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