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