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