]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_1.py
f97e6be58c41208289287dd30029259cc02d3bb6
[lyx.git] / lib / lyx2lyx / lyx_2_1.py
1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # -*- coding: utf-8 -*-
4 # Copyright (C) 2011 The LyX team
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
20 """ Convert files to the file format generated by LyX 2.1"""
21
22 import re, string
23 import unicodedata
24 import sys, os
25
26 # Uncomment only what you need to import, please.
27
28 from parser_tools import count_pars_in_inset, del_token, find_token, find_token_exact, \
29     find_token_backwards, find_end_of, find_end_of_inset, find_end_of_layout, \
30     find_end_of_sequence, find_re, get_option_value, get_containing_layout, \
31     get_value, get_quoted_value, set_option_value
32
33 #from parser_tools import find_token, find_end_of, find_tokens, \
34   #find_end_of_inset, find_end_of_layout, \
35   #is_in_inset, del_token, check_token
36
37 from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, get_ert
38
39 #from lyx2lyx_tools import insert_to_preamble, \
40 #  lyx2latex, latex_length, revert_flex_inset, \
41 #  revert_font_attrs, hex2ratio, str2bool
42
43 ####################################################################
44 # Private helper functions
45
46 #def remove_option(lines, m, option):
47     #''' removes option from line m. returns whether we did anything '''
48     #l = lines[m].find(option)
49     #if l == -1:
50         #return False
51     #val = lines[m][l:].split('"')[1]
52     #lines[m] = lines[m][:l - 1] + lines[m][l+len(option + '="' + val + '"'):]
53     #return True
54
55
56 ###############################################################################
57 ###
58 ### Conversion and reversion routines
59 ###
60 ###############################################################################
61
62 def revert_visible_space(document):
63     "Revert InsetSpace visible into its ERT counterpart"
64     i = 0
65     while True:
66       i = find_token(document.body, "\\begin_inset space \\textvisiblespace{}", i)
67       if i == -1:
68         return
69       end = find_end_of_inset(document.body, i)
70       subst = put_cmd_in_ert("\\textvisiblespace{}")
71       document.body[i:end + 1] = subst
72
73
74 def convert_undertilde(document):
75     " Load undertilde automatically "
76     i = find_token(document.header, "\\use_mathdots" , 0)
77     if i == -1:
78         i = find_token(document.header, "\\use_mhchem" , 0)
79     if i == -1:
80         i = find_token(document.header, "\\use_esint" , 0)
81     if i == -1:
82         document.warning("Malformed LyX document: Can't find \\use_mathdots.")
83         return;
84     j = find_token(document.preamble, "\\usepackage{undertilde}", 0)
85     if j == -1:
86         document.header.insert(i + 1, "\\use_undertilde 0")
87     else:
88         document.header.insert(i + 1, "\\use_undertilde 2")
89         del document.preamble[j]
90
91
92 def revert_undertilde(document):
93     " Load undertilde if used in the document "
94     undertilde = find_token(document.header, "\\use_undertilde" , 0)
95     if undertilde == -1:
96       document.warning("No \\use_undertilde line. Assuming auto.")
97     else:
98       val = get_value(document.header, "\\use_undertilde", undertilde)
99       del document.header[undertilde]
100       try:
101         usetilde = int(val)
102       except:
103         document.warning("Invalid \\use_undertilde value: " + val + ". Assuming auto.")
104         # probably usedots has not been changed, but be safe.
105         usetilde = 1
106
107       if usetilde == 0:
108         # do not load case
109         return
110       if usetilde == 2:
111         # force load case
112         add_to_preamble(document, ["\\usepackage{undertilde}"])
113         return
114
115     # so we are in the auto case. we want to load undertilde if \utilde is used.
116     i = 0
117     while True:
118       i = find_token(document.body, '\\begin_inset Formula', i)
119       if i == -1:
120         return
121       j = find_end_of_inset(document.body, i)
122       if j == -1:
123         document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
124         i += 1
125         continue
126       code = "\n".join(document.body[i:j])
127       if code.find("\\utilde") != -1:
128         add_to_preamble(document, ["\\@ifundefined{utilde}{\\usepackage{undertilde}}"])
129         return
130       i = j
131
132
133 def revert_negative_space(document):
134     "Revert InsetSpace negmedspace and negthickspace into its TeX-code counterpart"
135     i = 0
136     j = 0
137     reverted = False
138     while True:
139       i = find_token(document.body, "\\begin_inset space \\negmedspace{}", i)
140       if i == -1:
141         j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
142         if j == -1:
143           # load amsmath in the preamble if not already loaded if we are at the end of checking
144           if reverted == True:
145             i = find_token(document.header, "\\use_amsmath 2", 0)
146             if i == -1:
147               add_to_preamble(document, ["\\@ifundefined{negthickspace}{\\usepackage{amsmath}}"])
148           return
149       if i == -1:
150         return
151       end = find_end_of_inset(document.body, i)
152       subst = put_cmd_in_ert("\\negmedspace{}")
153       document.body[i:end + 1] = subst
154       j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
155       if j == -1:
156         return
157       end = find_end_of_inset(document.body, j)
158       subst = put_cmd_in_ert("\\negthickspace{}")
159       document.body[j:end + 1] = subst
160       reverted = True
161
162
163 def revert_math_spaces(document):
164     "Revert formulas with protected custom space and protected hfills to TeX-code"
165     i = 0
166     while True:
167       i = find_token(document.body, "\\begin_inset Formula", i)
168       if i == -1:
169         return
170       j = document.body[i].find("\\hspace*")
171       if j != -1:
172         end = find_end_of_inset(document.body, i)
173         subst = put_cmd_in_ert(document.body[i][21:])
174         document.body[i:end + 1] = subst
175       i = i + 1
176
177
178 def convert_japanese_encodings(document):
179     " Rename the japanese encodings to names understood by platex "
180     jap_enc_dict = {
181         "EUC-JP-pLaTeX": "euc",
182         "JIS-pLaTeX":    "jis",
183         "SJIS-pLaTeX":   "sjis"
184     }
185     i = find_token(document.header, "\\inputencoding" , 0)
186     if i == -1:
187         return
188     val = get_value(document.header, "\\inputencoding", i)
189     if val in jap_enc_dict.keys():
190         document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
191
192
193 def revert_japanese_encodings(document):
194     " Revert the japanese encodings name changes "
195     jap_enc_dict = {
196         "euc":  "EUC-JP-pLaTeX",
197         "jis":  "JIS-pLaTeX",
198         "sjis": "SJIS-pLaTeX"
199     }
200     i = find_token(document.header, "\\inputencoding" , 0)
201     if i == -1:
202         return
203     val = get_value(document.header, "\\inputencoding", i)
204     if val in jap_enc_dict.keys():
205         document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
206
207
208 def revert_justification(document):
209     " Revert the \\justification buffer param"
210     if not del_token(document.header, '\\justification', 0):
211         document.warning("Malformed LyX document: Missing \\justification.")
212
213
214 def revert_australian(document):
215     "Set English language variants Australian and Newzealand to English" 
216
217     if document.language == "australian" or document.language == "newzealand": 
218         document.language = "english"
219         i = find_token(document.header, "\\language", 0) 
220         if i != -1: 
221             document.header[i] = "\\language english" 
222     j = 0 
223     while True: 
224         j = find_token(document.body, "\\lang australian", j) 
225         if j == -1:
226             j = find_token(document.body, "\\lang newzealand", 0)
227             if j == -1:
228                 return
229             else:
230                 document.body[j] = document.body[j].replace("\\lang newzealand", "\\lang english")
231         else:
232             document.body[j] = document.body[j].replace("\\lang australian", "\\lang english") 
233         j += 1
234
235
236 def convert_biblio_style(document):
237     "Add a sensible default for \\biblio_style based on the citation engine."
238     i = find_token(document.header, "\\cite_engine", 0)
239     if i != -1:
240         engine = get_value(document.header, "\\cite_engine", i).split("_")[0]
241         style = {"basic": "plain", "natbib": "plainnat", "jurabib": "jurabib"}
242         document.header.insert(i + 1, "\\biblio_style " + style[engine])
243
244
245 def revert_biblio_style(document):
246     "BibTeX insets with default option use the style defined by \\biblio_style."
247     i = find_token(document.header, "\\biblio_style" , 0)
248     if i == -1:
249         document.warning("No \\biblio_style line. Nothing to do.")
250         return
251
252     default_style = get_value(document.header, "\\biblio_style", i)
253     del document.header[i]
254
255     # We are looking for bibtex insets having the default option
256     i = 0
257     while True:
258         i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
259         if i == -1:
260             return
261         j = find_end_of_inset(document.body, i)
262         if j == -1:
263             document.warning("Malformed LyX document: Can't find end of bibtex inset at line " + str(i))
264             i += 1
265             return
266         k = find_token(document.body, "options", i, j)
267         if k != -1:
268             options = get_quoted_value(document.body, "options", k)
269             if "default" in options.split(","):
270                 document.body[k] = 'options "%s"' \
271                     % options.replace("default", default_style)
272         i = j
273
274
275 def handle_longtable_captions(document, forward):
276     begin_table = 0
277     while True:
278         begin_table = find_token(document.body, '<lyxtabular version=', begin_table)
279         if begin_table == -1:
280             break
281         end_table = find_end_of(document.body, begin_table, '<lyxtabular', '</lyxtabular>')
282         if end_table == -1:
283             document.warning("Malformed LyX document: Could not find end of table.")
284             begin_table += 1
285             continue
286         fline = find_token(document.body, "<features", begin_table, end_table)
287         if fline == -1:
288             document.warning("Can't find features for inset at line " + str(begin_table))
289             begin_table += 1
290             continue
291         p = document.body[fline].find("islongtable")
292         if p == -1:
293             # no longtable
294             begin_table += 1
295             continue
296         numrows = get_option_value(document.body[begin_table], "rows")
297         try:
298             numrows = int(numrows)
299         except:
300             document.warning(document.body[begin_table])
301             document.warning("Unable to determine rows!")
302             begin_table = end_table
303             continue
304         begin_row = begin_table
305         for row in range(numrows):
306             begin_row = find_token(document.body, '<row', begin_row, end_table)
307             if begin_row == -1:
308                 document.warning("Can't find row " + str(row + 1))
309                 break
310             end_row = find_end_of(document.body, begin_row, '<row', '</row>')
311             if end_row == -1:
312                 document.warning("Can't find end of row " + str(row + 1))
313                 break
314             if forward:
315                 if (get_option_value(document.body[begin_row], 'caption') == 'true' and
316                     get_option_value(document.body[begin_row], 'endfirsthead') != 'true' and
317                     get_option_value(document.body[begin_row], 'endhead') != 'true' and
318                     get_option_value(document.body[begin_row], 'endfoot') != 'true' and
319                     get_option_value(document.body[begin_row], 'endlastfoot') != 'true'):
320                     document.body[begin_row] = set_option_value(document.body[begin_row], 'caption', 'true", endfirsthead="true')
321             elif get_option_value(document.body[begin_row], 'caption') == 'true':
322                 if get_option_value(document.body[begin_row], 'endfirsthead') == 'true':
323                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endfirsthead', 'false')
324                 if get_option_value(document.body[begin_row], 'endhead') == 'true':
325                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endhead', 'false')
326                 if get_option_value(document.body[begin_row], 'endfoot') == 'true':
327                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endfoot', 'false')
328                 if get_option_value(document.body[begin_row], 'endlastfoot') == 'true':
329                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endlastfoot', 'false')
330             begin_row = end_row
331         # since there could be a tabular inside this one, we 
332         # cannot jump to end.
333         begin_table += 1
334
335
336 def convert_longtable_captions(document):
337     "Add a firsthead flag to caption rows"
338     handle_longtable_captions(document, True)
339
340
341 def revert_longtable_captions(document):
342     "remove head/foot flag from caption rows"
343     handle_longtable_captions(document, False)
344
345
346 def convert_use_packages(document):
347     "use_xxx yyy => use_package xxx yyy"
348     packages = ["amsmath", "esint", "mathdots", "mhchem", "undertilde"]
349     for p in packages:
350         i = find_token(document.header, "\\use_%s" % p, 0)
351         if i != -1:
352             value = get_value(document.header, "\\use_%s" % p, i)
353             document.header[i] = "\\use_package %s %s" % (p, value)
354
355
356 def revert_use_packages(document):
357     "use_package xxx yyy => use_xxx yyy"
358     packages = ["amsmath", "esint", "mathdots", "mhchem", "undertilde"]
359     # the order is arbitrary for the use_package version, and not all packages need to be given.
360     # Ensure a complete list and correct order (important for older LyX versions and especially lyx2lyx)
361     j = 0
362     for p in packages:
363         regexp = re.compile(r'(\\use_package\s+%s)' % p)
364         i = find_re(document.header, regexp, j)
365         if i != -1:
366             value = get_value(document.header, "\\use_package %s" % p, i).split()[1]
367             del document.header[i]
368             j = i
369             document.header.insert(j, "\\use_%s %s"  % (p, value))
370         j = j + 1
371
372
373 def convert_use_package(document, pkg):
374     i = find_token(document.header, "\\use_package", 0)
375     if i == -1:
376         document.warning("Malformed LyX document: Can't find \\use_package.")
377         return;
378     j = find_token(document.preamble, "\\usepackage{" + pkg + "}", 0)
379     if j == -1:
380         document.header.insert(i + 1, "\\use_package " + pkg + " 0")
381     else:
382         document.header.insert(i + 1, "\\use_package " + pkg + " 2")
383         del document.preamble[j]
384
385
386 def revert_use_package(document, pkg, commands, oldauto):
387     # oldauto defines how the version we are reverting to behaves:
388     # if it is true, the old version uses the package automatically.
389     # if it is false, the old version never uses the package.
390     regexp = re.compile(r'(\\use_package\s+%s)' % pkg)
391     i = find_re(document.header, regexp, 0)
392     value = "1" # default is auto
393     if i != -1:
394         value = get_value(document.header, "\\use_package" , i).split()[1]
395         del document.header[i]
396     if value == "2": # on
397         add_to_preamble(document, ["\\usepackage{" + pkg + "}"])
398     elif value == "1" and not oldauto: # auto
399         i = 0
400         while True:
401             i = find_token(document.body, '\\begin_inset Formula', i)
402             if i == -1:
403                 return
404             j = find_end_of_inset(document.body, i)
405             if j == -1:
406                 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
407                 i += 1
408                 continue
409             code = "\n".join(document.body[i:j])
410             for c in commands:
411                 if code.find("\\%s" % c) != -1:
412                     add_to_preamble(document, ["\\usepackage{" + pkg + "}"])
413                     return
414             i = j
415
416
417 def convert_use_mathtools(document):
418     "insert use_package mathtools"
419     convert_use_package(document, "mathtools")
420
421
422 def revert_use_mathtools(document):
423     "remove use_package mathtools"
424     commands = ["mathclap", "mathllap", "mathrlap", \
425                 "lgathered", "rgathered", "vcentcolon", "dblcolon", \
426                 "coloneqq", "Coloneqq", "coloneq", "Coloneq", "eqqcolon", \
427                 "Eqqcolon", "eqcolon", "Eqcolon", "colonapprox", \
428                 "Colonapprox", "colonsim", "Colonsim"]
429     revert_use_package(document, "mathtools", commands, False)
430
431
432 def convert_use_stmaryrd(document):
433     "insert use_package stmaryrd"
434     convert_use_package(document, "stmaryrd")
435
436
437 def revert_use_stmaryrd(document):
438     "remove use_package stmaryrd"
439     # commands provided by stmaryrd.sty but LyX uses other packages:
440     # boxdot lightning, bigtriangledown, bigtriangleup
441     commands = ["shortleftarrow", "shortrightarrow", "shortuparrow", \
442                     "shortdownarrow", "Yup", "Ydown", "Yleft", "Yright", \
443                     "varcurlyvee", "varcurlywedge", "minuso", "baro", \
444                     "sslash", "bbslash", "moo", "varotimes", "varoast", \
445                     "varobar", "varodot", "varoslash", "varobslash", \
446                     "varocircle", "varoplus", "varominus", "boxast", \
447                     "boxbar", "boxslash", "boxbslash", "boxcircle", \
448                     "boxbox", "boxempty", "merge", "vartimes", \
449                     "fatsemi", "sswarrow", "ssearrow", "curlywedgeuparrow", \
450                     "curlywedgedownarrow", "fatslash", "fatbslash", "lbag", \
451                     "rbag", "varbigcirc", "leftrightarroweq", \
452                     "curlyveedownarrow", "curlyveeuparrow", "nnwarrow", \
453                     "nnearrow", "leftslice", "rightslice", "varolessthan", \
454                     "varogreaterthan", "varovee", "varowedge", "talloblong", \
455                     "interleave", "obar", "obslash", "olessthan", \
456                     "ogreaterthan", "ovee", "owedge", "oblong", "inplus", \
457                     "niplus", "nplus", "subsetplus", "supsetplus", \
458                     "subsetpluseq", "supsetpluseq", "Lbag", "Rbag", \
459                     "llbracket", "rrbracket", "llparenthesis", \
460                     "rrparenthesis", "binampersand", "bindnasrepma", \
461                     "trianglelefteqslant", "trianglerighteqslant", \
462                     "ntrianglelefteqslant", "ntrianglerighteqslant", \
463                     "llfloor", "rrfloor", "llceil", "rrceil", "arrownot", \
464                     "Arrownot", "Mapstochar", "mapsfromchar", "Mapsfromchar", \
465                     "leftrightarrowtriangle", "leftarrowtriangle", \
466                     "rightarrowtriangle", \
467                     "bigcurlyvee", "bigcurlywedge", "bigsqcap", "bigbox", \
468                     "bigparallel", "biginterleave", "bignplus", \
469                     "varcopyright", "longarrownot", "Longarrownot", \
470                     "Mapsto", "mapsfrom", "Mapsfrom" "Longmapsto", \
471                     "longmapsfrom", "Longmapsfrom"]
472     revert_use_package(document, "stmaryrd", commands, False)
473
474
475
476 def convert_use_stackrel(document):
477     "insert use_package stackrel"
478     convert_use_package(document, "stackrel")
479
480
481 def revert_use_stackrel(document):
482     "remove use_package stackrel"
483     commands = ["stackrel"]
484     revert_use_package(document, "stackrel", commands, False)
485
486
487 def convert_cite_engine_type(document):
488     "Determine the \\cite_engine_type from the citation engine."
489     i = find_token(document.header, "\\cite_engine", 0)
490     if i == -1:
491         return
492     engine = get_value(document.header, "\\cite_engine", i)
493     if "_" in engine:
494         engine, type = engine.split("_")
495     else:
496         type = {"basic": "numerical", "jurabib": "authoryear"}[engine]
497     document.header[i] = "\\cite_engine " + engine
498     document.header.insert(i + 1, "\\cite_engine_type " + type)
499
500
501 def revert_cite_engine_type(document):
502     "Natbib had the type appended with an underscore."
503     engine_type = "numerical"
504     i = find_token(document.header, "\\cite_engine_type" , 0)
505     if i == -1:
506         document.warning("No \\cite_engine_type line. Assuming numerical.")
507     else:
508         engine_type = get_value(document.header, "\\cite_engine_type", i)
509         del document.header[i]
510
511     # We are looking for the natbib citation engine
512     i = find_token(document.header, "\\cite_engine natbib", 0)
513     if i == -1:
514         return
515     document.header[i] = "\\cite_engine natbib_" + engine_type
516
517
518 def convert_cite_engine_type_default(document):
519     "Convert \\cite_engine_type to default for the basic citation engine."
520     i = find_token(document.header, "\\cite_engine basic", 0)
521     if i == -1:
522         return
523     i = find_token(document.header, "\\cite_engine_type" , 0)
524     if i == -1:
525         return
526     document.header[i] = "\\cite_engine_type default"
527
528
529 def revert_cite_engine_type_default(document):
530     """Revert \\cite_engine_type default.
531
532     Revert to numerical for the basic cite engine, otherwise to authoryear."""
533     engine_type = "authoryear"
534     i = find_token(document.header, "\\cite_engine_type default" , 0)
535     if i == -1:
536         return
537     j = find_token(document.header, "\\cite_engine basic", 0)
538     if j != -1:
539         engine_type = "numerical"
540     document.header[i] = "\\cite_engine_type " + engine_type
541
542
543 # this is the same, as revert_use_cancel() except for the default
544 def revert_cancel(document):
545     "add cancel to the preamble if necessary"
546     commands = ["cancelto", "cancel", "bcancel", "xcancel"]
547     revert_use_package(document, "cancel", commands, False)
548
549
550 def revert_verbatim(document):
551     " Revert verbatim einvironments completely to TeX-code. "
552     i = 0
553     consecutive = False
554     subst_end = ['\end_layout', '', '\\begin_layout Plain Layout',
555                  '\end_layout', '',
556                  '\\begin_layout Plain Layout', '', '',
557                  '\\backslash', '',
558                  'end{verbatim}',
559                  '\\end_layout', '', '\\end_inset',
560                  '', '', '\\end_layout']
561     subst_begin = ['\\begin_layout Standard', '\\noindent',
562                    '\\begin_inset ERT', 'status collapsed', '',
563                    '\\begin_layout Plain Layout', '', '', '\\backslash',
564                    'begin{verbatim}',
565                    '\\end_layout', '', '\\begin_layout Plain Layout', '']
566     while 1:
567         i = find_token(document.body, "\\begin_layout Verbatim", i)
568         if i == -1:
569             return
570         j = find_end_of_layout(document.body, i)
571         if j == -1:
572             document.warning("Malformed LyX document: Can't find end of Verbatim layout")
573             i += 1
574             continue
575         # delete all line breaks insets (there are no other insets)
576         l = i
577         while 1:
578             n = find_token(document.body, "\\begin_inset Newline newline", l)
579             if n == -1:
580                 n = find_token(document.body, "\\begin_inset Newline linebreak", l)
581                 if n == -1:
582                     break
583             m = find_end_of_inset(document.body, n)
584             del(document.body[m:m+1])
585             document.body[n:n+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
586             l += 1
587             j += 1
588         # consecutive verbatim environments need to be connected
589         k = find_token(document.body, "\\begin_layout Verbatim", j)
590         if k == j + 2 and consecutive == False:
591             consecutive = True
592             document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
593             document.body[i:i+1] = subst_begin
594             continue
595         if k == j + 2 and consecutive == True:
596             document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
597             del(document.body[i:i+1])
598             continue
599         if k != j + 2 and consecutive == True:
600             document.body[j:j+1] = subst_end
601             # the next paragraph must not be indented
602             document.body[j+19:j+19] = ['\\noindent']
603             del(document.body[i:i+1])
604             consecutive = False
605             continue
606         else:
607             document.body[j:j+1] = subst_end
608             # the next paragraph must not be indented
609             document.body[j+19:j+19] = ['\\noindent']
610             document.body[i:i+1] = subst_begin
611
612
613 def revert_tipa(document):
614     " Revert native TIPA insets to mathed or ERT. "
615     i = 0
616     while 1:
617         i = find_token(document.body, "\\begin_inset IPA", i)
618         if i == -1:
619             return
620         j = find_end_of_inset(document.body, i)
621         if j == -1:
622             document.warning("Malformed LyX document: Can't find end of IPA inset")
623             i += 1
624             continue
625         Multipar = False
626         n = find_token(document.body, "\\begin_layout", i, j)
627         if n == -1:
628             document.warning("Malformed LyX document: IPA inset has no embedded layout")
629             i += 1
630             continue
631         m = find_end_of_layout(document.body, n)
632         if m == -1:
633             document.warning("Malformed LyX document: Can't find end of embedded layout")
634             i += 1
635             continue
636         content = document.body[n+1:m]
637         p = find_token(document.body, "\\begin_layout", m, j)
638         if p != -1 or len(content) > 1:
639             Multipar = True
640             content = document.body[i+1:j]
641         if Multipar:
642             # IPA insets with multiple pars need to be wrapped by \begin{IPA}...\end{IPA}
643             document.body[i:j+1] = ['\\end_layout', '', '\\begin_layout Standard'] + put_cmd_in_ert("\\begin{IPA}") + ['\\end_layout'] + content + ['\\begin_layout Standard'] + put_cmd_in_ert("\\end{IPA}")
644             add_to_preamble(document, ["\\usepackage{tipa,tipx}"])
645         else:
646             # single-par IPA insets can be reverted to mathed
647             document.body[i:j+1] = ["\\begin_inset Formula $\\text{\\textipa{" + content[0] + "}}$", "\\end_inset"]
648         i = j
649
650
651 def revert_cell_rotation(document):
652   "Revert cell rotations to TeX-code"
653
654   load_rotating = False
655   i = 0
656   try:
657     while True:
658       # first, let's find out if we need to do anything
659       i = find_token(document.body, '<cell ', i)
660       if i == -1:
661         return
662       j = document.body[i].find('rotate="')
663       if j != -1:
664         k = document.body[i].find('"', j + 8)
665         value = document.body[i][j + 8 : k]
666         if value == "0":
667           rgx = re.compile(r' rotate="[^"]+?"')
668           # remove rotate option
669           document.body[i] = rgx.sub('', document.body[i])
670         elif value == "90":
671           rgx = re.compile(r' rotate="[^"]+?"')
672           document.body[i] = rgx.sub('rotate="true"', document.body[i])
673         else:
674           rgx = re.compile(r' rotate="[^"]+?"')
675           load_rotating = True
676           # remove rotate option
677           document.body[i] = rgx.sub('', document.body[i])
678           # write ERT
679           document.body[i + 5 : i + 5] = \
680             put_cmd_in_ert("\\end{turn}")
681           document.body[i + 4 : i + 4] = \
682             put_cmd_in_ert("\\begin{turn}{" + value + "}")
683         
684       i += 1
685         
686   finally:
687     if load_rotating:
688       add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
689
690
691 def convert_cell_rotation(document):
692     'Convert cell rotation statements from "true" to "90"'
693
694     i = 0
695     while True:
696       # first, let's find out if we need to do anything
697       i = find_token(document.body, '<cell ', i)
698       if i == -1:
699         return
700       j = document.body[i].find('rotate="true"')
701       if j != -1:
702         rgx = re.compile(r'rotate="[^"]+?"')
703         # convert "true" to "90"
704         document.body[i] = rgx.sub('rotate="90"', document.body[i])
705         
706       i += 1
707
708
709 def revert_table_rotation(document):
710   "Revert table rotations to TeX-code"
711
712   load_rotating = False
713   i = 0
714   try:
715     while True:
716       # first, let's find out if we need to do anything
717       i = find_token(document.body, '<features ', i)
718       if i == -1:
719         return
720       j = document.body[i].find('rotate="')
721       if j != -1:
722         end_table = find_token(document.body, '</lyxtabular>', j)
723         k = document.body[i].find('"', j + 8)
724         value = document.body[i][j + 8 : k]
725         if value == "0":
726           rgx = re.compile(r' rotate="[^"]+?"')
727           # remove rotate option
728           document.body[i] = rgx.sub('', document.body[i])
729         elif value == "90":
730           rgx = re.compile(r'rotate="[^"]+?"')
731           document.body[i] = rgx.sub('rotate="true"', document.body[i])
732         else:
733           rgx = re.compile(r' rotate="[^"]+?"')
734           load_rotating = True
735           # remove rotate option
736           document.body[i] = rgx.sub('', document.body[i])
737           # write ERT
738           document.body[end_table + 3 : end_table + 3] = \
739             put_cmd_in_ert("\\end{turn}")
740           document.body[i - 2 : i - 2] = \
741             put_cmd_in_ert("\\begin{turn}{" + value + "}")
742         
743       i += 1
744         
745   finally:
746     if load_rotating:
747       add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
748
749
750 def convert_table_rotation(document):
751     'Convert table rotation statements from "true" to "90"'
752
753     i = 0
754     while True:
755       # first, let's find out if we need to do anything
756       i = find_token(document.body, '<features ', i)
757       if i == -1:
758         return
759       j = document.body[i].find('rotate="true"')
760       if j != -1:
761         rgx = re.compile(r'rotate="[^"]+?"')
762         # convert "true" to "90"
763         document.body[i] = rgx.sub('rotate="90"', document.body[i])
764         
765       i += 1
766
767
768 def convert_listoflistings(document):
769     'Convert ERT \lstlistoflistings to TOC lstlistoflistings inset'
770     # We can support roundtrip because the command is so simple
771     i = 0
772     while True:
773         i = find_token(document.body, "\\begin_inset ERT", i)
774         if i == -1:
775             return
776         j = find_end_of_inset(document.body, i)
777         if j == -1:
778             document.warning("Malformed LyX document: Can't find end of ERT inset")
779             i += 1
780             continue
781         ert = get_ert(document.body, i)
782         if ert == "\\lstlistoflistings{}":
783             document.body[i:j] = ["\\begin_inset CommandInset toc", "LatexCommand lstlistoflistings", ""]
784             i = i + 4
785         else:
786             i = j + 1
787
788
789 def revert_listoflistings(document):
790     'Convert TOC lstlistoflistings inset to ERT lstlistoflistings'
791     i = 0
792     while True:
793         i = find_token(document.body, "\\begin_inset CommandInset toc", i)
794         if i == -1:
795             return
796         if document.body[i+1] == "LatexCommand lstlistoflistings":
797             j = find_end_of_inset(document.body, i)
798             if j == -1:
799                 document.warning("Malformed LyX document: Can't find end of TOC inset")
800                 i += 1
801                 continue
802             subst = put_cmd_in_ert("\\lstlistoflistings{}")
803             document.body[i:j+1] = subst
804             add_to_preamble(document, ["\\usepackage{listings}"])
805         i = i + 1
806
807
808 def convert_use_amssymb(document):
809     "insert use_package amssymb"
810     regexp = re.compile(r'(\\use_package\s+amsmath)')
811     i = find_re(document.header, regexp, 0)
812     if i == -1:
813         document.warning("Malformed LyX document: Can't find \\use_package amsmath.")
814         return;
815     value = get_value(document.header, "\\use_package" , i).split()[1]
816     useamsmath = 0
817     try:
818         useamsmath = int(value)
819     except:
820         document.warning("Invalid \\use_package amsmath: " + value + ". Assuming auto.")
821         useamsmath = 1
822     j = find_token(document.preamble, "\\usepackage{amssymb}", 0)
823     if j == -1:
824         document.header.insert(i + 1, "\\use_package amssymb %d" % useamsmath)
825     else:
826         document.header.insert(i + 1, "\\use_package amssymb 2")
827         del document.preamble[j]
828
829
830 def revert_use_amssymb(document):
831     "remove use_package amssymb"
832     regexp1 = re.compile(r'(\\use_package\s+amsmath)')
833     regexp2 = re.compile(r'(\\use_package\s+amssymb)')
834     i = find_re(document.header, regexp1, 0)
835     j = find_re(document.header, regexp2, 0)
836     value1 = "1" # default is auto
837     value2 = "1" # default is auto
838     if i != -1:
839         value1 = get_value(document.header, "\\use_package" , i).split()[1]
840     if j != -1:
841         value2 = get_value(document.header, "\\use_package" , j).split()[1]
842         del document.header[j]
843     if value1 != value2 and value2 == "2": # on
844         add_to_preamble(document, ["\\usepackage{amssymb}"])
845
846
847 def convert_use_cancel(document):
848     "insert use_package cancel"
849     convert_use_package(document, "cancel")
850
851
852 def revert_use_cancel(document):
853     "remove use_package cancel"
854     commands = ["cancel", "bcancel", "xcancel", "cancelto"]
855     revert_use_package(document, "cancel", commands, True)
856
857
858 def revert_ancientgreek(document):
859     "Set the document language for ancientgreek to greek" 
860
861     if document.language == "ancientgreek": 
862         document.language = "greek"
863         i = find_token(document.header, "\\language", 0) 
864         if i != -1: 
865             document.header[i] = "\\language greek" 
866     j = 0 
867     while True: 
868         j = find_token(document.body, "\\lang ancientgreek", j) 
869         if j == -1:
870             return
871         else:
872             document.body[j] = document.body[j].replace("\\lang ancientgreek", "\\lang greek") 
873         j += 1
874
875
876 def revert_languages(document):
877     "Set the document language for new supported languages to English" 
878
879     languages = [
880                  "coptic", "divehi", "hindi", "kurmanji", "lao", "marathi", "occitan", "sanskrit",
881                  "syriac", "tamil", "telugu", "urdu"
882                 ]
883     for n in range(len(languages)):
884         if document.language == languages[n]:
885             document.language = "english"
886             i = find_token(document.header, "\\language", 0) 
887             if i != -1: 
888                 document.header[i] = "\\language english" 
889         j = 0
890         while j < len(document.body): 
891             j = find_token(document.body, "\\lang " + languages[n], j)
892             if j != -1:
893                 document.body[j] = document.body[j].replace("\\lang " + languages[n], "\\lang english")
894                 j += 1
895             else:
896                 j = len(document.body)
897
898
899 def convert_armenian(document):
900     "Use polyglossia and thus non-TeX fonts for Armenian" 
901
902     if document.language == "armenian": 
903         i = find_token(document.header, "\\use_non_tex_fonts", 0) 
904         if i != -1: 
905             document.header[i] = "\\use_non_tex_fonts true" 
906
907
908 def revert_armenian(document):
909     "Use ArmTeX and thus TeX fonts for Armenian" 
910
911     if document.language == "armenian": 
912         i = find_token(document.header, "\\use_non_tex_fonts", 0) 
913         if i != -1: 
914             document.header[i] = "\\use_non_tex_fonts false" 
915
916
917 def revert_libertine(document):
918     " Revert native libertine font definition to LaTeX " 
919
920     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
921         i = find_token(document.header, "\\font_roman libertine", 0)
922         if i != -1:
923             osf = False
924             j = find_token(document.header, "\\font_osf true", 0)
925             if j != -1:
926                 osf = True
927             preamble = "\\usepackage"
928             if osf:
929                 document.header[j] = "\\font_osf false"
930                 preamble += "[osf]"
931             else:
932                 preamble += "[lining]"
933             preamble += "{libertine-type1}"
934             add_to_preamble(document, [preamble])
935             document.header[i] = "\\font_roman default"
936
937
938 def revert_txtt(document):
939     " Revert native txtt font definition to LaTeX " 
940
941     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
942         i = find_token(document.header, "\\font_typewriter txtt", 0)
943         if i != -1:
944             preamble = "\\renewcommand{\\ttdefault}{txtt}"
945             add_to_preamble(document, [preamble])
946             document.header[i] = "\\font_typewriter default"
947
948
949 def revert_mathdesign(document):
950     " Revert native mathdesign font definition to LaTeX " 
951
952     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
953         mathdesign_dict = {
954         "mdbch":  "charter",
955         "mdput":  "utopia",
956         "mdugm":  "garamond"
957         }
958         i = find_token(document.header, "\\font_roman", 0)
959         if i == -1:
960             return
961         val = get_value(document.header, "\\font_roman", i)
962         if val in mathdesign_dict.keys():
963             preamble = "\\usepackage[%s" % mathdesign_dict[val]
964             expert = False
965             j = find_token(document.header, "\\font_osf true", 0)
966             if j != -1:
967                 expert = True
968                 document.header[j] = "\\font_osf false"
969             l = find_token(document.header, "\\font_sc true", 0)
970             if l != -1:
971                 expert = True
972                 document.header[l] = "\\font_sc false"
973             if expert:
974                 preamble += ",expert"
975             preamble += "]{mathdesign}"
976             add_to_preamble(document, [preamble])
977             document.header[i] = "\\font_roman default"
978
979
980 def revert_texgyre(document):
981     " Revert native TeXGyre font definition to LaTeX " 
982
983     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
984         texgyre_fonts = ["tgadventor", "tgbonum", "tgchorus", "tgcursor", \
985                          "tgheros", "tgpagella", "tgschola", "tgtermes"]
986         i = find_token(document.header, "\\font_roman", 0)
987         if i != -1:
988             val = get_value(document.header, "\\font_roman", i)
989             if val in texgyre_fonts:
990                 preamble = "\\usepackage{%s}" % val
991                 add_to_preamble(document, [preamble])
992                 document.header[i] = "\\font_roman default"
993         i = find_token(document.header, "\\font_sans", 0)
994         if i != -1:
995             val = get_value(document.header, "\\font_sans", i)
996             if val in texgyre_fonts:
997                 preamble = "\\usepackage{%s}" % val
998                 add_to_preamble(document, [preamble])
999                 document.header[i] = "\\font_sans default"
1000         i = find_token(document.header, "\\font_typewriter", 0)
1001         if i != -1:
1002             val = get_value(document.header, "\\font_typewriter", i)
1003             if val in texgyre_fonts:
1004                 preamble = "\\usepackage{%s}" % val
1005                 add_to_preamble(document, [preamble])
1006                 document.header[i] = "\\font_typewriter default"
1007
1008
1009 def revert_ipadeco(document):
1010     " Revert IPA decorations to ERT "
1011     i = 0
1012     while True:
1013       i = find_token(document.body, "\\begin_inset IPADeco", i)
1014       if i == -1:
1015           return
1016       end = find_end_of_inset(document.body, i)
1017       if end == -1:
1018           document.warning("Can't find end of inset at line " + str(i))
1019           i += 1
1020           continue
1021       line = document.body[i]
1022       rx = re.compile(r'\\begin_inset IPADeco (.*)$')
1023       m = rx.match(line)
1024       decotype = m.group(1)
1025       if decotype != "toptiebar" and decotype != "bottomtiebar":
1026           document.warning("Invalid IPADeco type: " + decotype)
1027           i = end
1028           continue
1029       blay = find_token(document.body, "\\begin_layout Plain Layout", i, end)
1030       if blay == -1:
1031           document.warning("Can't find layout for inset at line " + str(i))
1032           i = end
1033           continue
1034       bend = find_end_of_layout(document.body, blay)
1035       if bend == -1:
1036           document.warning("Malformed LyX document: Could not find end of IPADeco inset's layout.")
1037           i = end
1038           continue
1039       substi = ["\\begin_inset ERT", "status collapsed", "",
1040                 "\\begin_layout Plain Layout", "", "", "\\backslash", 
1041                 decotype + "{", "\\end_layout", "", "\\end_inset"]
1042       substj = ["\\size default", "", "\\begin_inset ERT", "status collapsed", "",
1043                 "\\begin_layout Plain Layout", "", "}", "\\end_layout", "", "\\end_inset"]
1044       # do the later one first so as not to mess up the numbering
1045       document.body[bend:end + 1] = substj
1046       document.body[i:blay + 1] = substi
1047       i = end + len(substi) + len(substj) - (end - bend) - (blay - i) - 2
1048       add_to_preamble(document, "\\usepackage{tipa}")
1049
1050
1051 def revert_ipachar(document):
1052     ' Revert \\IPAChar to ERT '
1053     i = 0
1054     found = False
1055     while i < len(document.body):
1056         m = re.match(r'(.*)\\IPAChar \\(\w+\{\w+\})(.*)', document.body[i])
1057         if m:
1058             found = True
1059             before = m.group(1)
1060             ipachar = m.group(2)
1061             after = m.group(3)
1062             subst = [before,
1063                      '\\begin_inset ERT',
1064                      'status collapsed', '',
1065                      '\\begin_layout Standard',
1066                      '', '', '\\backslash',
1067                      ipachar,
1068                      '\\end_layout', '',
1069                      '\\end_inset', '',
1070                      after]
1071             document.body[i: i+1] = subst
1072             i = i + len(subst)
1073         else:
1074             i = i + 1
1075     if found:
1076         add_to_preamble(document, "\\usepackage{tone}")
1077
1078
1079 def revert_minionpro(document):
1080     " Revert native MinionPro font definition to LaTeX " 
1081
1082     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1083         i = find_token(document.header, "\\font_roman minionpro", 0)
1084         if i != -1:
1085             osf = False
1086             j = find_token(document.header, "\\font_osf true", 0)
1087             if j != -1:
1088                 osf = True
1089             preamble = "\\usepackage"
1090             if osf:
1091                 document.header[j] = "\\font_osf false"
1092             else:
1093                 preamble += "[lf]"
1094             preamble += "{MinionPro}"
1095             add_to_preamble(document, [preamble])
1096             document.header[i] = "\\font_roman default"
1097
1098
1099 def revert_mathfonts(document):
1100     " Revert native math font definitions to LaTeX " 
1101
1102     i = find_token(document.header, "\\font_math", 0)
1103     if i == -1:
1104        return
1105     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1106         val = get_value(document.header, "\\font_math", i)
1107         if val == "eulervm":
1108             add_to_preamble(document, "\\usepackage{eulervm}")
1109         elif val == "default":
1110             mathfont_dict = {
1111             "lmodern":  "\\renewcommand{\\rmdefault}{lmr}",
1112             "minionpro":  "\\usepackage[onlytext,lf]{MinionPro}",
1113             "minionpro-osf":  "\\usepackage[onlytext]{MinionPro}",
1114             "palatino":  "\\renewcommand{\\rmdefault}{ppl}",
1115             "palatino-osf":  "\\renewcommand{\\rmdefault}{pplj}",
1116             "times":  "\\renewcommand{\\rmdefault}{ptm}",
1117             "utopia":  "\\renewcommand{\\rmdefault}{futs}",
1118             "utopia-osf":  "\\renewcommand{\\rmdefault}{futj}",
1119             }
1120             j = find_token(document.header, "\\font_roman", 0)
1121             if j != -1:
1122                 rm = get_value(document.header, "\\font_roman", j)
1123                 k = find_token(document.header, "\\font_osf true", 0)
1124                 if k != -1:
1125                     rm += "-osf"
1126                 if rm in mathfont_dict.keys():
1127                     add_to_preamble(document, mathfont_dict[rm])
1128                     document.header[j] = "\\font_roman default"
1129                     if k != -1:
1130                         document.header[k] = "\\font_osf false"
1131     del document.header[i]
1132
1133
1134 def revert_mdnomath(document):
1135     " Revert mathdesign and fourier without math " 
1136
1137     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1138         mathdesign_dict = {
1139         "md-charter": "mdbch",
1140         "md-utopia": "mdput",
1141         "md-garamond": "mdugm"
1142         }
1143         i = find_token(document.header, "\\font_roman", 0)
1144         if i == -1:
1145             return
1146         val = get_value(document.header, "\\font_roman", i)
1147         if val in mathdesign_dict.keys():
1148             j = find_token(document.header, "\\font_math", 0)
1149             if j == -1:
1150                 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1151             mval = get_value(document.header, "\\font_math", j)
1152             if mval == "default":
1153                 document.header[i] = "\\font_roman default"
1154                 add_to_preamble(document, "\\renewcommand{\\rmdefault}{%s}" % mathdesign_dict[val])
1155             else:
1156                 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1157
1158
1159 def convert_mdnomath(document):
1160     " Change mathdesign font name " 
1161
1162     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1163         mathdesign_dict = {
1164         "mdbch":  "md-charter",
1165         "mdput":  "md-utopia",
1166         "mdugm":  "md-garamond"
1167         }
1168         i = find_token(document.header, "\\font_roman", 0)
1169         if i == -1:
1170             return
1171         val = get_value(document.header, "\\font_roman", i)
1172         if val in mathdesign_dict.keys():
1173              document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1174
1175
1176 def revert_newtxmath(document):
1177     " Revert native newtxmath definitions to LaTeX " 
1178
1179     i = find_token(document.header, "\\font_math", 0)
1180     if i == -1:
1181        return
1182     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1183         val = get_value(document.header, "\\font_math", i)
1184         mathfont_dict = {
1185         "libertine-ntxm":  "\\usepackage[libertine]{newtxmath}",
1186         "minion-ntxm":  "\\usepackage[minion]{newtxmath}",
1187         "newtxmath":  "\\usepackage{newtxmath}",
1188         }
1189         if val in mathfont_dict.keys():
1190             add_to_preamble(document, mathfont_dict[val])
1191             document.header[i] = "\\font_math auto"
1192
1193
1194 def revert_biolinum(document):
1195     " Revert native biolinum font definition to LaTeX " 
1196
1197     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1198         i = find_token(document.header, "\\font_sans biolinum", 0)
1199         if i != -1:
1200             osf = False
1201             j = find_token(document.header, "\\font_osf true", 0)
1202             if j != -1:
1203                 osf = True
1204             preamble = "\\usepackage"
1205             if not osf:
1206                 preamble += "[lf]"
1207             preamble += "{biolinum-type1}"
1208             add_to_preamble(document, [preamble])
1209             document.header[i] = "\\font_sans default"
1210
1211
1212 def revert_uop(document):
1213     " Revert native URW Classico (Optima) font definition to LaTeX "
1214
1215     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1216         i = find_token(document.header, "\\font_sans uop", 0)
1217         if i != -1:
1218                 preamble = "\\renewcommand{\\sfdefault}{uop}"
1219                 add_to_preamble(document, [preamble])
1220                 document.header[i] = "\\font_sans default"
1221
1222
1223 def convert_latexargs(document):
1224     " Convert InsetArgument to new syntax "
1225
1226     if find_token(document.body, "\\begin_inset Argument", 0) == -1:
1227         # nothing to do.
1228         return
1229
1230     # A list of layouts (document classes) with only optional or no arguments.
1231     # These can be safely converted to the new syntax
1232     # (I took the liberty to add some of my personal layouts/modules here; JSP)
1233     safe_layouts = ["aa", "aapaper", "aastex", "achemso", "acmsiggraph", "AEA",
1234                     "agu-dtd", "agums", "agutex", "amsart", "amsbook", "apa",
1235                     "arab-article", "armenian-article", "article-beamer", "article",
1236                     "beamer", "book", "broadway", "chess", "cl2emult", "ctex-article",
1237                     "ctex-book", "ctex-report", "dinbrief", "docbook-book", "docbook-chapter",
1238                     "docbook", "docbook-section", "doublecol-new", "dtk", "ectaart", "egs",
1239                     "elsarticle", "elsart", "entcs", "europecv", "extarticle", "extbook",
1240                     "extletter", "extreport", "foils", "frletter", "g-brief2", "g-brief",
1241                     "heb-article", "heb-letter", "hollywood", "IEEEtran", "ijmpc", "ijmpd",
1242                     "iopart", "isprs", "jarticle", "jasatex", "jbook", "jgrga", "jreport",
1243                     "jsarticle", "jsbeamer", "jsbook", "jss", "kluwer", "latex8", "letter", "lettre",
1244                     "literate-article", "literate-book", "literate-report", "llncs", "ltugboat",
1245                     "memoir", "moderncv", "mwart", "mwbk", "mwrep", "paper", "powerdot",
1246                     "recipebook", "report", "revtex4", "revtex", "scrartcl", "scrarticle-beamer",
1247                     "scrbook", "scrlettr", "scrlttr2", "scrreprt", "seminar", "siamltex",
1248                     "sigplanconf", "simplecv", "singlecol", "singlecol-new", "slides", "spie",
1249                     "svglobal3", "svglobal", "svjog", "svmono", "svmult", "svprobth", "tarticle",
1250                     "tbook", "treport", "tufte-book", "tufte-handout"]
1251     # A list of "safe" modules, same as above
1252     safe_modules = ["biblatex", "beameraddons", "beamersession", "braille", "customHeadersFooters",
1253                     "endnotes", "enumitem", "eqs-within-sections", "figs-within-sections", "fix-cm",
1254                     "fixltx2e", "foottoend", "hanging", "jscharstyles", "knitr", "lilypond",
1255                     "linguistics", "linguisticx", "logicalmkup", "minimalistic", "nomindex", "noweb",
1256                     "pdfcomment", "sweave", "tabs-within-sections", "theorems-ams-bytype",
1257                     "theorems-ams-extended-bytype", "theorems-ams-extended", "theorems-ams", "theorems-bytype",
1258                     "theorems-chap-bytype", "theorems-chap", "theorems-named", "theorems-sec-bytype",
1259                     "theorems-sec", "theorems-starred", "theorems-std", "todonotes"]
1260     # Modules we need to take care of
1261     caveat_modules = ["initials"]
1262     # information about the relevant styles in caveat_modules (number of opt and req args)
1263     # use this if we get more caveat_modules. For now, use hard coding (see below).
1264     # initials = [{'Layout' : 'Initial', 'opt' : 1, 'req' : 1}]
1265
1266     # Is this a known safe layout?
1267     safe_layout = document.textclass in safe_layouts
1268     if not safe_layout:
1269         document.warning("Lyx2lyx knows nothing about textclass '%s'. "
1270                          "Please check if short title insets have been converted correctly."
1271                          % document.textclass)
1272     # Do we use unsafe or unknown modules
1273     mods = document.get_module_list()
1274     unknown_modules = False
1275     used_caveat_modules = list()
1276     for mod in mods:
1277         if mod in safe_modules:
1278             continue
1279         if mod in caveat_modules:
1280             used_caveat_modules.append(mod)
1281             continue
1282         unknown_modules = True
1283         document.warning("Lyx2lyx knows nothing about module '%s'. "
1284                          "Please check if short title insets have been converted correctly."
1285                          % mod)
1286
1287     i = 0
1288     while True:
1289         i = find_token(document.body, "\\begin_inset Argument", i)
1290         if i == -1:
1291             return
1292
1293         if not safe_layout or unknown_modules:
1294             # We cannot do more here since we have no access to this layout.
1295             # InsetArgument itself will do the real work
1296             # (see InsetArgument::updateBuffer())
1297             document.body[i] = "\\begin_inset Argument 999"
1298             i = i + 1
1299             continue
1300         
1301         # Find containing paragraph layout
1302         parent = get_containing_layout(document.body, i)
1303         if parent == False:
1304             document.warning("Malformed LyX document: Can't find parent paragraph layout")
1305             i = i + 1
1306             continue
1307         parbeg = parent[1]
1308         parend = parent[2]
1309         allowed_opts = -1
1310         first_req = -1
1311         if len(used_caveat_modules) > 0:
1312             # We know for now that this must be the initials module with the Initial layout
1313             # If we get more such modules, we need some automating.
1314             if parent[0] == "Initial":
1315                 # Layout has 1 opt and 1 req arg.
1316                 # Count the actual arguments
1317                 actualargs = 0
1318                 for p in range(parbeg, parend):
1319                     if document.body[p] == "\\begin_inset Argument":
1320                         actualargs += 1
1321                 if actualargs == 1:
1322                     allowed_opts = 0
1323                     first_req = 2
1324         # Collect all arguments in this paragraph
1325         argnr = 0
1326         for p in range(parbeg, parend):
1327             if document.body[p] == "\\begin_inset Argument":
1328                 argnr += 1
1329                 if allowed_opts != -1:
1330                     # We have less arguments than opt + required.
1331                     # required must take precedence.
1332                     if argnr > allowed_opts and argnr < first_req:
1333                         argnr = first_req
1334                 document.body[p] = "\\begin_inset Argument %d" % argnr
1335         i = i + 1
1336
1337
1338 def revert_latexargs(document):
1339     " Revert InsetArgument to old syntax "
1340
1341     i = 0
1342     rx = re.compile(r'^\\begin_inset Argument (\d+)$')
1343     args = dict()
1344     while True:
1345         # Search for Argument insets
1346         i = find_token(document.body, "\\begin_inset Argument", i)
1347         if i == -1:
1348             return
1349         m = rx.match(document.body[i])
1350         if not m:
1351             # No ID: inset already reverted
1352             i = i + 1
1353             continue
1354         # Find containing paragraph layout
1355         parent = get_containing_layout(document.body, i)
1356         if parent == False:
1357             document.warning("Malformed LyX document: Can't find parent paragraph layout")
1358             i = i + 1
1359             continue
1360         parbeg = parent[1]
1361         parend = parent[2]
1362         realparbeg = parent[3]
1363         # Collect all arguments in this paragraph 
1364         realparend = parend
1365         for p in range(parbeg, parend):
1366             m = rx.match(document.body[p])
1367             if m:
1368                 val = int(m.group(1))
1369                 j = find_end_of_inset(document.body, p)
1370                 # Revert to old syntax
1371                 document.body[p] = "\\begin_inset Argument"
1372                 if j == -1:
1373                     document.warning("Malformed LyX document: Can't find end of Argument inset")
1374                     continue
1375                 if val > 0:
1376                     args[val] = document.body[p : j + 1]
1377                 # Adjust range end
1378                 realparend = realparend - len(document.body[p : j + 1])
1379                 # Remove arg inset at this position
1380                 del document.body[p : j + 1]
1381             if p >= realparend:
1382                 break
1383         # Now sort the arg insets
1384         subst = [""]
1385         for f in sorted(args):
1386             subst += args[f]
1387             del args[f]
1388         # Insert the sorted arg insets at paragraph begin
1389         document.body[realparbeg : realparbeg] = subst
1390
1391         i = realparbeg + 1 + len(subst)
1392
1393
1394 def revert_Argument_to_TeX_brace(document, line, endline, n, nmax, environment, opt):
1395     '''
1396     Reverts an InsetArgument to TeX-code
1397     usage:
1398     revert_Argument_to_TeX_brace(document, LineOfBegin, LineOfEnd, StartArgument, EndArgument, isEnvironment, isOpt)
1399     LineOfBegin is the line  of the \begin_layout or \begin_inset statement
1400     LineOfEnd is the line  of the \end_layout or \end_inset statement, if "0" is given, the end of the file is used instead
1401     StartArgument is the number of the first argument that needs to be converted
1402     EndArgument is the number of the last argument that needs to be converted or the last defined one
1403     isEnvironment must be true, if the layout is for a LaTeX environment
1404     isOpt must be true, if the argument is an optional one
1405     '''
1406     lineArg = 0
1407     wasOpt = False
1408     while lineArg != -1 and n < nmax + 1:
1409       lineArg = find_token(document.body, "\\begin_inset Argument " + str(n), line)
1410       if lineArg > endline and endline != 0:
1411         return wasOpt
1412       if lineArg != -1:
1413         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
1414         # we have to assure that no other inset is in the Argument
1415         beginInset = find_token(document.body, "\\begin_inset", beginPlain)
1416         endInset = find_token(document.body, "\\end_inset", beginPlain)
1417         k = beginPlain + 1
1418         l = k
1419         while beginInset < endInset and beginInset != -1:
1420           beginInset = find_token(document.body, "\\begin_inset", k)
1421           endInset = find_token(document.body, "\\end_inset", l)
1422           k = beginInset + 1
1423           l = endInset + 1
1424         if environment == False:
1425           if opt == False:
1426             document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}{")
1427             del(document.body[lineArg : beginPlain + 1])
1428             wasOpt = False
1429           else:
1430             document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("]")
1431             document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("[")
1432             wasOpt = True
1433         else:
1434           document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
1435           document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("{")
1436           wasOpt = False
1437         n = n + 1
1438     return wasOpt
1439
1440
1441 def convert_TeX_brace_to_Argument(document, line, n, nmax, inset, environment):
1442     '''
1443     Converts TeX code for mandatory arguments to an InsetArgument
1444     The conversion of TeX code for optional arguments must be done with another routine
1445     !!! Be careful if the braces are different in your case as expected here:
1446     - "}{" separates mandatory arguments of commands
1447     - "}" + "{" separates mandatory arguments of commands
1448     - "}" + " " + "{" separates mandatory arguments of commands
1449     - { and } surround a mandatory argument of an environment
1450     usage:
1451     convert_TeX_brace_to_Argument(document, LineOfBeginLayout/Inset, StartArgument, EndArgument, isInset, isEnvironment)
1452     LineOfBeginLayout/Inset is the line  of the \begin_layout or \begin_inset statement
1453     StartArgument is the number of the first ERT that needs to be converted
1454     EndArgument is the number of the last ERT that needs to be converted
1455     isInset must be true, if braces inside an InsetLayout needs to be converted
1456     isEnvironment must be true, if the layout is for a LaTeX environment
1457     
1458     Todo: this routine can currently handle only one mandatory argument of environments
1459     '''
1460     lineERT = line
1461     endn = line
1462     loop = 1
1463     while lineERT != -1 and n < nmax + 1:
1464       lineERT = find_token(document.body, "\\begin_inset ERT", lineERT)
1465       if environment == False and lineERT != -1:
1466         bracePair = find_token(document.body, "}{", lineERT)
1467         # assure that the "}{" is in this ERT
1468         if bracePair == lineERT + 5:
1469           end = find_token(document.body, "\\end_inset", bracePair)
1470           document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1471           if loop == 1:
1472             # in the case that n > 1 we have optional arguments before
1473             # therefore detect them if any
1474             if n > 1:
1475               # first check if there is an argument
1476               lineArg = find_token(document.body, "\\begin_inset Argument", line)
1477               if lineArg < lineERT and lineArg != -1:
1478                 # we have an argument, so now search backwards for its end
1479                 # we must now assure that we don't find other insets like e.g. a newline
1480                 endInsetArg = lineERT
1481                 endLayoutArg = endInsetArg
1482                 while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1483                   endInsetArg = endInsetArg - 1
1484                   endLayoutArg = endInsetArg
1485                   endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1486                   endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1487                 line = endInsetArg + 1
1488             if inset == False:
1489               document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1490             else:
1491               document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1492           else:
1493             document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1494           n = n + 1
1495           endn = end
1496           loop = loop + 1
1497         # now check the case that we have "}" + "{" in two ERTs
1498         else:
1499           endBrace = find_token(document.body, "}", lineERT)
1500           if endBrace == lineERT + 5:
1501             beginBrace = find_token(document.body, "{", endBrace)
1502             # assure that the ERTs are consecutive (11 or 12 depending if there is a space between the ERTs or not)
1503             if beginBrace == endBrace + 11 or beginBrace == endBrace + 12:
1504               end = find_token(document.body, "\\end_inset", beginBrace)
1505               document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1506               if loop == 1:
1507                 # in the case that n > 1 we have optional arguments before
1508                 # therefore detect them if any
1509                 if n > 1:
1510                   # first check if there is an argument
1511                   lineArg = find_token(document.body, "\\begin_inset Argument", line)
1512                   if lineArg < lineERT and lineArg != -1:
1513                     # we have an argument, so now search backwards for its end
1514                     # we must now assure that we don't find other insets like e.g. a newline
1515                     endInsetArg = lineERT
1516                     endLayoutArg = endInsetArg
1517                     while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1518                       endInsetArg = endInsetArg - 1
1519                       endLayoutArg = endInsetArg
1520                       endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1521                       endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1522                     line = endInsetArg + 1
1523                 if inset == False:
1524                   document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1525                 else:
1526                   document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1527               else:
1528                 document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1529               n = n + 1
1530               loop = loop + 1
1531               # set the line where the next argument will be inserted
1532               if beginBrace == endBrace + 11:
1533                 endn = end - 11
1534               else:
1535                 endn = end - 12
1536           else:
1537             lineERT = lineERT + 1
1538       if environment == True and lineERT != -1:
1539         opening = find_token(document.body, "{", lineERT)
1540         if opening == lineERT + 5: # assure that the "{" is in this ERT
1541           end = find_token(document.body, "\\end_inset", opening)
1542           document.body[lineERT : end + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1543           n = n + 1
1544           lineERT2 = find_token(document.body, "\\begin_inset ERT", lineERT)
1545           closing = find_token(document.body, "}", lineERT2)
1546           if closing == lineERT2 + 5: # assure that the "}" is in this ERT
1547             end2 = find_token(document.body, "\\end_inset", closing)
1548             document.body[lineERT2 : end2 + 1] = ["\\end_layout", "", "\\end_inset"]
1549         else:
1550           lineERT = lineERT + 1
1551
1552
1553 def revert_IEEEtran(document):
1554   '''
1555   Reverts InsetArgument of
1556   Page headings
1557   Biography
1558   Biography without photo
1559   to TeX-code
1560   '''
1561   if document.textclass == "IEEEtran":
1562     i = 0
1563     i2 = 0
1564     j = 0
1565     k = 0
1566     while True:
1567       if i != -1:
1568         i = find_token(document.body, "\\begin_layout Page headings", i)
1569       if i != -1:
1570         revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1571         i = i + 1
1572       if i2 != -1:
1573         i2 = find_token(document.body, "\\begin_inset Flex Paragraph Start", i2)
1574       if i2 != -1:
1575         revert_Argument_to_TeX_brace(document, i2, 0, 1, 1, False, False)
1576         i2 = i2 + 1
1577       if j != -1:
1578         j = find_token(document.body, "\\begin_layout Biography without photo", j)
1579       if j != -1:
1580         revert_Argument_to_TeX_brace(document, j, 0, 1, 1, True, False)
1581         j = j + 1
1582       if k != -1:
1583         k = find_token(document.body, "\\begin_layout Biography", k)
1584         kA = find_token(document.body, "\\begin_layout Biography without photo", k)
1585         if k == kA and k != -1:
1586           k = k + 1
1587           continue
1588       if k != -1:
1589         # start with the second argument, therefore 2
1590         revert_Argument_to_TeX_brace(document, k, 0, 2, 2, True, False)
1591         k = k + 1
1592       if i == -1 and i2 == -1 and j == -1 and k == -1:
1593         return
1594
1595
1596 def revert_IEEEtran_2(document):
1597   '''
1598   Reverts Flex Paragraph Start to TeX-code
1599   '''
1600   if document.textclass == "IEEEtran":
1601     begin = 0
1602     while True:
1603       if begin != -1:
1604         begin = find_token(document.body, "\\begin_inset Flex Paragraph Start", begin)
1605       if begin != -1:
1606         end1 = find_end_of_inset(document.body, begin)
1607         document.body[end1 - 2 : end1 + 1] = put_cmd_in_ert("}")
1608         document.body[begin : begin + 4] = put_cmd_in_ert("\\IEEEPARstart{")
1609         begin = begin + 5
1610       if begin == -1:
1611         return
1612
1613
1614 def convert_IEEEtran(document):
1615   '''
1616   Converts ERT of
1617   Page headings
1618   Biography
1619   Biography without photo
1620   to InsetArgument
1621   '''
1622   if document.textclass == "IEEEtran":
1623     i = 0
1624     j = 0
1625     k = 0
1626     while True:
1627       if i != -1:
1628         i = find_token(document.body, "\\begin_layout Page headings", i)
1629       if i != -1:
1630         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1631         i = i + 1
1632       if j != -1:
1633         j = find_token(document.body, "\\begin_layout Biography without photo", j)
1634       if j != -1:
1635         convert_TeX_brace_to_Argument(document, j, 1, 1, False, True)
1636         j = j + 1
1637       if k != -1:
1638         # assure that we don't handle Biography Biography without photo
1639         k = find_token(document.body, "\\begin_layout Biography", k)
1640         kA = find_token(document.body, "\\begin_layout Biography without photo", k - 1)
1641       if k == kA and k != -1:
1642         k = k + 1
1643         continue
1644       if k != -1:
1645         # the argument we want to convert is the second one
1646         convert_TeX_brace_to_Argument(document, k, 2, 2, False, True)
1647         k = k + 1
1648       if i == -1 and j == -1 and k == -1:
1649         return
1650
1651
1652 def revert_AASTeX(document):
1653   " Reverts InsetArgument of Altaffilation to TeX-code "
1654   if document.textclass == "aastex":
1655     i = 0
1656     while True:
1657       if i != -1:
1658         i = find_token(document.body, "\\begin_layout Altaffilation", i)
1659       if i != -1:
1660         revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1661         i = i + 1
1662       if i == -1:
1663         return
1664
1665
1666 def convert_AASTeX(document):
1667   " Converts ERT of Altaffilation to InsetArgument "
1668   if document.textclass == "aastex":
1669     i = 0
1670     while True:
1671       if i != -1:
1672         i = find_token(document.body, "\\begin_layout Altaffilation", i)
1673       if i != -1:
1674         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1675         i = i + 1
1676       if i == -1:
1677         return
1678
1679
1680 def revert_AGUTeX(document):
1681   " Reverts InsetArgument of Author affiliation to TeX-code "
1682   if document.textclass == "agutex":
1683     i = 0
1684     while True:
1685       if i != -1:
1686         i = find_token(document.body, "\\begin_layout Author affiliation", i)
1687       if i != -1:
1688         revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1689         i = i + 1
1690       if i == -1:
1691         return
1692
1693
1694 def convert_AGUTeX(document):
1695   " Converts ERT of Author affiliation to InsetArgument "
1696   if document.textclass == "agutex":
1697     i = 0
1698     while True:
1699       if i != -1:
1700         i = find_token(document.body, "\\begin_layout Author affiliation", i)
1701       if i != -1:
1702         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1703         i = i + 1
1704       if i == -1:
1705         return
1706
1707
1708 def revert_IJMP(document):
1709   " Reverts InsetArgument of MarkBoth to TeX-code "
1710   if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1711     i = 0
1712     while True:
1713       if i != -1:
1714         i = find_token(document.body, "\\begin_layout MarkBoth", i)
1715       if i != -1:
1716         revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1717         i = i + 1
1718       if i == -1:
1719         return
1720
1721
1722 def convert_IJMP(document):
1723   " Converts ERT of MarkBoth to InsetArgument "
1724   if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1725     i = 0
1726     while True:
1727       if i != -1:
1728         i = find_token(document.body, "\\begin_layout MarkBoth", i)
1729       if i != -1:
1730         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1731         i = i + 1
1732       if i == -1:
1733         return
1734
1735
1736 def revert_SIGPLAN(document):
1737   " Reverts InsetArguments of SIGPLAN to TeX-code "
1738   if document.textclass == "sigplanconf":
1739     i = 0
1740     j = 0
1741     while True:
1742       if i != -1:
1743         i = find_token(document.body, "\\begin_layout Conference", i)
1744       if i != -1:
1745         revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1746         i = i + 1
1747       if j != -1:
1748         j = find_token(document.body, "\\begin_layout Author", j)
1749       if j != -1:
1750         revert_Argument_to_TeX_brace(document, j, 0, 1, 2, False, False)
1751         j = j + 1
1752       if i == -1 and j == -1:
1753         return
1754
1755
1756 def convert_SIGPLAN(document):
1757   " Converts ERT of SIGPLAN to InsetArgument "
1758   if document.textclass == "sigplanconf":
1759     i = 0
1760     j = 0
1761     while True:
1762       if i != -1:
1763         i = find_token(document.body, "\\begin_layout Conference", i)
1764       if i != -1:
1765         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1766         i = i + 1
1767       if j != -1:
1768         j = find_token(document.body, "\\begin_layout Author", j)
1769       if j != -1:
1770         convert_TeX_brace_to_Argument(document, j, 1, 2, False, False)
1771         j = j + 1
1772       if i == -1 and j == -1:
1773         return
1774
1775
1776 def revert_SIGGRAPH(document):
1777   " Reverts InsetArgument of Flex CRcat to TeX-code "
1778   if document.textclass == "acmsiggraph":
1779     i = 0
1780     while True:
1781       if i != -1:
1782         i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1783       if i != -1:
1784         revert_Argument_to_TeX_brace(document, i, 0, 1, 3, False, False)
1785         i = i + 1
1786       if i == -1:
1787         return
1788
1789
1790 def convert_SIGGRAPH(document):
1791   " Converts ERT of Flex CRcat to InsetArgument "
1792   if document.textclass == "acmsiggraph":
1793     i = 0
1794     while True:
1795       if i != -1:
1796         i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1797       if i != -1:
1798         convert_TeX_brace_to_Argument(document, i, 1, 3, True, False)
1799         i = i + 1
1800       if i == -1:
1801         return
1802
1803
1804 def revert_EuropeCV(document):
1805   " Reverts InsetArguments of europeCV to TeX-code "
1806   if document.textclass == "europecv":
1807     i = 0
1808     j = 0
1809     k = 0
1810     m = 0
1811     while True:
1812       if i != -1:
1813         i = find_token(document.body, "\\begin_layout Item", i)
1814       if i != -1:
1815         revert_Argument_to_TeX_brace(document, i, 0, 2, 2, False, False)
1816         i = i + 1
1817       if j != -1:
1818         j = find_token(document.body, "\\begin_layout BulletedItem", j)
1819       if j != -1:
1820         revert_Argument_to_TeX_brace(document, j, 0, 2, 2, False, False)
1821         j = j + 1
1822       if k != -1:
1823         k = find_token(document.body, "\\begin_layout Language", k)
1824       if k != -1:
1825         revert_Argument_to_TeX_brace(document, k, 0, 2, 6, False, False)
1826         k = k + 1
1827       if m != -1:
1828         m = find_token(document.body, "\\begin_layout LastLanguage", m)
1829       if m != -1:
1830         revert_Argument_to_TeX_brace(document, m, 0, 2, 6, False, False)
1831         m = m + 1
1832       if i == -1 and j == -1 and k == -1 and m == -1:
1833         return
1834
1835
1836 def convert_EuropeCV(document):
1837   " Converts ERT of europeCV to InsetArgument "
1838   if document.textclass == "europecv":
1839     i = 0
1840     j = 0
1841     k = 0
1842     m = 0
1843     while True:
1844       if i != -1:
1845         i = find_token(document.body, "\\begin_layout Item", i)
1846       if i != -1:
1847         convert_TeX_brace_to_Argument(document, i, 2, 2, False, False)
1848         i = i + 1
1849       if j != -1:
1850         j = find_token(document.body, "\\begin_layout BulletedItem", j)
1851       if j != -1:
1852         convert_TeX_brace_to_Argument(document, j, 2, 2, False, False)
1853         j = j + 1
1854       if k != -1:
1855         k = find_token(document.body, "\\begin_layout Language", k)
1856       if k != -1:
1857         convert_TeX_brace_to_Argument(document, k, 2, 6, False, False)
1858         k = k + 1
1859       if m != -1:
1860         m = find_token(document.body, "\\begin_layout LastLanguage", m)
1861       if m != -1:
1862         convert_TeX_brace_to_Argument(document, m, 2, 6, False, False)
1863         m = m + 1
1864       if i == -1 and j == -1 and k == -1 and m == -1:
1865         return
1866
1867
1868 def revert_ModernCV(document):
1869   " Reverts InsetArguments of modernCV to TeX-code "
1870   if document.textclass == "moderncv":
1871     j = 0
1872     k = 0
1873     m = 0
1874     o = 0
1875     while True:
1876       if j != -1:
1877         j = find_token(document.body, "\\begin_layout Entry", j)
1878       if j != -1:
1879         revert_Argument_to_TeX_brace(document, j, 0, 1, 5, False, False)
1880         j = j + 1
1881       if k != -1:
1882         k = find_token(document.body, "\\begin_layout Item", k)
1883       if k != -1:
1884         revert_Argument_to_TeX_brace(document, k, 0, 1, 1, False, False)
1885         k = k + 1
1886       if m != -1:
1887         m = find_token(document.body, "\\begin_layout ItemWithComment", m)
1888       if m != -1:
1889         revert_Argument_to_TeX_brace(document, m, 0, 1, 2, False, False)
1890         document.body[m] = document.body[m].replace("\\begin_layout ItemWithComment", "\\begin_layout Language")
1891         m = m + 1
1892       if o != -1:
1893         o = find_token(document.body, "\\begin_layout DoubleItem", o)
1894       if o != -1:
1895         revert_Argument_to_TeX_brace(document, o, 0, 1, 3, False, False)
1896         document.body[o] = document.body[o].replace("\\begin_layout DoubleItem", "\\begin_layout Computer")
1897         o = o + 1
1898       if j == -1 and k == -1 and m == -1 and o == -1:
1899         return
1900
1901
1902 def revert_ModernCV_2(document):
1903   " Reverts the Flex:Column inset of modernCV to TeX-code "
1904   if document.textclass == "moderncv":
1905     flex = 0
1906     flexEnd = -1
1907     while True:
1908       if flex != -1:
1909         flex = find_token(document.body, "\\begin_inset Flex Column", flex)
1910       if flex != -1:
1911         flexEnd = find_end_of_inset(document.body, flex)
1912         wasOpt = revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, False, True)
1913         revert_Argument_to_TeX_brace(document, flex, 0, 2, 2, False, False)
1914         flexEnd = find_end_of_inset(document.body, flex)
1915         if wasOpt == True:
1916           document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\cvcolumn")
1917         else:
1918           document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\cvcolumn{")
1919         document.body[flexEnd + 4 : flexEnd + 7] = put_cmd_in_ert("}")
1920         flex = flex + 1
1921       if flex == -1:
1922         return flexEnd
1923
1924
1925 def revert_ModernCV_3(document):
1926   " Reverts the Column style of modernCV to TeX-code "
1927   if document.textclass == "moderncv":
1928     # revert the layouts
1929     revert_ModernCV(document)
1930     p = 0
1931     # get the position of the end of the last column inset
1932     LastFlexEnd = revert_ModernCV_2(document)
1933     while True:
1934       if p != -1:
1935         p = find_token(document.body, "\\begin_layout Columns", p)
1936       if p != -1:
1937         pEnd = find_end_of_layout(document.body, p)
1938         document.body[p] = document.body[p].replace("\\begin_layout Columns", "\\begin_layout Standard")
1939         if LastFlexEnd != -1:
1940           document.body[p + 1 : p + 1] = put_cmd_in_ert("\\begin{cvcolumns}")
1941           document.body[LastFlexEnd + 24 : LastFlexEnd + 24] = put_cmd_in_ert("\\end{cvcolumns}")
1942         p = p + 1
1943       if p == -1:
1944         return
1945
1946
1947 def convert_ModernCV(document):
1948   " Converts ERT of modernCV to InsetArgument "
1949   if document.textclass == "moderncv":
1950     i = 0
1951     j = 0
1952     k = 0
1953     m = 0
1954     o = 0
1955     while True:
1956       if i != -1:
1957         i = find_token(document.body, "\\begin_layout DoubleItem", i)
1958       if i != -1:
1959         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1960         document.body[o] = document.body[o].replace("\\begin_layout DoubleItem", "\\begin_layout DoubleListItem")
1961         i = i + 1
1962       if j != -1:
1963         j = find_token(document.body, "\\begin_layout Entry", j)
1964       if j != -1:
1965         convert_TeX_brace_to_Argument(document, j, 1, 5, False, False)
1966         j = j + 1
1967       if k != -1:
1968         k = find_token(document.body, "\\begin_layout Item", k)
1969       if k != -1:
1970         convert_TeX_brace_to_Argument(document, k, 1, 1, False, False)
1971         k = k + 1
1972       if m != -1:
1973         m = find_token(document.body, "\\begin_layout Language", m)
1974       if m != -1:
1975         convert_TeX_brace_to_Argument(document, m, 1, 2, False, False)
1976         m = m + 1
1977       if i == -1 and j == -1 and k == -1 and m == -1:
1978         return
1979
1980
1981 def revert_Initials(document):
1982   " Reverts InsetArgument of Initial to TeX-code "
1983   i = 0
1984   while True:
1985     if i != -1:
1986       i = find_token(document.body, "\\begin_layout Initial", i)
1987     if i != -1:
1988       # first arg (optional) and second arg (first mandatory) are supported in LyX 2.0.x
1989       revert_Argument_to_TeX_brace(document, i, 0, 3, 3, False, False)
1990       i = i + 1
1991     if i == -1:
1992       return
1993
1994
1995 def convert_Initials(document):
1996   " Converts ERT of Initial to InsetArgument "
1997   i = 0
1998   while True:
1999     if i != -1:
2000       i = find_token(document.body, "\\begin_layout Initial", i)
2001     if i != -1:
2002       convert_TeX_brace_to_Argument(document, i, 3, 3, False, False)
2003       i = i + 1
2004     if i == -1:
2005       return
2006
2007
2008 def revert_literate(document):
2009     " Revert Literate document to old format "
2010     if del_token(document.header, "noweb", 0):
2011       document.textclass = "literate-" + document.textclass
2012       i = 0
2013       while True:
2014         i = find_token(document.body, "\\begin_layout Chunk", i)
2015         if i == -1:
2016           break
2017         document.body[i] = "\\begin_layout Scrap"
2018         i = i + 1
2019
2020
2021 def convert_literate(document):
2022     " Convert Literate document to new format"
2023     i = find_token(document.header, "\\textclass", 0)    
2024     if (i != -1) and "literate-" in document.header[i]:
2025       document.textclass = document.header[i].replace("\\textclass literate-", "")
2026       j = find_token(document.header, "\\begin_modules", 0)
2027       if (j != -1):
2028         document.header.insert(j + 1, "noweb")
2029       else:
2030         document.header.insert(i + 1, "\\end_modules")
2031         document.header.insert(i + 1, "noweb")
2032         document.header.insert(i + 1, "\\begin_modules")
2033       i = 0
2034       while True:
2035         i = find_token(document.body, "\\begin_layout Scrap", i)
2036         if i == -1:
2037           break
2038         document.body[i] = "\\begin_layout Chunk"
2039         i = i + 1
2040
2041
2042 def revert_itemargs(document):
2043     " Reverts \\item arguments to TeX-code "
2044     i = 0
2045     while True:
2046         i = find_token(document.body, "\\begin_inset Argument item:", i)
2047         if i == -1:
2048             return
2049         j = find_end_of_inset(document.body, i)
2050         # Find containing paragraph layout
2051         parent = get_containing_layout(document.body, i)
2052         if parent == False:
2053             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2054             i = i + 1
2055             continue
2056         parbeg = parent[3]
2057         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2058         endPlain = find_end_of_layout(document.body, beginPlain)
2059         content = document.body[beginPlain + 1 : endPlain]
2060         del document.body[i:j+1]
2061         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2062         document.body[parbeg : parbeg] = subst
2063         i = i + 1
2064
2065
2066 def revert_garamondx_newtxmath(document):
2067     " Revert native garamond newtxmath definition to LaTeX " 
2068
2069     i = find_token(document.header, "\\font_math", 0)
2070     if i == -1:
2071        return
2072     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
2073         val = get_value(document.header, "\\font_math", i)
2074         if val == "garamondx-ntxm":
2075             add_to_preamble(document, "\\usepackage[garamondx]{newtxmath}")
2076             document.header[i] = "\\font_math auto"
2077
2078
2079 def revert_garamondx(document):
2080     " Revert native garamond font definition to LaTeX " 
2081
2082     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
2083         i = find_token(document.header, "\\font_roman garamondx", 0)
2084         if i != -1:
2085             osf = False
2086             j = find_token(document.header, "\\font_osf true", 0)
2087             if j != -1:
2088                 osf = True
2089             preamble = "\\usepackage"
2090             if osf:
2091                 preamble += "[osfI]"
2092             preamble += "{garamondx}"
2093             add_to_preamble(document, [preamble])
2094             document.header[i] = "\\font_roman default"
2095
2096
2097 def convert_beamerargs(document):
2098     " Converts beamer arguments to new layout "
2099     
2100     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2101     if document.textclass not in beamer_classes:
2102         return
2103
2104     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2105     list_layouts = ["Itemize", "Enumerate", "Description"]
2106     rx = re.compile(r'^\\begin_inset Argument (\d+)$')
2107
2108     i = 0
2109     while True:
2110         i = find_token(document.body, "\\begin_inset Argument", i)
2111         if i == -1:
2112             return
2113         # Find containing paragraph layout
2114         parent = get_containing_layout(document.body, i)
2115         if parent == False:
2116             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2117             i = i + 1
2118             continue
2119         parbeg = parent[1]
2120         parend = parent[2]
2121         layoutname = parent[0]
2122         for p in range(parbeg, parend):
2123             if layoutname in shifted_layouts:
2124                 m = rx.match(document.body[p])
2125                 if m:
2126                     argnr = int(m.group(1))
2127                     argnr += 1
2128                     document.body[p] = "\\begin_inset Argument %d" % argnr
2129             if layoutname == "AgainFrame":
2130                 m = rx.match(document.body[p])
2131                 if m:
2132                     document.body[p] = "\\begin_inset Argument 3"
2133                     if document.body[p + 4] == "\\begin_inset ERT":
2134                         if document.body[p + 9].startswith("<"):
2135                             # This is an overlay specification
2136                             # strip off the <
2137                             document.body[p + 9] = document.body[p + 9][1:]
2138                             if document.body[p + 9].endswith(">"):
2139                                 # strip off the >
2140                                 document.body[p + 9] = document.body[p + 9][:-1]
2141                                 # Shift this one
2142                                 document.body[p] = "\\begin_inset Argument 2"
2143             if layoutname in list_layouts:
2144                 m = rx.match(document.body[p])
2145                 if m:
2146                     if m.group(1) == "1":
2147                         if document.body[p + 4] == "\\begin_inset ERT":
2148                             if document.body[p + 9].startswith("<"):
2149                                 # This is an overlay specification
2150                                 # strip off the <
2151                                 document.body[p + 9] = document.body[p + 9][1:]
2152                                 if document.body[p + 9].endswith(">"):
2153                                     # strip off the >
2154                                     document.body[p + 9] = document.body[p + 9][:-1]
2155                         elif layoutname != "Itemize":
2156                             # Shift this one
2157                             document.body[p] = "\\begin_inset Argument 2"
2158         i = i + 1
2159
2160
2161 def convert_againframe_args(document):
2162     " Converts beamer AgainFrame to new layout "
2163
2164     # FIXME: This currently only works if the arguments are in one single ERT
2165     
2166     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2167     if document.textclass not in beamer_classes:
2168         return
2169    
2170     i = 0
2171     while True:
2172         i = find_token(document.body, "\\begin_layout AgainFrame", i)
2173         if i == -1:
2174             break
2175         parent = get_containing_layout(document.body, i)
2176         if parent[1] != i:
2177             document.warning("Wrong parent layout!")
2178         j = parent[2]
2179         parbeg = parent[3]
2180         if i != -1:
2181             if document.body[parbeg] == "\\begin_inset ERT":
2182                 ertcont = parbeg + 5
2183                 if document.body[ertcont].startswith("[<"):
2184                     # This is a default overlay specification
2185                     # strip off the [<
2186                     document.body[ertcont] = document.body[ertcont][2:]
2187                     if document.body[ertcont].endswith(">]"):
2188                         # strip off the >]
2189                         document.body[ertcont] = document.body[ertcont][:-2]
2190                     elif document.body[ertcont].endswith("]"):
2191                         # divide the args
2192                         tok = document.body[ertcont].find('>][')
2193                         if tok != -1:
2194                             subst = [document.body[ertcont][:tok],
2195                                      '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2196                                      'status collapsed', '', '\\begin_layout Plain Layout',
2197                                      document.body[ertcont][tok + 3:-1]]
2198                             document.body[ertcont : ertcont + 1] = subst
2199                      # Convert to ArgInset
2200                     document.body[parbeg] = "\\begin_inset Argument 2"
2201                     i = j
2202                     continue
2203                 elif document.body[ertcont].startswith("<"):
2204                     # This is an overlay specification
2205                     # strip off the <
2206                     document.body[ertcont] = document.body[ertcont][1:]
2207                     if document.body[ertcont].endswith(">"):
2208                         # strip off the >
2209                         document.body[ertcont] = document.body[ertcont][:-1]
2210                         # Convert to ArgInset
2211                         document.body[parbeg] = "\\begin_inset Argument 1"
2212                     elif document.body[ertcont].endswith(">]"):
2213                         # divide the args
2214                         tok = document.body[ertcont].find('>[<')
2215                         if tok != -1:
2216                            document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2217                                                            '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2218                                                            'status collapsed', '', '\\begin_layout Plain Layout',
2219                                                            document.body[ertcont][tok + 3:-2]]
2220                         # Convert to ArgInset
2221                         document.body[parbeg] = "\\begin_inset Argument 1"
2222                     elif document.body[ertcont].endswith("]"):
2223                         # divide the args
2224                         tok = document.body[ertcont].find('>[<')
2225                         if tok != -1:
2226                            # divide the args
2227                            tokk = document.body[ertcont].find('>][')
2228                            if tokk != -1:
2229                                document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2230                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2231                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2232                                                                document.body[ertcont][tok + 3:tokk],
2233                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2234                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2235                                                                document.body[ertcont][tokk + 3:-1]]
2236                         else:
2237                             tokk = document.body[ertcont].find('>[')
2238                             if tokk != -1:
2239                                 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
2240                                                                 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2241                                                                 'status collapsed', '', '\\begin_layout Plain Layout',
2242                                                                 document.body[ertcont][tokk + 2:-1]]
2243                         # Convert to ArgInset
2244                         document.body[parbeg] = "\\begin_inset Argument 1"
2245                     i = j
2246                     continue
2247                 elif document.body[ertcont].startswith("["):
2248                     # This is an ERT option
2249                     # strip off the [
2250                     document.body[ertcont] = document.body[ertcont][1:]
2251                     if document.body[ertcont].endswith("]"):
2252                         # strip off the ]
2253                         document.body[ertcont] = document.body[ertcont][:-1]
2254                         # Convert to ArgInset
2255                         document.body[parbeg] = "\\begin_inset Argument 3"
2256                     i = j
2257                     continue
2258         i = j
2259
2260
2261 def convert_corollary_args(document):
2262     " Converts beamer corrolary-style ERT arguments native InsetArgs "
2263     
2264     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2265     if document.textclass not in beamer_classes:
2266         return
2267    
2268     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2269     for lay in corollary_layouts:
2270         i = 0
2271         while True:
2272             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2273             if i == -1:
2274                 break
2275             parent = get_containing_layout(document.body, i)
2276             if parent[1] != i:
2277                 document.warning("Wrong parent layout!")
2278             j = parent[2]
2279             parbeg = parent[3]
2280             if i != -1:
2281                 if document.body[parbeg] == "\\begin_inset ERT":
2282                     ertcont = parbeg + 5
2283                     if document.body[ertcont].startswith("<"):
2284                         # This is an overlay specification
2285                         # strip off the <
2286                         document.body[ertcont] = document.body[ertcont][1:]
2287                         if document.body[ertcont].endswith(">"):
2288                             # strip off the >
2289                             document.body[ertcont] = document.body[ertcont][:-1]
2290                         elif document.body[ertcont].endswith("]"):
2291                             # divide the args
2292                             tok = document.body[ertcont].find('>[')
2293                             if tok != -1:
2294                                 subst = [document.body[ertcont][:tok],
2295                                          '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2296                                          'status collapsed', '', '\\begin_layout Plain Layout',
2297                                          document.body[ertcont][tok + 2:-1]]
2298                                 document.body[ertcont : ertcont + 1] = subst
2299                         # Convert to ArgInset
2300                         document.body[parbeg] = "\\begin_inset Argument 1"
2301                         i = j
2302                         continue
2303                     elif document.body[ertcont].startswith("["):
2304                         # This is an ERT option
2305                         # strip off the [
2306                         document.body[ertcont] = document.body[ertcont][1:]
2307                         if document.body[ertcont].endswith("]"):
2308                             # strip off the ]
2309                             document.body[ertcont] = document.body[ertcont][:-1]
2310                         # Convert to ArgInset
2311                         document.body[parbeg] = "\\begin_inset Argument 2"
2312                     i = j
2313                     continue
2314             i = j
2315
2316
2317
2318 def convert_quote_args(document):
2319     " Converts beamer quote style ERT args to native InsetArgs "
2320     
2321     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2322     if document.textclass not in beamer_classes:
2323         return
2324    
2325     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2326     for lay in quote_layouts:
2327         i = 0
2328         while True:
2329             i = find_token(document.body, "\\begin_layout " + lay, i)
2330             if i == -1:
2331                 break
2332             parent = get_containing_layout(document.body, i)
2333             if parent[1] != i:
2334                 document.warning("Wrong parent layout!")
2335             j = parent[2]
2336             parbeg = parent[3]
2337             if i != -1:
2338                 if document.body[parbeg] == "\\begin_inset ERT":
2339                     if document.body[i + 6].startswith("<"):
2340                         # This is an overlay specification
2341                         # strip off the <
2342                         document.body[i + 6] = document.body[i + 6][1:]
2343                         if document.body[i + 6].endswith(">"):
2344                             # strip off the >
2345                             document.body[i + 6] = document.body[i + 6][:-1]
2346                             # Convert to ArgInset
2347                             document.body[i + 1] = "\\begin_inset Argument 1"
2348             i = j
2349
2350
2351 def revert_beamerargs(document):
2352     " Reverts beamer arguments to old layout "
2353     
2354     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2355     if document.textclass not in beamer_classes:
2356         return
2357
2358     i = 0
2359     list_layouts = ["Itemize", "Enumerate", "Description"]
2360     headings = ["Part", "Section", "Section*", "Subsection", "Subsection*",
2361                 "Subsubsection", "Subsubsection*", "FrameSubtitle", "NoteItem"]
2362     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2363     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2364     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2365
2366     while True:
2367         i = find_token(document.body, "\\begin_inset Argument", i)
2368         if i == -1:
2369             return
2370         # Find containing paragraph layout
2371         parent = get_containing_layout(document.body, i)
2372         if parent == False:
2373             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2374             i = i + 1
2375             continue
2376         parbeg = parent[1]
2377         parend = parent[2]
2378         realparbeg = parent[3]
2379         layoutname = parent[0]
2380         realparend = parend
2381         for p in range(parbeg, parend):
2382             if p >= realparend:
2383                 i = realparend
2384                 break
2385             if layoutname in headings:
2386                 m = rx.match(document.body[p])
2387                 if m:
2388                     argnr = m.group(1)
2389                     if argnr == "1":
2390                         # Find containing paragraph layout
2391                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2392                         endPlain = find_end_of_layout(document.body, beginPlain)
2393                         endInset = find_end_of_inset(document.body, p)
2394                         argcontent = document.body[beginPlain + 1 : endPlain]
2395                         # Adjust range end
2396                         realparend = realparend - len(document.body[p : endInset + 1])
2397                         # Remove arg inset
2398                         del document.body[p : endInset + 1]
2399                         if layoutname == "FrameSubtitle":
2400                             pre = put_cmd_in_ert("\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2401                         elif layoutname == "NoteItem":
2402                             pre = put_cmd_in_ert("\\note<") + argcontent + put_cmd_in_ert(">[item]")
2403                         elif layoutname.endswith('*'):
2404                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower()[:-1] + "<") + argcontent + put_cmd_in_ert(">*")
2405                         else:
2406                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2407                         secarg = find_token(document.body, "\\begin_inset Argument 2", parbeg, parend)
2408                         if secarg != -1:
2409                             # Find containing paragraph layout
2410                             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", secarg)
2411                             endPlain = find_end_of_layout(document.body, beginPlain)
2412                             endInset = find_end_of_inset(document.body, secarg)
2413                             argcontent = document.body[beginPlain + 1 : endPlain]
2414                             # Adjust range end
2415                             realparend = realparend - len(document.body[secarg : endInset + 1])
2416                             del document.body[secarg : endInset + 1]
2417                             pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2418                         pre += put_cmd_in_ert("{")
2419                         document.body[parbeg] = "\\begin_layout Standard"
2420                         document.body[realparbeg : realparbeg] = pre
2421                         pe = find_end_of_layout(document.body, parbeg)
2422                         post = put_cmd_in_ert("}")
2423                         document.body[pe : pe] = post
2424                         realparend += len(pre) + len(post)
2425             if layoutname == "AgainFrame":
2426                 m = rx.match(document.body[p])
2427                 if m:
2428                     argnr = m.group(1)
2429                     if argnr == "3":
2430                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2431                         endPlain = find_end_of_layout(document.body, beginPlain)
2432                         endInset = find_end_of_inset(document.body, p)
2433                         content = document.body[beginPlain + 1 : endPlain]
2434                         # Adjust range end
2435                         realparend = realparend - len(document.body[p : endInset + 1])
2436                         # Remove arg inset
2437                         del document.body[p : endInset + 1]
2438                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2439                         document.body[realparbeg : realparbeg] = subst
2440             if layoutname == "Overprint":
2441                 m = rx.match(document.body[p])
2442                 if m:
2443                     argnr = m.group(1)
2444                     if argnr == "1":
2445                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2446                         endPlain = find_end_of_layout(document.body, beginPlain)
2447                         endInset = find_end_of_inset(document.body, p)
2448                         content = document.body[beginPlain + 1 : endPlain]
2449                         # Adjust range end
2450                         realparend = realparend - len(document.body[p : endInset + 1])
2451                         # Remove arg inset
2452                         del document.body[p : endInset + 1]
2453                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2454                         document.body[realparbeg : realparbeg] = subst
2455             if layoutname == "OverlayArea":
2456                 m = rx.match(document.body[p])
2457                 if m:
2458                     argnr = m.group(1)
2459                     if argnr == "2":
2460                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2461                         endPlain = find_end_of_layout(document.body, beginPlain)
2462                         endInset = find_end_of_inset(document.body, p)
2463                         content = document.body[beginPlain + 1 : endPlain]
2464                         # Adjust range end
2465                         realparend = realparend - len(document.body[p : endInset + 1])
2466                         # Remove arg inset
2467                         del document.body[p : endInset + 1]
2468                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2469                         document.body[realparbeg : realparbeg] = subst
2470             if layoutname in list_layouts:
2471                 m = rx.match(document.body[p])
2472                 if m:
2473                     argnr = m.group(1)
2474                     if argnr == "1":
2475                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2476                         endPlain = find_end_of_layout(document.body, beginPlain)
2477                         endInset = find_end_of_inset(document.body, p)
2478                         content = document.body[beginPlain + 1 : endPlain]
2479                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2480                         realparend = realparend + len(subst) - len(content)
2481                         document.body[beginPlain + 1 : endPlain] = subst
2482                     elif argnr == "item:1":
2483                         j = find_end_of_inset(document.body, i)
2484                         # Find containing paragraph layout
2485                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2486                         endPlain = find_end_of_layout(document.body, beginPlain)
2487                         content = document.body[beginPlain + 1 : endPlain]
2488                         del document.body[i:j+1]
2489                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2490                         document.body[realparbeg : realparbeg] = subst
2491                     elif argnr == "item:2":
2492                         j = find_end_of_inset(document.body, i)
2493                         # Find containing paragraph layout
2494                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2495                         endPlain = find_end_of_layout(document.body, beginPlain)
2496                         content = document.body[beginPlain + 1 : endPlain]
2497                         del document.body[i:j+1]
2498                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2499                         document.body[realparbeg : realparbeg] = subst
2500             if layoutname in quote_layouts:
2501                 m = rx.match(document.body[p])
2502                 if m:
2503                     argnr = m.group(1)
2504                     if argnr == "1":
2505                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2506                         endPlain = find_end_of_layout(document.body, beginPlain)
2507                         endInset = find_end_of_inset(document.body, p)
2508                         content = document.body[beginPlain + 1 : endPlain]
2509                         # Adjust range end
2510                         realparend = realparend - len(document.body[p : endInset + 1])
2511                         # Remove arg inset
2512                         del document.body[p : endInset + 1]
2513                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2514                         document.body[realparbeg : realparbeg] = subst
2515             if layoutname in corollary_layouts:
2516                 m = rx.match(document.body[p])
2517                 if m:
2518                     argnr = m.group(1)
2519                     if argnr == "2":
2520                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2521                         endPlain = find_end_of_layout(document.body, beginPlain)
2522                         endInset = find_end_of_inset(document.body, p)
2523                         content = document.body[beginPlain + 1 : endPlain]
2524                         # Adjust range end
2525                         realparend = realparend - len(document.body[p : endInset + 1])
2526                         # Remove arg inset
2527                         del document.body[p : endInset + 1]
2528                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2529                         document.body[realparbeg : realparbeg] = subst
2530         
2531         i = realparend
2532
2533
2534 def revert_beamerargs2(document):
2535     " Reverts beamer arguments to old layout, step 2 "
2536     
2537     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2538     if document.textclass not in beamer_classes:
2539         return
2540
2541     i = 0
2542     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2543     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2544     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2545
2546     while True:
2547         i = find_token(document.body, "\\begin_inset Argument", i)
2548         if i == -1:
2549             return
2550         # Find containing paragraph layout
2551         parent = get_containing_layout(document.body, i)
2552         if parent == False:
2553             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2554             i = i + 1
2555             continue
2556         parbeg = parent[1]
2557         parend = parent[2]
2558         realparbeg = parent[3]
2559         layoutname = parent[0]
2560         realparend = parend
2561         for p in range(parbeg, parend):
2562             if p >= realparend:
2563                 i = realparend
2564                 break
2565             if layoutname in shifted_layouts:
2566                 m = rx.match(document.body[p])
2567                 if m:
2568                     argnr = m.group(1)
2569                     if argnr == "2":
2570                         document.body[p] = "\\begin_inset Argument 1"       
2571             if layoutname in corollary_layouts:
2572                 m = rx.match(document.body[p])
2573                 if m:
2574                     argnr = m.group(1)
2575                     if argnr == "1":
2576                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2577                         endPlain = find_end_of_layout(document.body, beginPlain)
2578                         endInset = find_end_of_inset(document.body, p)
2579                         content = document.body[beginPlain + 1 : endPlain]
2580                         # Adjust range end
2581                         realparend = realparend - len(document.body[p : endInset + 1])
2582                         # Remove arg inset
2583                         del document.body[p : endInset + 1]
2584                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2585                         document.body[realparbeg : realparbeg] = subst
2586             if layoutname == "OverlayArea":
2587                 m = rx.match(document.body[p])
2588                 if m:
2589                     argnr = m.group(1)
2590                     if argnr == "1":
2591                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2592                         endPlain = find_end_of_layout(document.body, beginPlain)
2593                         endInset = find_end_of_inset(document.body, p)
2594                         content = document.body[beginPlain + 1 : endPlain]
2595                         # Adjust range end
2596                         realparend = realparend - len(document.body[p : endInset + 1])
2597                         # Remove arg inset
2598                         del document.body[p : endInset + 1]
2599                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2600                         document.body[realparbeg : realparbeg] = subst
2601             if layoutname == "AgainFrame":
2602                 m = rx.match(document.body[p])
2603                 if m:
2604                     argnr = m.group(1)
2605                     if argnr == "2":
2606                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2607                         endPlain = find_end_of_layout(document.body, beginPlain)
2608                         endInset = find_end_of_inset(document.body, p)
2609                         content = document.body[beginPlain + 1 : endPlain]
2610                         # Adjust range end
2611                         realparend = realparend - len(document.body[p : endInset + 1])
2612                         # Remove arg inset
2613                         del document.body[p : endInset + 1]
2614                         subst = put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
2615                         document.body[realparbeg : realparbeg] = subst
2616         i = realparend
2617
2618
2619 def revert_beamerargs3(document):
2620     " Reverts beamer arguments to old layout, step 3 "
2621     
2622     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2623     if document.textclass not in beamer_classes:
2624         return
2625
2626     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2627     i = 0
2628     while True:
2629         i = find_token(document.body, "\\begin_inset Argument", i)
2630         if i == -1:
2631             return
2632         # Find containing paragraph layout
2633         parent = get_containing_layout(document.body, i)
2634         if parent == False:
2635             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2636             i = i + 1
2637             continue
2638         parbeg = parent[1]
2639         parend = parent[2]
2640         realparbeg = parent[3]
2641         layoutname = parent[0]
2642         realparend = parend
2643         for p in range(parbeg, parend):
2644             if p >= realparend:
2645                 i = realparend
2646                 break
2647             if layoutname == "AgainFrame":
2648                 m = rx.match(document.body[p])
2649                 if m:
2650                     argnr = m.group(1)
2651                     if argnr == "1":
2652                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2653                         endPlain = find_end_of_layout(document.body, beginPlain)
2654                         endInset = find_end_of_inset(document.body, p)
2655                         content = document.body[beginPlain + 1 : endPlain]
2656                         # Adjust range end
2657                         realparend = realparend - len(document.body[p : endInset + 1])
2658                         # Remove arg inset
2659                         del document.body[p : endInset + 1]
2660                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2661                         document.body[realparbeg : realparbeg] = subst
2662         i = realparend
2663
2664
2665 def revert_beamerflex(document):
2666     " Reverts beamer Flex insets "
2667     
2668     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2669     if document.textclass not in beamer_classes:
2670         return
2671
2672     new_flexes = {"Bold" : "\\textbf", "Emphasize" : "\\emph", "Only" : "\\only",
2673                   "Uncover" : "\\uncover", "Visible" : "\\visible",
2674                   "Invisible" : "\\invisible", "Alternative" : "\\alt",
2675                   "Beamer_Note" : "\\note"}
2676     old_flexes = {"Alert" : "\\alert", "Structure" : "\\structure"}
2677     rx = re.compile(r'^\\begin_inset Flex (.+)$')
2678
2679     i = 0
2680     while True:
2681         i = find_token(document.body, "\\begin_inset Flex", i)
2682         if i == -1:
2683             return
2684         m = rx.match(document.body[i])
2685         if m:
2686             flextype = m.group(1)
2687             z = find_end_of_inset(document.body, i)
2688             if z == -1:
2689                 document.warning("Can't find end of Flex " + flextype + " inset.")
2690                 i += 1
2691                 continue
2692             if flextype in new_flexes:
2693                 pre = put_cmd_in_ert(new_flexes[flextype])
2694                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2695                 if arg != -1:
2696                     argend = find_end_of_inset(document.body, arg)
2697                     if argend == -1:
2698                         document.warning("Can't find end of Argument!")
2699                         i += 1
2700                         continue
2701                     # Find containing paragraph layout
2702                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2703                     endPlain = find_end_of_layout(document.body, beginPlain)
2704                     argcontent = document.body[beginPlain + 1 : endPlain]
2705                     # Adjust range end
2706                     z = z - len(document.body[arg : argend + 1])
2707                     # Remove arg inset
2708                     del document.body[arg : argend + 1]
2709                     pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2710                 arg = find_token(document.body, "\\begin_inset Argument 2", i, z)
2711                 if arg != -1:
2712                     argend = find_end_of_inset(document.body, arg)
2713                     if argend == -1:
2714                         document.warning("Can't find end of Argument!")
2715                         i += 1
2716                         continue
2717                     # Find containing paragraph layout
2718                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2719                     endPlain = find_end_of_layout(document.body, beginPlain)
2720                     argcontent = document.body[beginPlain + 1 : endPlain]
2721                     # Adjust range end
2722                     z = z - len(document.body[arg : argend + 1])
2723                     # Remove arg inset
2724                     del document.body[arg : argend + 1]
2725                     if flextype == "Alternative":
2726                         pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
2727                     else:
2728                         pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2729                 pre += put_cmd_in_ert("{")
2730                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2731                 endPlain = find_end_of_layout(document.body, beginPlain)
2732                 # Adjust range end
2733                 z = z - len(document.body[i : beginPlain + 1])
2734                 z += len(pre)
2735                 document.body[i : beginPlain + 1] = pre
2736                 post = put_cmd_in_ert("}")
2737                 document.body[z - 2 : z + 1] = post
2738             elif flextype in old_flexes:
2739                 pre = put_cmd_in_ert(old_flexes[flextype])
2740                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2741                 if arg == -1:
2742                     i += 1
2743                     continue
2744                 argend = find_end_of_inset(document.body, arg)
2745                 if argend == -1:
2746                     document.warning("Can't find end of Argument!")
2747                     i += 1
2748                     continue
2749                 # Find containing paragraph layout
2750                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2751                 endPlain = find_end_of_layout(document.body, beginPlain)
2752                 argcontent = document.body[beginPlain + 1 : endPlain]
2753                 # Adjust range end
2754                 z = z - len(document.body[arg : argend + 1])
2755                 # Remove arg inset
2756                 del document.body[arg : argend + 1]
2757                 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2758                 pre += put_cmd_in_ert("{")
2759                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2760                 endPlain = find_end_of_layout(document.body, beginPlain)
2761                 # Adjust range end
2762                 z = z - len(document.body[i : beginPlain + 1])
2763                 z += len(pre)
2764                 document.body[i : beginPlain + 1] = pre
2765                 post = put_cmd_in_ert("}")
2766                 document.body[z - 2 : z + 1] = post
2767         
2768         i += 1
2769
2770
2771 def revert_beamerblocks(document):
2772     " Reverts beamer block arguments to ERT "
2773     
2774     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2775     if document.textclass not in beamer_classes:
2776         return
2777
2778     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2779
2780     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2781     i = 0
2782     while True:
2783         i = find_token(document.body, "\\begin_inset Argument", i)
2784         if i == -1:
2785             return
2786         # Find containing paragraph layout
2787         parent = get_containing_layout(document.body, i)
2788         if parent == False:
2789             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2790             i = i + 1
2791             continue
2792         parbeg = parent[1]
2793         parend = parent[2]
2794         realparbeg = parent[3]
2795         layoutname = parent[0]
2796         realparend = parend
2797         for p in range(parbeg, parend):
2798             if p >= realparend:
2799                 i = realparend
2800                 break
2801             if layoutname in blocks:
2802                 m = rx.match(document.body[p])
2803                 if m:
2804                     argnr = m.group(1)
2805                     if argnr == "1":
2806                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2807                         endPlain = find_end_of_layout(document.body, beginPlain)
2808                         endInset = find_end_of_inset(document.body, p)
2809                         content = document.body[beginPlain + 1 : endPlain]
2810                         # Adjust range end
2811                         realparend = realparend - len(document.body[p : endInset + 1])
2812                         # Remove arg inset
2813                         del document.body[p : endInset + 1]
2814                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2815                         document.body[realparbeg : realparbeg] = subst
2816                     elif argnr == "2":
2817                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2818                         endPlain = find_end_of_layout(document.body, beginPlain)
2819                         endInset = find_end_of_inset(document.body, p)
2820                         content = document.body[beginPlain + 1 : endPlain]
2821                         # Adjust range end
2822                         realparend = realparend - len(document.body[p : endInset + 1])
2823                         # Remove arg inset
2824                         del document.body[p : endInset + 1]
2825                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2826                         document.body[realparbeg : realparbeg] = subst
2827         i = realparend
2828
2829
2830
2831 def convert_beamerblocks(document):
2832     " Converts beamer block ERT args to native InsetArgs "
2833     
2834     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2835     if document.textclass not in beamer_classes:
2836         return
2837    
2838     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2839     for lay in blocks:
2840         i = 0
2841         while True:
2842             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2843             if i == -1:
2844                 break
2845             parent = get_containing_layout(document.body, i)
2846             if parent == False or parent[1] != i:
2847                 document.warning("Wrong parent layout!")
2848                 i += 1
2849                 continue
2850             j = parent[2]
2851             parbeg = parent[3]
2852             if i != -1:
2853                 if document.body[parbeg] == "\\begin_inset ERT":
2854                     ertcont = parbeg + 5
2855                     while True:
2856                         if document.body[ertcont].startswith("<"):
2857                             # This is an overlay specification
2858                             # strip off the <
2859                             document.body[ertcont] = document.body[ertcont][1:]
2860                             if document.body[ertcont].endswith(">"):
2861                                 # strip off the >
2862                                 document.body[ertcont] = document.body[ertcont][:-1]
2863                                 # Convert to ArgInset
2864                                 document.body[parbeg] = "\\begin_inset Argument 1"
2865                             elif document.body[ertcont].endswith("}"):
2866                                 # divide the args
2867                                 tok = document.body[ertcont].find('>{')
2868                                 if tok != -1:
2869                                     document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2870                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2871                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
2872                                                                             document.body[ertcont][tok + 2:-1]]
2873                             # Convert to ArgInset
2874                             document.body[parbeg] = "\\begin_inset Argument 1"
2875                         elif document.body[ertcont].startswith("{"):
2876                             # This is the block title
2877                             if document.body[ertcont].endswith("}"):
2878                                 # strip off the braces
2879                                 document.body[ertcont] = document.body[ertcont][1:-1]
2880                                 # Convert to ArgInset
2881                                 document.body[parbeg] = "\\begin_inset Argument 2"
2882                             elif count_pars_in_inset(document.body, ertcont) > 1:
2883                                 # Multipar ERT. Skip this.
2884                                 break
2885                             else:
2886                                 convert_TeX_brace_to_Argument(document, i, 2, 2, False, True)
2887                         else:
2888                             break
2889                         j = find_end_of_layout(document.body, i)
2890                         if j == -1:
2891                             document.warning("end of layout not found!")
2892                         k = find_token(document.body, "\\begin_inset Argument", i, j)
2893                         if k == -1:
2894                             document.warning("InsetArgument not found!")
2895                             break
2896                         l = find_end_of_inset(document.body, k)
2897                         m = find_token(document.body, "\\begin_inset ERT", l, j)
2898                         if m == -1:
2899                             break
2900                         ertcont = m + 5
2901                         parbeg = m
2902             i = j
2903
2904
2905 def convert_overprint(document):
2906     " Convert old beamer overprint layouts to ERT "
2907     
2908     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2909     if document.textclass not in beamer_classes:
2910         return
2911
2912     i = 0
2913     while True:
2914         i = find_token(document.body, "\\begin_layout Overprint", i)
2915         if i == -1:
2916             return
2917         # Find end of sequence
2918         j = find_end_of_sequence(document.body, i)
2919         if j == -1:
2920             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
2921             i = i + 1
2922             continue
2923         endseq = j
2924         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
2925         esubst = list()
2926         if document.body[j] == "\\end_deeper":
2927             esubst = ["", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2928         else:
2929             esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2930         endseq = endseq + len(esubst) - len(document.body[j : j])
2931         document.body[j : j] = esubst
2932         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2933         if argbeg != -1:
2934             argend = find_end_of_layout(document.body, argbeg)
2935             if argend == -1:
2936                 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
2937                 i = i + 1
2938                 continue
2939             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2940             endPlain = find_end_of_layout(document.body, beginPlain)
2941             content = document.body[beginPlain + 1 : endPlain]
2942             # Adjust range end
2943             endseq = endseq - len(document.body[argbeg : argend + 1])
2944             # Remove arg inset
2945             del document.body[argbeg : argend + 1]
2946             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2947             
2948         endseq = endseq - len(document.body[i : i])
2949         document.body[i : i] = subst + ["\\end_layout"]
2950         endseq += len(subst)
2951         
2952         for p in range(i, endseq):
2953             if document.body[p] == "\\begin_layout Overprint":
2954                 document.body[p] = "\\begin_layout Standard"
2955
2956         i = endseq
2957
2958
2959 def revert_overprint(document):
2960     " Revert old beamer overprint layouts to ERT "
2961     
2962     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2963     if document.textclass not in beamer_classes:
2964         return
2965
2966     i = 0
2967     while True:
2968         i = find_token(document.body, "\\begin_layout Overprint", i)
2969         if i == -1:
2970             return
2971         # Find end of sequence
2972         j = find_end_of_sequence(document.body, i)
2973         if j == -1:
2974             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
2975             i = i + 1
2976             continue
2977         endseq = j
2978         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
2979         esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}")
2980         endseq = endseq + len(esubst) - len(document.body[j : j])
2981         if document.body[j] == "\\end_deeper":
2982             document.body[j : j] = ["\\end_deeper", ""] + esubst
2983         else:
2984             document.body[j : j] = esubst
2985         r = i
2986         while r < j:
2987             if document.body[r] == "\\begin_deeper":
2988                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
2989                 if s != -1:
2990                     document.body[r] = ""
2991                     document.body[s] = ""
2992                     r = s
2993                     continue
2994             r = r + 1
2995         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2996         if argbeg != -1:
2997             argend = find_end_of_inset(document.body, argbeg)
2998             if argend == -1:
2999                 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3000                 i = i + 1
3001                 continue
3002             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3003             endPlain = find_end_of_layout(document.body, beginPlain)
3004             content = document.body[beginPlain + 1 : endPlain]
3005             # Adjust range end
3006             endseq = endseq - len(document.body[argbeg : argend])
3007             # Remove arg inset
3008             del document.body[argbeg : argend + 1]
3009             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3010             
3011         endseq = endseq - len(document.body[i : i])
3012         document.body[i : i] = subst + ["\\end_layout"]
3013         endseq += len(subst)
3014      
3015         p = i
3016         while True:
3017             if p >= endseq:
3018                 break
3019             if document.body[p] == "\\begin_layout Overprint":
3020                 q = find_end_of_layout(document.body, p)
3021                 if q == -1:
3022                     document.warning("Malformed LyX document. Cannot find end of Overprint layout!")
3023                     p += 1
3024                     continue
3025                 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\onslide")
3026                 argbeg = find_token(document.body, "\\begin_inset Argument item:1", p, q)
3027                 if argbeg != -1:
3028                     argend = find_end_of_inset(document.body, argbeg)
3029                     if argend == -1:
3030                         document.warning("Malformed LyX document. Cannot find end of Overprint item argument!")
3031                         p += 1
3032                         continue
3033                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3034                     endPlain = find_end_of_layout(document.body, beginPlain)
3035                     content = document.body[beginPlain + 1 : endPlain]
3036                     # Adjust range end
3037                     endseq = endseq - len(document.body[argbeg : argend + 1])
3038                     # Remove arg inset
3039                     del document.body[argbeg : argend + 1]
3040                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3041                 endseq = endseq - len(document.body[p : p + 1]) + len(subst)
3042                 document.body[p : p + 1] = subst
3043             p = p + 1
3044
3045         i = endseq
3046
3047
3048 def revert_frametitle(document):
3049     " Reverts beamer frametitle layout to ERT "
3050     
3051     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3052     if document.textclass not in beamer_classes:
3053         return
3054
3055     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3056     i = 0
3057     while True:
3058         i = find_token(document.body, "\\begin_layout FrameTitle", i)
3059         if i == -1:
3060             return
3061         j = find_end_of_layout(document.body, i)
3062         if j == -1:
3063             document.warning("Malformed LyX document: Can't find end of FrameTitle layout")
3064             i = i + 1
3065             continue
3066         endlay = j
3067         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
3068         endlay += len(put_cmd_in_ert("}"))
3069         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\frametitle")
3070         for p in range(i, j):
3071             if p >= endlay:
3072                 break
3073             m = rx.match(document.body[p])
3074             if m:
3075                 argnr = m.group(1)
3076                 if argnr == "1":
3077                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3078                     endPlain = find_end_of_layout(document.body, beginPlain)
3079                     endInset = find_end_of_inset(document.body, p)
3080                     content = document.body[beginPlain + 1 : endPlain]
3081                     # Adjust range end
3082                     endlay = endlay - len(document.body[p : endInset + 1])
3083                     # Remove arg inset
3084                     del document.body[p : endInset + 1]
3085                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3086                 elif argnr == "2":
3087                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3088                     endPlain = find_end_of_layout(document.body, beginPlain)
3089                     endInset = find_end_of_inset(document.body, p)
3090                     content = document.body[beginPlain + 1 : endPlain]
3091                     # Adjust range end
3092                     endlay = endlay - len(document.body[p : endInset + 1])
3093                     # Remove arg inset
3094                     del document.body[p : endInset + 1]
3095                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3096                     
3097         subst += put_cmd_in_ert("{")
3098         document.body[i : i + 1] = subst
3099         i = endlay
3100
3101
3102 def convert_epigraph(document):
3103     " Converts memoir epigraph to new syntax "
3104     
3105     if document.textclass != "memoir":
3106         return
3107
3108     i = 0
3109     while True:
3110         i = find_token(document.body, "\\begin_layout Epigraph", i)
3111         if i == -1:
3112             return
3113         j = find_end_of_layout(document.body, i)
3114         if j == -1:
3115             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3116             i = i + 1
3117             continue
3118         endlay = j
3119         subst = list()
3120         ert = find_token(document.body, "\\begin_inset ERT", i, j)
3121         if ert != -1:
3122             endInset = find_end_of_inset(document.body, ert)
3123             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", ert)
3124             endPlain = find_end_of_layout(document.body, beginPlain)
3125             ertcont = beginPlain + 2
3126             if document.body[ertcont] == "}{":
3127                 # strip off the <
3128                 # Convert to ArgInset
3129                 endlay = endlay - 2 * len(document.body[j])
3130                 begsubst = ['\\begin_inset Argument post:1', 'status collapsed', '',
3131                             '\\begin_layout Plain Layout']
3132                 endsubst = ['\\end_layout', '', '\\end_inset', '', document.body[j]]
3133                 document.body[j : j + 1] = endsubst
3134                 document.body[endInset + 1 : endInset + 1] = begsubst
3135                 # Adjust range end
3136                 endlay += len(begsubst) + len(endsubst)
3137                 endlay = endlay - len(document.body[ert : endInset + 1])
3138                 del document.body[ert : endInset + 1]
3139                     
3140         i = endlay
3141
3142
3143 def revert_epigraph(document):
3144     " Reverts memoir epigraph argument to ERT "
3145     
3146     if document.textclass != "memoir":
3147         return
3148
3149     i = 0
3150     while True:
3151         i = find_token(document.body, "\\begin_layout Epigraph", i)
3152         if i == -1:
3153             return
3154         j = find_end_of_layout(document.body, i)
3155         if j == -1:
3156             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3157             i = i + 1
3158             continue
3159         endlay = j
3160         subst = list()
3161         p = find_token(document.body, "\\begin_layout Argument post:1", i, j)
3162         if p != -1:
3163             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3164             endPlain = find_end_of_layout(document.body, beginPlain)
3165             endInset = find_end_of_inset(document.body, p)
3166             content = document.body[beginPlain + 1 : endPlain]
3167             # Adjust range end
3168             endlay = endlay - len(document.body[p : endInset + 1])
3169             # Remove arg inset
3170             del document.body[p : endInset + 1]
3171             subst += put_cmd_in_ert("}{") + content
3172         else:
3173             subst += put_cmd_in_ert("}{")
3174                     
3175         document.body[j : j] = subst + document.body[j : j]
3176         i = endlay
3177
3178
3179 def convert_captioninsets(document):
3180     " Converts caption insets to new syntax "
3181     
3182     i = 0
3183     while True:
3184       i = find_token(document.body, "\\begin_inset Caption", i)
3185       if i == -1:
3186           return
3187       document.body[i] = "\\begin_inset Caption Standard"
3188       i = i + 1
3189
3190
3191 def revert_captioninsets(document):
3192     " Reverts caption insets to old syntax "
3193     
3194     i = 0
3195     while True:
3196       i = find_token(document.body, "\\begin_inset Caption Standard", i)
3197       if i == -1:
3198           return
3199       document.body[i] = "\\begin_inset Caption"
3200       i = i + 1
3201
3202
3203 def convert_captionlayouts(document):
3204     " Convert caption layouts to caption insets. "
3205
3206     caption_dict = {
3207         "Captionabove":  "Above",
3208         "Captionbelow":  "Below",
3209         "FigCaption"  :  "FigCaption",
3210         "Table_Caption" :  "Table",
3211         "CenteredCaption" : "Centered",
3212         "Bicaption" : "Bicaption",
3213         }
3214
3215     i = 0
3216     while True:
3217         i = find_token(document.body, "\\begin_layout", i)
3218         if i == -1:
3219             return
3220         val = get_value(document.body, "\\begin_layout", i)
3221         if val in caption_dict.keys():
3222             j = find_end_of_layout(document.body, i)
3223             if j == -1:
3224                 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3225                 return
3226
3227             document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""]
3228             document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout,
3229                                     "\\begin_inset Caption %s" % caption_dict[val], "",
3230                                     "\\begin_layout %s" % document.default_layout]
3231         i = i + 1
3232
3233
3234 def revert_captionlayouts(document):
3235     " Revert caption insets to caption layouts. "
3236     
3237     caption_dict = {
3238         "Above" : "Captionabove",
3239         "Below" : "Captionbelow",
3240         "FigCaption"  :  "FigCaption",
3241         "Table" : "Table_Caption",
3242         "Centered" : "CenteredCaption",
3243         "Bicaption" : "Bicaption",
3244         }
3245     
3246     i = 0
3247     rx = re.compile(r'^\\begin_inset Caption (\S+)$')
3248     while True:
3249         i = find_token(document.body, "\\begin_inset Caption", i)
3250         if i == -1:
3251             return
3252
3253         m = rx.match(document.body[i])
3254         val = ""
3255         if m:
3256             val = m.group(1)
3257         if val not in caption_dict.keys():
3258             i = i + 1
3259             continue
3260         
3261         # We either need to delete the previous \begin_layout line, or we
3262         # need to end the previous layout if this inset is not in the first
3263         # position of the paragraph.
3264         layout_before = find_token_backwards(document.body, "\\begin_layout", i)
3265         if layout_before == -1:
3266             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3267             return
3268         layout_line = document.body[layout_before]
3269         del_layout_before = True
3270         l = layout_before + 1
3271         while l < i:
3272             if document.body[l] != "":
3273                 del_layout_before = False
3274                 break
3275             l = l + 1
3276         if del_layout_before:
3277             del document.body[layout_before:i]
3278             i = layout_before
3279         else:
3280             document.body[i:i] = ["\\end_layout", ""]
3281             i = i + 2
3282
3283         # Find start of layout in the inset and end of inset
3284         j = find_token(document.body, "\\begin_layout", i)
3285         if j == -1:
3286             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3287             return
3288         k = find_end_of_inset(document.body, i)
3289         if k == -1:
3290             document.warning("Malformed LyX document: Missing `\\end_inset'.")
3291             return
3292
3293         # We either need to delete the following \end_layout line, or we need
3294         # to restart the old layout if this inset is not at the paragraph end.
3295         layout_after = find_token(document.body, "\\end_layout", k)
3296         if layout_after == -1:
3297             document.warning("Malformed LyX document: Missing `\\end_layout'.")
3298             return
3299         del_layout_after = True
3300         l = k + 1
3301         while l < layout_after:
3302             if document.body[l] != "":
3303                 del_layout_after = False
3304                 break
3305             l = l + 1
3306         if del_layout_after:
3307             del document.body[k+1:layout_after+1]
3308         else:
3309             document.body[k+1:k+1] = [layout_line, ""]
3310
3311         # delete \begin_layout and \end_inset and replace \begin_inset with
3312         # "\begin_layout XXX". This works because we can only have one
3313         # paragraph in the caption inset: The old \end_layout will be recycled.
3314         del document.body[k]
3315         if document.body[k] == "":
3316             del document.body[k]
3317         del document.body[j]
3318         if document.body[j] == "":
3319             del document.body[j]
3320         document.body[i] = "\\begin_layout %s" % caption_dict[val]
3321         if document.body[i+1] == "":
3322             del document.body[i+1]
3323         i = i + 1
3324
3325
3326 def revert_fragileframe(document):
3327     " Reverts beamer FragileFrame layout to ERT "
3328     
3329     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3330     if document.textclass not in beamer_classes:
3331         return
3332
3333     i = 0
3334     while True:
3335         i = find_token(document.body, "\\begin_layout FragileFrame", i)
3336         if i == -1:
3337             return
3338         # Find end of sequence
3339         j = find_end_of_sequence(document.body, i)
3340         if j == -1:
3341             document.warning("Malformed LyX document. Cannot find end of FragileFrame sequence!")
3342             i = i + 1
3343             continue
3344         endseq = j
3345         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{frame}")
3346         esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}")
3347         endseq = endseq + len(esubst) - len(document.body[j : j])
3348         if document.body[j] == "\\end_deeper":
3349             document.body[j : j] = ["\\end_deeper", ""] + esubst
3350         else:
3351             document.body[j : j] = esubst
3352         for q in range(i, j):
3353             if document.body[q] == "\\begin_layout FragileFrame":
3354                 document.body[q] = "\\begin_layout %s" % document.default_layout
3355         r = i
3356         while r < j:
3357             if document.body[r] == "\\begin_deeper":
3358                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3359                 if s != -1:
3360                     document.body[r] = ""
3361                     document.body[s] = ""
3362                     r = s
3363                     continue
3364             r = r + 1
3365         for p in range(1, 5):
3366             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, j)
3367             if arg != -1:
3368                 if p == 1:
3369                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3370                     endPlain = find_end_of_layout(document.body, beginPlain)
3371                     endInset = find_end_of_inset(document.body, arg)
3372                     content = document.body[beginPlain + 1 : endPlain]
3373                     # Adjust range end
3374                     j = j - len(document.body[arg : endInset + 1])
3375                     # Remove arg inset
3376                     del document.body[arg : endInset + 1]
3377                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3378                 elif p == 2:
3379                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3380                     endPlain = find_end_of_layout(document.body, beginPlain)
3381                     endInset = find_end_of_inset(document.body, arg)
3382                     content = document.body[beginPlain + 1 : endPlain]
3383                     # Adjust range end
3384                     j = j - len(document.body[arg : endInset + 1])
3385                     # Remove arg inset
3386                     del document.body[arg : endInset + 1]
3387                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3388                 elif p == 3:
3389                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3390                     endPlain = find_end_of_layout(document.body, beginPlain)
3391                     endInset = find_end_of_inset(document.body, arg)
3392                     content = document.body[beginPlain + 1 : endPlain]
3393                     # Adjust range end
3394                     j = j - len(document.body[arg : endInset + 1])
3395                     # Remove arg inset
3396                     del document.body[arg : endInset + 1]
3397                     subst += put_cmd_in_ert("[fragile,") + content + put_cmd_in_ert("]")
3398                 elif p == 4:
3399                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3400                     endPlain = find_end_of_layout(document.body, beginPlain)
3401                     endInset = find_end_of_inset(document.body, arg)
3402                     content = document.body[beginPlain + 1 : endPlain]
3403                     # Adjust range end
3404                     j = j - len(document.body[arg : endInset + 1])
3405                     # Remove arg inset
3406                     del document.body[arg : endInset + 1]
3407                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3408             elif p == 3:
3409                 subst += put_cmd_in_ert("[fragile]")
3410                     
3411         document.body[i : i + 1] = subst
3412         i = j
3413
3414
3415 def revert_newframes(document):
3416     " Reverts beamer Frame and PlainFrame layouts to old forms "
3417     
3418     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3419     if document.textclass not in beamer_classes:
3420         return
3421
3422     frame_dict = {
3423         "Frame" : "BeginFrame",
3424         "PlainFrame" : "BeginPlainFrame",
3425         }
3426
3427     rx = re.compile(r'^\\begin_layout (\S+)$')
3428     i = 0
3429     while True:
3430         i = find_token(document.body, "\\begin_layout", i)
3431         if i == -1:
3432             return
3433
3434         m = rx.match(document.body[i])
3435         val = ""
3436         if m:
3437             val = m.group(1)
3438         if val not in frame_dict.keys():
3439             i = i + 1
3440             continue
3441         # Find end of sequence
3442         j = find_end_of_sequence(document.body, i)
3443         if j == -1:
3444             document.warning("Malformed LyX document. Cannot find end of Frame sequence!")
3445             i = i + 1
3446             continue
3447         endseq = j
3448         subst = ["\\begin_layout %s" % frame_dict[val]]
3449         esubst = ["\\end_layout", "", "\\begin_layout EndFrame", "", "\\end_layout"]
3450         endseq = endseq + len(esubst) - len(document.body[j : j])
3451         if document.body[j] == "\\end_deeper":
3452             document.body[j : j] = ["\\end_deeper", ""] + esubst
3453         else:
3454             document.body[j : j] = esubst
3455         for q in range(i, j):
3456             if document.body[q] == "\\begin_layout %s" % val:
3457                 document.body[q] = "\\begin_layout %s" % document.default_layout
3458         r = i
3459         while r < j:
3460             if document.body[r] == "\\begin_deeper":
3461                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3462                 if s != -1:
3463                     document.body[r] = ""
3464                     document.body[s] = ""
3465                     r = s
3466                     continue
3467             r = r + 1
3468         l = find_end_of_layout(document.body, i)
3469         for p in range(1, 5):
3470             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, l)
3471             if arg != -1:
3472                 if p == 1:
3473                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3474                     endPlain = find_end_of_layout(document.body, beginPlain)
3475                     endInset = find_end_of_inset(document.body, arg)
3476                     content = document.body[beginPlain + 1 : endPlain]
3477                     # Adjust range end
3478                     l = l - len(document.body[arg : endInset + 1])
3479                     # Remove arg inset
3480                     del document.body[arg : endInset + 1]
3481                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3482                 elif p == 2:
3483                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3484                     endPlain = find_end_of_layout(document.body, beginPlain)
3485                     endInset = find_end_of_inset(document.body, arg)
3486                     content = document.body[beginPlain + 1 : endPlain]
3487                     # Adjust range end
3488                     l = l - len(document.body[arg : endInset + 1])
3489                     # Remove arg inset
3490                     del document.body[arg : endInset + 1]
3491                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3492                 elif p == 3:
3493                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3494                     endPlain = find_end_of_layout(document.body, beginPlain)
3495                     endInset = find_end_of_inset(document.body, arg)
3496                     content = document.body[beginPlain + 1 : endPlain]
3497                     # Adjust range end
3498                     l = l - len(document.body[arg : endInset + 1])
3499                     # Remove arg inset
3500                     del document.body[arg : endInset + 1]
3501                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3502                 elif p == 4:
3503                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3504                     endPlain = find_end_of_layout(document.body, beginPlain)
3505                     endInset = find_end_of_inset(document.body, arg)
3506                     content = document.body[beginPlain + 1 : endPlain]
3507                     # Adjust range end
3508                     l = l - len(document.body[arg : endInset + 1])
3509                     # Remove arg inset
3510                     del document.body[arg : endInset + 1]
3511                     subst += content
3512                     
3513         document.body[i : i + 1] = subst
3514         i = j
3515
3516 # known encodings that do not change their names (same LyX and LaTeX names)
3517 known_enc_tuple = ("auto", "default", "ansinew", "applemac", "armscii8", "ascii",
3518     "cp437", "cp437de", "cp850", "cp852", "cp855", "cp858", "cp862", "cp865", "cp866",
3519     "cp1250", "cp1251", "cp1252", "cp1255", "cp1256", "cp1257", "koi8-r", "koi8-u",
3520     "pt154", "pt254", "tis620-0", "utf8", "utf8x", "utf8-plain")
3521
3522 def convert_encodings(document):
3523     "Use the LyX names of the encodings instead of the LaTeX names."
3524     LaTeX2LyX_enc_dict = {
3525         "8859-6":     "iso8859-6",
3526         "8859-8":     "iso8859-8",
3527         "Bg5":        "big5",
3528         "euc":        "euc-jp-platex",
3529         "EUC-JP":     "euc-jp",
3530         "EUC-TW":     "euc-tw",
3531         "GB":         "euc-cn",
3532         "GBK":        "gbk",
3533         "iso88595":   "iso8859-5",
3534         "iso-8859-7": "iso8859-7",
3535         "JIS":        "jis",
3536         "jis":        "jis-platex",
3537         "KS":         "euc-kr",
3538         "l7xenc":     "iso8859-13",
3539         "latin1":     "iso8859-1",
3540         "latin2":     "iso8859-2",
3541         "latin3":     "iso8859-3",
3542         "latin4":     "iso8859-4",
3543         "latin5":     "iso8859-9",
3544         "latin9":     "iso8859-15",
3545         "latin10":    "iso8859-16",
3546         "SJIS":       "shift-jis",
3547         "sjis":       "shift-jis-platex",
3548         "UTF8":       "utf8-cjk"
3549     }
3550     i = find_token(document.header, "\\inputencoding" , 0)
3551     if i == -1:
3552         return
3553     val = get_value(document.header, "\\inputencoding", i)
3554     if val in LaTeX2LyX_enc_dict.keys():
3555         document.header[i] = "\\inputencoding %s" % LaTeX2LyX_enc_dict[val]
3556     elif val not in known_enc_tuple:
3557         document.warning("Ignoring unknown input encoding: `%s'" % val)
3558
3559
3560 def revert_encodings(document):
3561     """Revert to using the LaTeX names of the encodings instead of the LyX names.
3562     Also revert utf8-platex to sjis, the language default when using Japanese.
3563     """
3564     LyX2LaTeX_enc_dict = {
3565         "big5":             "Bg5",
3566         "euc-cn":           "GB",
3567         "euc-kr":           "KS",
3568         "euc-jp":           "EUC-JP",
3569         "euc-jp-platex":    "euc",
3570         "euc-tw":           "EUC-TW",
3571         "gbk":              "GBK",
3572         "iso8859-1":        "latin1",
3573         "iso8859-2":        "latin2",
3574         "iso8859-3":        "latin3",
3575         "iso8859-4":        "latin4",
3576         "iso8859-5":        "iso88595",
3577         "iso8859-6":        "8859-6",
3578         "iso8859-7":        "iso-8859-7",
3579         "iso8859-8":        "8859-8",
3580         "iso8859-9":        "latin5",
3581         "iso8859-13":       "l7xenc",
3582         "iso8859-15":       "latin9",
3583         "iso8859-16":       "latin10",
3584         "jis":              "JIS",
3585         "jis-platex":       "jis",
3586         "shift-jis":        "SJIS",
3587         "shift-jis-platex": "sjis",
3588         "utf8-cjk":         "UTF8",
3589         "utf8-platex":      "sjis"
3590     }
3591     i = find_token(document.header, "\\inputencoding" , 0)
3592     if i == -1:
3593         return
3594     val = get_value(document.header, "\\inputencoding", i)
3595     if val in LyX2LaTeX_enc_dict.keys():
3596         document.header[i] = "\\inputencoding %s" % LyX2LaTeX_enc_dict[val]
3597     elif val not in known_enc_tuple:
3598         document.warning("Ignoring unknown input encoding: `%s'" % val)
3599
3600
3601 def revert_IEEEtran_3(document):
3602   '''
3603   Reverts Flex Insets to TeX-code
3604   '''
3605   if document.textclass == "IEEEtran":
3606     h = 0
3607     i = 0
3608     j = 0
3609     while True:
3610       if h != -1:
3611         h = find_token(document.body, "\\begin_inset Flex Author Mark", h)
3612       if h != -1:
3613         endh = find_end_of_inset(document.body, h)
3614         document.body[endh - 2 : endh + 1] = put_cmd_in_ert("}")
3615         document.body[h : h + 4] = put_cmd_in_ert("\\IEEEauthorrefmark{")
3616         h = h + 5
3617       if i != -1:
3618         i = find_token(document.body, "\\begin_inset Flex Author Name", i)
3619       if i != -1:
3620         endi = find_end_of_inset(document.body, i)
3621         document.body[endi - 2 : endi + 1] = put_cmd_in_ert("}")
3622         document.body[i : i + 4] = put_cmd_in_ert("\\IEEEauthorblockN{")
3623         i = i + 5
3624       if j != -1:
3625         j = find_token(document.body, "\\begin_inset Flex Author Affiliation", j)
3626       if j != -1:
3627         endj = find_end_of_inset(document.body, j)
3628         document.body[endj - 2 : endj + 1] = put_cmd_in_ert("}")
3629         document.body[j : j + 4] = put_cmd_in_ert("\\IEEEauthorblockA{")
3630         j = j + 5
3631       if i == -1 and j == -1 and h == -1:
3632         return
3633
3634
3635 def revert_kurier_fonts(document):
3636   " Revert kurier font definition to LaTeX "
3637   
3638   i = find_token(document.header, "\\font_math", 0)
3639   if i != -1:
3640     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3641       val = get_value(document.header, "\\font_math", i)
3642       if val == "kurier-math":
3643         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
3644           "\\usepackage[math]{kurier}\n" \
3645           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
3646         document.header[i] = "\\font_math auto"
3647   
3648   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3649     kurier_fonts = ["kurier", "kurierc", "kurierl", "kurierlc"]
3650     k = find_token(document.header, "\\font_sans kurier", 0)
3651     if k != -1:
3652       sf = get_value(document.header, "\\font_sans", k)
3653       if sf in kurier_fonts:
3654         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
3655         document.header[k] = "\\font_sans default"
3656
3657 def revert_iwona_fonts(document):
3658   " Revert iwona font definition to LaTeX "
3659   
3660   i = find_token(document.header, "\\font_math", 0)
3661   if i != -1:
3662     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3663       val = get_value(document.header, "\\font_math", i)
3664       if val == "iwona-math":
3665         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
3666           "\\usepackage[math]{iwona}\n" \
3667           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
3668         document.header[i] = "\\font_math auto"
3669   
3670   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3671     iwona_fonts = ["iwona", "iwonac", "iwonal", "iwonalc"]
3672     k = find_token(document.header, "\\font_sans iwona", 0)
3673     if k != -1:
3674       sf = get_value(document.header, "\\font_sans", k)
3675       if sf in iwona_fonts:
3676         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
3677         document.header[k] = "\\font_sans default"
3678
3679
3680 def revert_new_libertines(document):
3681     " Revert new libertine font definition to LaTeX "
3682   
3683     if find_token(document.header, "\\use_non_tex_fonts true", 0) != -1:
3684         return
3685
3686     i = find_token(document.header, "\\font_typewriter libertine-mono", 0)
3687     if i != -1:
3688         preamble = "\\usepackage"
3689         sc = find_token(document.header, "\\font_tt_scale", 0)
3690         if sc != -1:
3691             scval = get_value(document.header, "\\font_tt_scale", sc)
3692             if scval != "100":
3693                 preamble += "[scale=%f]" % (float(scval) / 100)
3694                 document.header[sc] = "\\font_tt_scale 100"
3695         preamble += "{libertineMono-type1}"
3696         add_to_preamble(document, [preamble])
3697         document.header[i] = "\\font_typewriter default"
3698    
3699     k = find_token(document.header, "\\font_sans biolinum", 0)
3700     if k != -1:
3701         preamble = "\\usepackage"
3702         options = ""
3703         j = find_token(document.header, "\\font_osf true", 0)
3704         if j != -1:
3705             options += "osf"
3706         else:
3707             options += "lining"
3708         sc = find_token(document.header, "\\font_sf_scale", 0)
3709         if sc != -1:
3710             scval = get_value(document.header, "\\font_sf_scale", sc)
3711             if scval != "100":
3712                 options += ",scale=%f" % (float(scval) / 100)
3713                 document.header[sc] = "\\font_sf_scale 100"
3714         if options != "":
3715             preamble += "[" + options +"]"
3716         preamble += "{biolinum-type1}"
3717         add_to_preamble(document, [preamble])
3718         document.header[k] = "\\font_sans default"
3719
3720
3721 def convert_lyxframes(document):
3722     " Converts old beamer frames to new style "
3723     
3724     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3725     if document.textclass not in beamer_classes:
3726         return
3727    
3728     framebeg = ["BeginFrame", "BeginPlainFrame"]
3729     frameend = ["EndFrame", "BeginFrame", "BeginPlainFrame", "AgainFrame", "Section", "Section*",
3730                 "Subsection", "Subsection*", "Subsubsection", "Subsubsection*"]
3731     for lay in framebeg:
3732         i = 0
3733         while True:
3734             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
3735             if i == -1:
3736                 break
3737             parent = get_containing_layout(document.body, i)
3738             if parent == False or parent[1] != i:
3739                 document.warning("Wrong parent layout!")
3740                 i += 1
3741                 continue
3742             frametype = parent[0]
3743             j = parent[2]
3744             parbeg = parent[3]
3745             if i != -1:
3746                 # Step I: Convert ERT arguments
3747                 # FIXME: This currently only works if the arguments are in one single ERT
3748                 ertend = i
3749                 if document.body[parbeg] == "\\begin_inset ERT":
3750                     ertend = find_end_of_inset(document.body, parbeg)
3751                     if ertend == -1:
3752                         document.warning("Malformed LyX document: missing ERT \\end_inset")
3753                         continue
3754                     ertcont = parbeg + 5
3755                     if document.body[ertcont].startswith("[<"):
3756                         # This is a default overlay specification
3757                         # strip off the [<
3758                         document.body[ertcont] = document.body[ertcont][2:]
3759                         if document.body[ertcont].endswith(">]"):
3760                             # strip off the >]
3761                             document.body[ertcont] = document.body[ertcont][:-2]
3762                         elif document.body[ertcont].endswith("]"):
3763                             # divide the args
3764                             tok = document.body[ertcont].find('>][')
3765                             if tok != -1:
3766                                 subst = [document.body[ertcont][:tok],
3767                                          '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
3768                                          'status collapsed', '', '\\begin_layout Plain Layout',
3769                                          document.body[ertcont][tok + 3:-1]]
3770                                 document.body[ertcont : ertcont + 1] = subst
3771                                 ertend += 11
3772                         # Convert to ArgInset
3773                         document.body[parbeg] = "\\begin_inset Argument 2"
3774                     elif document.body[ertcont].startswith("<"):
3775                         # This is an overlay specification
3776                         # strip off the <
3777                         document.body[ertcont] = document.body[ertcont][1:]
3778                         if document.body[ertcont].endswith(">"):
3779                             # strip off the >
3780                             document.body[ertcont] = document.body[ertcont][:-1]
3781                             # Convert to ArgInset
3782                             document.body[parbeg] = "\\begin_inset Argument 1"
3783                         elif document.body[ertcont].endswith(">]"):
3784                             # divide the args
3785                             tok = document.body[ertcont].find('>[<')
3786                             if tok != -1:
3787                                document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
3788                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3789                                                                'status collapsed', '', '\\begin_layout Plain Layout',
3790                                                                document.body[ertcont][tok + 3:-2]]
3791                             # Convert to ArgInset
3792                             document.body[parbeg] = "\\begin_inset Argument 1"
3793                             ertend += 11
3794                         elif document.body[ertcont].endswith("]"):
3795                             # divide the args
3796                             tok = document.body[ertcont].find('>[<')
3797                             if tok != -1:
3798                                # divide the args
3799                                tokk = document.body[ertcont].find('>][')
3800                                if tokk != -1:
3801                                    document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
3802                                                                    '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3803                                                                    'status collapsed', '', '\\begin_layout Plain Layout',
3804                                                                    document.body[ertcont][tok + 3:tokk],
3805                                                                    '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
3806                                                                    'status collapsed', '', '\\begin_layout Plain Layout',
3807                                                                    document.body[ertcont][tokk + 3:-1]]
3808                                    ertend += 22
3809                             else:
3810                                 tokk = document.body[ertcont].find('>[')
3811                                 if tokk != -1:
3812                                     document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
3813                                                                     '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
3814                                                                     'status collapsed', '', '\\begin_layout Plain Layout',
3815                                                                     document.body[ertcont][tokk + 2:-1]]
3816                                     ertend += 11
3817                             # Convert to ArgInset
3818                             document.body[parbeg] = "\\begin_inset Argument 1"
3819                     elif document.body[ertcont].startswith("["):
3820                         # This is an ERT option
3821                         # strip off the [
3822                         document.body[ertcont] = document.body[ertcont][1:]
3823                         if document.body[ertcont].endswith("]"):
3824                             # strip off the ]
3825                             document.body[ertcont] = document.body[ertcont][:-1]
3826                             # Convert to ArgInset
3827                             document.body[parbeg] = "\\begin_inset Argument 3"
3828                 # End of argument conversion
3829                 # Step II: Now rename the layout and convert the title to an argument
3830                 j = find_end_of_layout(document.body, i)
3831                 document.body[j : j + 1] = ['\\end_layout', '', '\\end_inset', '', '\\end_layout']
3832                 if lay == "BeginFrame":
3833                     document.body[i] = "\\begin_layout Frame"
3834                 else:
3835                     document.body[i] = "\\begin_layout PlainFrame"
3836                 document.body[ertend + 1 : ertend + 1] = ['\\begin_inset Argument 4',
3837                                                 'status open', '', '\\begin_layout Plain Layout']
3838                 # Step III: find real frame end
3839                 j = j + 8
3840                 jj = j
3841                 while True:
3842                     fend = find_token(document.body, "\\begin_layout", jj)
3843                     if fend == -1:
3844                         document.warning("Malformed LyX document: No real frame end!")
3845                         return
3846                     val = get_value(document.body, "\\begin_layout", fend)
3847                     if val not in frameend:
3848                         jj = fend + 1
3849                         continue
3850                     old = document.body[fend]
3851                     if val == frametype:
3852                         document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
3853                     else:
3854                         document.body[fend : fend] = ['\\end_deeper']
3855                     document.body[j + 1 : j + 1] = ['', '\\begin_deeper']
3856                     break
3857             i = j
3858
3859
3860 def remove_endframes(document):
3861     " Remove deprecated beamer endframes "
3862     
3863     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3864     if document.textclass not in beamer_classes:
3865         return
3866    
3867     i = 0
3868     while True:
3869         i = find_token_exact(document.body, "\\begin_layout EndFrame", i)
3870         if i == -1:
3871             break
3872         j = find_end_of_layout(document.body, i)
3873         if j == -1:
3874             document.warning("Malformed LyX document: Missing \\end_layout to EndFrame")
3875             i = i + 1
3876             continue
3877         del document.body[i : j + 1]
3878
3879
3880 def revert_powerdot_flexes(document):
3881     " Reverts powerdot flex insets "
3882     
3883     if document.textclass != "powerdot":
3884         return
3885
3886     flexes = {"Onslide" : "\\onslide",
3887               "Onslide*" : "\\onslide*",
3888               "Onslide+" : "\\onslide+"}
3889     rx = re.compile(r'^\\begin_inset Flex (.+)$')
3890
3891     i = 0
3892     while True:
3893         i = find_token(document.body, "\\begin_inset Flex", i)
3894         if i == -1:
3895             return
3896         m = rx.match(document.body[i])
3897         if m:
3898             flextype = m.group(1)
3899             z = find_end_of_inset(document.body, i)
3900             if z == -1:
3901                 document.warning("Can't find end of Flex " + flextype + " inset.")
3902                 i += 1
3903                 continue
3904             if flextype in flexes:
3905                 pre = put_cmd_in_ert(flexes[flextype])
3906                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
3907                 if arg != -1:
3908                     argend = find_end_of_inset(document.body, arg)
3909                     if argend == -1:
3910                         document.warning("Can't find end of Argument!")
3911                         i += 1
3912                         continue
3913                     # Find containing paragraph layout
3914                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3915                     endPlain = find_end_of_layout(document.body, beginPlain)
3916                     argcontent = document.body[beginPlain + 1 : endPlain]
3917                     # Adjust range end
3918                     z = z - len(document.body[arg : argend + 1])
3919                     # Remove arg inset
3920                     del document.body[arg : argend + 1]
3921                     pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
3922                 pre += put_cmd_in_ert("{")
3923                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
3924                 endPlain = find_end_of_layout(document.body, beginPlain)
3925                 # Adjust range end
3926                 z = z - len(document.body[i : beginPlain + 1])
3927                 z += len(pre)
3928                 document.body[i : beginPlain + 1] = pre
3929                 post = put_cmd_in_ert("}")
3930                 document.body[z - 2 : z + 1] = post     
3931         i += 1
3932
3933
3934 def revert_powerdot_pause(document):
3935     " Reverts powerdot pause layout to ERT "
3936     
3937     if document.textclass != "powerdot":
3938         return
3939
3940     i = 0
3941     while True:
3942         i = find_token(document.body, "\\begin_layout Pause", i)
3943         if i == -1:
3944             return
3945         j = find_end_of_layout(document.body, i)
3946         if j == -1:
3947             document.warning("Malformed LyX document: Can't find end of Pause layout")
3948             i = i + 1
3949             continue
3950         endlay = j
3951         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\pause")
3952         for p in range(i, j):
3953             if p >= endlay:
3954                 break
3955             arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3956             if arg != -1:
3957                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3958                 endPlain = find_end_of_layout(document.body, beginPlain)
3959                 endInset = find_end_of_inset(document.body, p)
3960                 content = document.body[beginPlain + 1 : endPlain]
3961                 # Adjust range end
3962                 endlay = endlay - len(document.body[p : endInset + 1])
3963                 # Remove arg inset
3964                 del document.body[p : endInset + 1]
3965                 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3966                     
3967         document.body[i : i + 1] = subst
3968         i = endlay
3969
3970
3971 def revert_powerdot_itemargs(document):
3972     " Reverts powerdot item arguments to ERT "
3973     
3974     if document.textclass != "powerdot":
3975         return
3976
3977     i = 0
3978     list_layouts = ["Itemize", "ItemizeType1", "Enumerate", "EnumerateType1"]
3979     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3980
3981     while True:
3982         i = find_token(document.body, "\\begin_inset Argument", i)
3983         if i == -1:
3984             return
3985         # Find containing paragraph layout
3986         parent = get_containing_layout(document.body, i)
3987         if parent == False:
3988             document.warning("Malformed LyX document: Can't find parent paragraph layout")
3989             i = i + 1
3990             continue
3991         parbeg = parent[1]
3992         parend = parent[2]
3993         realparbeg = parent[3]
3994         layoutname = parent[0]
3995         realparend = parend
3996         for p in range(parbeg, parend):
3997             if p >= realparend:
3998                 i = realparend
3999                 break
4000             if layoutname in list_layouts:
4001                 m = rx.match(document.body[p])
4002                 if m:
4003                     argnr = m.group(1)
4004                     if argnr == "item:1":
4005                         j = find_end_of_inset(document.body, i)
4006                         # Find containing paragraph layout
4007                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4008                         endPlain = find_end_of_layout(document.body, beginPlain)
4009                         content = document.body[beginPlain + 1 : endPlain]
4010                         del document.body[i:j+1]
4011                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4012                         document.body[realparbeg : realparbeg] = subst
4013                     elif argnr == "item:2":
4014                         j = find_end_of_inset(document.body, i)
4015                         # Find containing paragraph layout
4016                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4017                         endPlain = find_end_of_layout(document.body, beginPlain)
4018                         content = document.body[beginPlain + 1 : endPlain]
4019                         del document.body[i:j+1]
4020                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
4021                         document.body[realparbeg : realparbeg] = subst
4022         
4023         i = realparend
4024
4025
4026 def revert_powerdot_columns(document):
4027     " Reverts powerdot twocolumn to TeX-code "
4028     if document.textclass != "powerdot":
4029         return
4030
4031     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4032     i = 0
4033     while True:
4034         i = find_token(document.body, "\\begin_layout Twocolumn", i)
4035         if i == -1:
4036             return
4037         j = find_end_of_layout(document.body, i)
4038         if j == -1:
4039             document.warning("Malformed LyX document: Can't find end of Twocolumn layout")
4040             i = i + 1
4041             continue
4042         endlay = j
4043         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
4044         endlay += len(put_cmd_in_ert("}"))
4045         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\twocolumn")
4046         for p in range(i, j):
4047             if p >= endlay:
4048                 break
4049             m = rx.match(document.body[p])
4050             if m:
4051                 argnr = m.group(1)
4052                 if argnr == "1":
4053                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4054                     endPlain = find_end_of_layout(document.body, beginPlain)
4055                     endInset = find_end_of_inset(document.body, p)
4056                     content = document.body[beginPlain + 1 : endPlain]
4057                     # Adjust range end
4058                     endlay = endlay - len(document.body[p : endInset + 1])
4059                     # Remove arg inset
4060                     del document.body[p : endInset + 1]
4061                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4062                 elif argnr == "2":
4063                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4064                     endPlain = find_end_of_layout(document.body, beginPlain)
4065                     endInset = find_end_of_inset(document.body, p)
4066                     content = document.body[beginPlain + 1 : endPlain]
4067                     # Adjust range end
4068                     endlay = endlay - len(document.body[p : endInset + 1])
4069                     # Remove arg inset
4070                     del document.body[p : endInset + 1]
4071                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
4072                     
4073         subst += put_cmd_in_ert("{")
4074         document.body[i : i + 1] = subst
4075         i = endlay
4076
4077
4078 def revert_mbox_fbox(document):
4079     'Convert revert mbox/fbox boxes to TeX-code'
4080     i = 0
4081     while True:
4082         i = find_token(document.body, "\\begin_inset Box", i)
4083         if i == -1:
4084             return
4085         j = find_token(document.body, "width", i)
4086         if j != i + 7:
4087             document.warning("Malformed LyX document: Can't find box width")
4088             return
4089         width = get_value(document.body, "width", j)
4090         k = find_end_of_inset(document.body, j)
4091         if k == -1:
4092             document.warning("Malformed LyX document: Can't find end of box inset")
4093             i += 1
4094             continue
4095         BeginLayout = find_token(document.body, "\\begin_layout Plain Layout", j)
4096         EndLayout = find_token(document.body, "\\end_layout", BeginLayout)
4097         # replace if width is ""
4098         if (width == '""'):
4099             document.body[EndLayout:k + 1] = put_cmd_in_ert("}")
4100             if document.body[i] == "\\begin_inset Box Frameless":
4101                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\mbox{")
4102             if document.body[i] == "\\begin_inset Box Boxed":
4103                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\fbox{")
4104         i = i + 1
4105
4106
4107 def revert_starred_caption(document):
4108     " Reverts unnumbered longtable caption insets "
4109     
4110     i = 0
4111     while True:
4112       i = find_token(document.body, "\\begin_inset Caption LongTableNoNumber", i)
4113       if i == -1:
4114           return
4115       # This is not equivalent, but since the caption inset is a full blown
4116       # text inset a true conversion to ERT is too difficult.
4117       document.body[i] = "\\begin_inset Caption Standard"
4118       i = i + 1
4119
4120
4121 def revert_forced_local_layout(document):
4122     i = 0
4123     while True:
4124         i = find_token(document.header, "\\begin_forced_local_layout", i)
4125         if i == -1:
4126             return
4127         j = find_end_of(document.header, i, "\\begin_forced_local_layout", "\\end_forced_local_layout")
4128         if j == -1:
4129             # this should not happen
4130             break
4131         regexp = re.compile(r'\s*forcelocal', re.IGNORECASE)
4132         k = find_re(document.header, regexp, i, j)
4133         while k != -1:
4134             del document.header[k]
4135             j = j - 1
4136             k = find_re(document.header, regexp, i, j)
4137         k = find_token(document.header, "\\begin_local_layout", 0)
4138         if k == -1:
4139             document.header[i] = "\\begin_local_layout"
4140             document.header[j] = "\\end_local_layout"
4141         else:
4142             l = find_end_of(document.header, k, "\\begin_local_layout", "\\end_local_layout")
4143             if j == -1:
4144                 # this should not happen
4145                 break
4146             lines = document.header[i+1 : j]
4147             if k > i:
4148                 document.header[k+1 : k+1] = lines
4149                 document.header[i   : j  ] = []
4150             else:
4151                 document.header[i   : j  ] = []
4152                 document.header[k+1 : k+1] = lines
4153
4154
4155 def revert_aa1(document):
4156   " Reverts InsetArguments of aa to TeX-code "
4157   if document.textclass == "aa":
4158     i = 0
4159     while True:
4160       if i != -1:
4161         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4162       if i != -1:
4163         revert_Argument_to_TeX_brace(document, i, 0, 1, 4, False, False)
4164         i = i + 1
4165       if i == -1:
4166         return
4167
4168
4169 def revert_aa2(document):
4170   " Reverts InsetArguments of aa to TeX-code "
4171   if document.textclass == "aa":
4172     i = 0
4173     while True:
4174       if i != -1:
4175         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4176       if i != -1:
4177         document.body[i] = "\\begin_layout Abstract"
4178         i = i + 1
4179       if i == -1:
4180         return
4181
4182
4183 ##
4184 # Conversion hub
4185 #
4186
4187 supported_versions = ["2.1.0","2.1"]
4188 convert = [
4189            [414, []],
4190            [415, [convert_undertilde]],
4191            [416, []],
4192            [417, [convert_japanese_encodings]],
4193            [418, []],
4194            [419, []],
4195            [420, [convert_biblio_style]],
4196            [421, [convert_longtable_captions]],
4197            [422, [convert_use_packages]],
4198            [423, [convert_use_mathtools]],
4199            [424, [convert_cite_engine_type]],
4200            [425, []],
4201            [426, []],
4202            [427, []],
4203            [428, [convert_cell_rotation]],
4204            [429, [convert_table_rotation]],
4205            [430, [convert_listoflistings]],
4206            [431, [convert_use_amssymb]],
4207            [432, []],
4208            [433, [convert_armenian]],
4209            [434, []],
4210            [435, []],
4211            [436, []],
4212            [437, []],
4213            [438, []],
4214            [439, []],
4215            [440, []],
4216            [441, [convert_mdnomath]],
4217            [442, []],
4218            [443, []],
4219            [444, []],
4220            [445, []],
4221            [446, [convert_latexargs]],
4222            [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV, convert_Initials, convert_ModernCV]],
4223            [448, [convert_literate]],
4224            [449, []],
4225            [450, []],
4226            [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]],
4227            [452, [convert_beamerblocks]],
4228            [453, [convert_use_stmaryrd]],
4229            [454, [convert_overprint]],
4230            [455, []],
4231            [456, [convert_epigraph]],
4232            [457, [convert_use_stackrel]],
4233            [458, [convert_captioninsets, convert_captionlayouts]],
4234            [459, []],
4235            [460, []],
4236            [461, []],
4237            [462, []],
4238            [463, [convert_encodings]],
4239            [464, [convert_use_cancel]],
4240            [465, [convert_lyxframes, remove_endframes]],
4241            [466, []],
4242            [467, []],
4243            [468, []],
4244            [469, []],
4245            [470, []],
4246            [471, [convert_cite_engine_type_default]],
4247            [472, []]
4248           ]
4249
4250 revert =  [
4251            [471, [revert_aa1,revert_aa2]],
4252            [470, [revert_cite_engine_type_default]],
4253            [469, [revert_forced_local_layout]],
4254            [468, [revert_starred_caption]],
4255            [467, [revert_mbox_fbox]],
4256            [466, [revert_iwona_fonts]],
4257            [465, [revert_powerdot_flexes, revert_powerdot_pause, revert_powerdot_itemargs, revert_powerdot_columns]],
4258            [464, []],
4259            [463, [revert_use_cancel]],
4260            [462, [revert_encodings]],
4261            [461, [revert_new_libertines]],
4262            [460, [revert_kurier_fonts]],
4263            [459, [revert_IEEEtran_3]],
4264            [458, [revert_fragileframe, revert_newframes]],
4265            [457, [revert_captioninsets, revert_captionlayouts]],
4266            [456, [revert_use_stackrel]],
4267            [455, [revert_epigraph]],
4268            [454, [revert_frametitle]],
4269            [453, [revert_overprint]],
4270            [452, [revert_use_stmaryrd]],
4271            [451, [revert_beamerblocks]],
4272            [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
4273            [449, [revert_garamondx, revert_garamondx_newtxmath]],
4274            [448, [revert_itemargs]],
4275            [447, [revert_literate]],
4276            [446, [revert_IEEEtran, revert_IEEEtran_2, revert_AASTeX, revert_AGUTeX, revert_IJMP, revert_SIGPLAN, revert_SIGGRAPH, revert_EuropeCV, revert_Initials, revert_ModernCV_3]],
4277            [445, [revert_latexargs]],
4278            [444, [revert_uop]],
4279            [443, [revert_biolinum]],
4280            [442, []],
4281            [441, [revert_newtxmath]],
4282            [440, [revert_mdnomath]],
4283            [439, [revert_mathfonts]],
4284            [438, [revert_minionpro]],
4285            [437, [revert_ipadeco, revert_ipachar]],
4286            [436, [revert_texgyre]],
4287            [435, [revert_mathdesign]],
4288            [434, [revert_txtt]],
4289            [433, [revert_libertine]],
4290            [432, [revert_armenian]],
4291            [431, [revert_languages, revert_ancientgreek]],
4292            [430, [revert_use_amssymb]],
4293            [429, [revert_listoflistings]],
4294            [428, [revert_table_rotation]],
4295            [427, [revert_cell_rotation]],
4296            [426, [revert_tipa]],
4297            [425, [revert_verbatim]],
4298            [424, [revert_cancel]],
4299            [423, [revert_cite_engine_type]],
4300            [422, [revert_use_mathtools]],
4301            [421, [revert_use_packages]],
4302            [420, [revert_longtable_captions]],
4303            [419, [revert_biblio_style]],
4304            [418, [revert_australian]],
4305            [417, [revert_justification]],
4306            [416, [revert_japanese_encodings]],
4307            [415, [revert_negative_space, revert_math_spaces]],
4308            [414, [revert_undertilde]],
4309            [413, [revert_visible_space]]
4310           ]
4311
4312
4313 if __name__ == "__main__":
4314     pass