]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_1.py
6752eb981782bcf039231fa6e082afad2115d90a
[lyx.git] / lib / lyx2lyx / lyx_2_1.py
1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # -*- coding: utf-8 -*-
4 # Copyright (C) 2011 The LyX team
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
20 """ Convert files to the file format generated by LyX 2.1"""
21
22 import re, string
23 import unicodedata
24 import sys, os
25
26 # Uncomment only what you need to import, please.
27
28 from parser_tools import count_pars_in_inset, del_token, find_token, find_token_exact, \
29     find_token_backwards, find_end_of, find_end_of_inset, find_end_of_layout, \
30     find_end_of_sequence, find_re, get_option_value, get_containing_layout, \
31     get_value, get_quoted_value, set_option_value
32
33 #from parser_tools import find_token, find_end_of, find_tokens, \
34   #find_end_of_inset, find_end_of_layout, \
35   #is_in_inset, del_token, check_token
36
37 from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, get_ert
38
39 #from lyx2lyx_tools import insert_to_preamble, \
40 #  lyx2latex, latex_length, revert_flex_inset, \
41 #  revert_font_attrs, hex2ratio, str2bool
42
43 ####################################################################
44 # Private helper functions
45
46 #def remove_option(lines, m, option):
47     #''' removes option from line m. returns whether we did anything '''
48     #l = lines[m].find(option)
49     #if l == -1:
50         #return False
51     #val = lines[m][l:].split('"')[1]
52     #lines[m] = lines[m][:l - 1] + lines[m][l+len(option + '="' + val + '"'):]
53     #return True
54
55
56 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 cleanup_beamerargs(document):
2519     " Clean up empty ERTs (conversion artefacts) "
2520
2521     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2522     if document.textclass not in beamer_classes:
2523         return
2524
2525     i = 0
2526     while True:
2527         i = find_token(document.body, "\\begin_inset Argument", i)
2528         if i == -1:
2529             return
2530         j = find_end_of_inset(document.body, i)
2531         if j == -1:
2532             document.warning("Malformed LyX document: Can't find end of Argument inset")
2533             i += 1
2534             continue
2535         while True:
2536             ertbeg = find_token(document.body, "\\begin_inset ERT", i, j)
2537             if ertbeg == -1:
2538                 break
2539             ertend = find_end_of_inset(document.body, ertbeg)
2540             if ertend == -1:
2541                 document.warning("Malformed LyX document: Can't find end of ERT inset")
2542                 break
2543             stripped = [line for line in document.body[ertbeg : ertend + 1] if line.strip()]
2544             if len(stripped) == 5:
2545                 # This is an empty ERT
2546                 offset = len(document.body[ertbeg : ertend + 1])
2547                 del document.body[ertbeg : ertend + 1]
2548                 j = j - offset
2549             else:
2550                 i = ertend
2551         i += 1
2552
2553
2554 def revert_beamerargs(document):
2555     " Reverts beamer arguments to old layout "
2556     
2557     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2558     if document.textclass not in beamer_classes:
2559         return
2560
2561     i = 0
2562     list_layouts = ["Itemize", "Enumerate", "Description"]
2563     headings = ["Part", "Section", "Section*", "Subsection", "Subsection*",
2564                 "Subsubsection", "Subsubsection*", "FrameSubtitle", "NoteItem"]
2565     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2566     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2567     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2568
2569     while True:
2570         i = find_token(document.body, "\\begin_inset Argument", i)
2571         if i == -1:
2572             return
2573         # Find containing paragraph layout
2574         parent = get_containing_layout(document.body, i)
2575         if parent == False:
2576             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2577             i += 1
2578             continue
2579         parbeg = parent[1]
2580         parend = parent[2]
2581         realparbeg = parent[3]
2582         layoutname = parent[0]
2583         realparend = parend
2584         for p in range(parbeg, parend):
2585             if p >= realparend:
2586                 i = realparend
2587                 break
2588             if layoutname in headings:
2589                 m = rx.match(document.body[p])
2590                 if m:
2591                     argnr = m.group(1)
2592                     if argnr == "1":
2593                         # Find containing paragraph layout
2594                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2595                         endPlain = find_end_of_layout(document.body, beginPlain)
2596                         endInset = find_end_of_inset(document.body, p)
2597                         argcontent = document.body[beginPlain + 1 : endPlain]
2598                         # Adjust range end
2599                         realparend = realparend - len(document.body[p : endInset + 1])
2600                         # Remove arg inset
2601                         del document.body[p : endInset + 1]
2602                         if layoutname == "FrameSubtitle":
2603                             pre = put_cmd_in_ert("\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2604                         elif layoutname == "NoteItem":
2605                             pre = put_cmd_in_ert("\\note<") + argcontent + put_cmd_in_ert(">[item]")
2606                         elif layoutname.endswith('*'):
2607                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower()[:-1] + "<") + argcontent + put_cmd_in_ert(">*")
2608                         else:
2609                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2610                         secarg = find_token(document.body, "\\begin_inset Argument 2", parbeg, parend)
2611                         if secarg != -1:
2612                             # Find containing paragraph layout
2613                             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", secarg)
2614                             endPlain = find_end_of_layout(document.body, beginPlain)
2615                             endInset = find_end_of_inset(document.body, secarg)
2616                             argcontent = document.body[beginPlain + 1 : endPlain]
2617                             # Adjust range end
2618                             realparend = realparend - len(document.body[secarg : endInset + 1])
2619                             del document.body[secarg : endInset + 1]
2620                             pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2621                         pre += put_cmd_in_ert("{")
2622                         document.body[parbeg] = "\\begin_layout Standard"
2623                         document.body[realparbeg : realparbeg] = pre
2624                         pe = find_end_of_layout(document.body, parbeg)
2625                         post = put_cmd_in_ert("}")
2626                         document.body[pe : pe] = post
2627                         realparend += len(pre) + len(post)
2628             if layoutname == "AgainFrame":
2629                 m = rx.match(document.body[p])
2630                 if m:
2631                     argnr = m.group(1)
2632                     if argnr == "3":
2633                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2634                         endPlain = find_end_of_layout(document.body, beginPlain)
2635                         endInset = find_end_of_inset(document.body, p)
2636                         content = document.body[beginPlain + 1 : endPlain]
2637                         # Adjust range end
2638                         realparend = realparend - len(document.body[p : endInset + 1])
2639                         # Remove arg inset
2640                         del document.body[p : endInset + 1]
2641                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2642                         document.body[realparbeg : realparbeg] = subst
2643             if layoutname == "Overprint":
2644                 m = rx.match(document.body[p])
2645                 if m:
2646                     argnr = m.group(1)
2647                     if argnr == "1":
2648                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2649                         endPlain = find_end_of_layout(document.body, beginPlain)
2650                         endInset = find_end_of_inset(document.body, p)
2651                         content = document.body[beginPlain + 1 : endPlain]
2652                         # Adjust range end
2653                         realparend = realparend - len(document.body[p : endInset + 1])
2654                         # Remove arg inset
2655                         del document.body[p : endInset + 1]
2656                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2657                         document.body[realparbeg : realparbeg] = subst
2658             if layoutname == "OverlayArea":
2659                 m = rx.match(document.body[p])
2660                 if m:
2661                     argnr = m.group(1)
2662                     if argnr == "2":
2663                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2664                         endPlain = find_end_of_layout(document.body, beginPlain)
2665                         endInset = find_end_of_inset(document.body, p)
2666                         content = document.body[beginPlain + 1 : endPlain]
2667                         # Adjust range end
2668                         realparend = realparend - len(document.body[p : endInset + 1])
2669                         # Remove arg inset
2670                         del document.body[p : endInset + 1]
2671                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2672                         document.body[realparbeg : realparbeg] = subst
2673             if layoutname in list_layouts:
2674                 m = rx.match(document.body[p])
2675                 if m:
2676                     argnr = m.group(1)
2677                     if argnr == "1":
2678                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2679                         endPlain = find_end_of_layout(document.body, beginPlain)
2680                         endInset = find_end_of_inset(document.body, p)
2681                         content = document.body[beginPlain + 1 : endPlain]
2682                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2683                         realparend = realparend + len(subst) - len(content)
2684                         document.body[beginPlain + 1 : endPlain] = subst
2685                     elif argnr == "item:1":
2686                         j = find_end_of_inset(document.body, i)
2687                         # Find containing paragraph layout
2688                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2689                         endPlain = find_end_of_layout(document.body, beginPlain)
2690                         content = document.body[beginPlain + 1 : endPlain]
2691                         del document.body[i:j+1]
2692                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2693                         document.body[realparbeg : realparbeg] = subst
2694                     elif argnr == "item:2":
2695                         j = find_end_of_inset(document.body, i)
2696                         # Find containing paragraph layout
2697                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2698                         endPlain = find_end_of_layout(document.body, beginPlain)
2699                         content = document.body[beginPlain + 1 : endPlain]
2700                         del document.body[i:j+1]
2701                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2702                         document.body[realparbeg : realparbeg] = subst
2703             if layoutname in quote_layouts:
2704                 m = rx.match(document.body[p])
2705                 if m:
2706                     argnr = m.group(1)
2707                     if argnr == "1":
2708                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2709                         endPlain = find_end_of_layout(document.body, beginPlain)
2710                         endInset = find_end_of_inset(document.body, p)
2711                         content = document.body[beginPlain + 1 : endPlain]
2712                         # Adjust range end
2713                         realparend = realparend - len(document.body[p : endInset + 1])
2714                         # Remove arg inset
2715                         del document.body[p : endInset + 1]
2716                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2717                         document.body[realparbeg : realparbeg] = subst
2718             if layoutname in corollary_layouts:
2719                 m = rx.match(document.body[p])
2720                 if m:
2721                     argnr = m.group(1)
2722                     if argnr == "2":
2723                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2724                         endPlain = find_end_of_layout(document.body, beginPlain)
2725                         endInset = find_end_of_inset(document.body, p)
2726                         content = document.body[beginPlain + 1 : endPlain]
2727                         # Adjust range end
2728                         realparend = realparend - len(document.body[p : endInset + 1])
2729                         # Remove arg inset
2730                         del document.body[p : endInset + 1]
2731                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2732                         document.body[realparbeg : realparbeg] = subst
2733         
2734         i = realparend
2735
2736
2737 def revert_beamerargs2(document):
2738     " Reverts beamer arguments to old layout, step 2 "
2739     
2740     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2741     if document.textclass not in beamer_classes:
2742         return
2743
2744     i = 0
2745     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2746     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2747     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2748
2749     while True:
2750         i = find_token(document.body, "\\begin_inset Argument", i)
2751         if i == -1:
2752             return
2753         # Find containing paragraph layout
2754         parent = get_containing_layout(document.body, i)
2755         if parent == False:
2756             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2757             i += 1
2758             continue
2759         parbeg = parent[1]
2760         parend = parent[2]
2761         realparbeg = parent[3]
2762         layoutname = parent[0]
2763         realparend = parend
2764         for p in range(parbeg, parend):
2765             if p >= realparend:
2766                 i = realparend
2767                 break
2768             if layoutname in shifted_layouts:
2769                 m = rx.match(document.body[p])
2770                 if m:
2771                     argnr = m.group(1)
2772                     if argnr == "2":
2773                         document.body[p] = "\\begin_inset Argument 1"       
2774             if layoutname in corollary_layouts:
2775                 m = rx.match(document.body[p])
2776                 if m:
2777                     argnr = m.group(1)
2778                     if argnr == "1":
2779                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2780                         endPlain = find_end_of_layout(document.body, beginPlain)
2781                         endInset = find_end_of_inset(document.body, p)
2782                         content = document.body[beginPlain + 1 : endPlain]
2783                         # Adjust range end
2784                         realparend = realparend - len(document.body[p : endInset + 1])
2785                         # Remove arg inset
2786                         del document.body[p : endInset + 1]
2787                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2788                         document.body[realparbeg : realparbeg] = subst
2789             if layoutname == "OverlayArea":
2790                 m = rx.match(document.body[p])
2791                 if m:
2792                     argnr = m.group(1)
2793                     if argnr == "1":
2794                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2795                         endPlain = find_end_of_layout(document.body, beginPlain)
2796                         endInset = find_end_of_inset(document.body, p)
2797                         content = document.body[beginPlain + 1 : endPlain]
2798                         # Adjust range end
2799                         realparend = realparend - len(document.body[p : endInset + 1])
2800                         # Remove arg inset
2801                         del document.body[p : endInset + 1]
2802                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2803                         document.body[realparbeg : realparbeg] = subst
2804             if layoutname == "AgainFrame":
2805                 m = rx.match(document.body[p])
2806                 if m:
2807                     argnr = m.group(1)
2808                     if argnr == "2":
2809                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2810                         endPlain = find_end_of_layout(document.body, beginPlain)
2811                         endInset = find_end_of_inset(document.body, p)
2812                         content = document.body[beginPlain + 1 : endPlain]
2813                         # Adjust range end
2814                         realparend = realparend - len(document.body[p : endInset + 1])
2815                         # Remove arg inset
2816                         del document.body[p : endInset + 1]
2817                         subst = put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
2818                         document.body[realparbeg : realparbeg] = subst
2819         i = realparend
2820
2821
2822 def revert_beamerargs3(document):
2823     " Reverts beamer arguments to old layout, step 3 "
2824     
2825     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2826     if document.textclass not in beamer_classes:
2827         return
2828
2829     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2830     i = 0
2831     while True:
2832         i = find_token(document.body, "\\begin_inset Argument", i)
2833         if i == -1:
2834             return
2835         # Find containing paragraph layout
2836         parent = get_containing_layout(document.body, i)
2837         if parent == False:
2838             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2839             i += 1
2840             continue
2841         parbeg = parent[1]
2842         parend = parent[2]
2843         realparbeg = parent[3]
2844         layoutname = parent[0]
2845         realparend = parend
2846         for p in range(parbeg, parend):
2847             if p >= realparend:
2848                 i = realparend
2849                 break
2850             if layoutname == "AgainFrame":
2851                 m = rx.match(document.body[p])
2852                 if m:
2853                     argnr = m.group(1)
2854                     if argnr == "1":
2855                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2856                         endPlain = find_end_of_layout(document.body, beginPlain)
2857                         endInset = find_end_of_inset(document.body, p)
2858                         content = document.body[beginPlain + 1 : endPlain]
2859                         # Adjust range end
2860                         realparend = realparend - len(document.body[p : endInset + 1])
2861                         # Remove arg inset
2862                         del document.body[p : endInset + 1]
2863                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2864                         document.body[realparbeg : realparbeg] = subst
2865         i = realparend
2866
2867
2868 def revert_beamerflex(document):
2869     " Reverts beamer Flex insets "
2870     
2871     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2872     if document.textclass not in beamer_classes:
2873         return
2874
2875     new_flexes = {"Bold" : "\\textbf", "Emphasize" : "\\emph", "Only" : "\\only",
2876                   "Uncover" : "\\uncover", "Visible" : "\\visible",
2877                   "Invisible" : "\\invisible", "Alternative" : "\\alt",
2878                   "Beamer_Note" : "\\note"}
2879     old_flexes = {"Alert" : "\\alert", "Structure" : "\\structure"}
2880     rx = re.compile(r'^\\begin_inset Flex (.+)$')
2881
2882     i = 0
2883     while True:
2884         i = find_token(document.body, "\\begin_inset Flex", i)
2885         if i == -1:
2886             return
2887         m = rx.match(document.body[i])
2888         if m:
2889             flextype = m.group(1)
2890             z = find_end_of_inset(document.body, i)
2891             if z == -1:
2892                 document.warning("Can't find end of Flex " + flextype + " inset.")
2893                 i += 1
2894                 continue
2895             if flextype in new_flexes:
2896                 pre = put_cmd_in_ert(new_flexes[flextype])
2897                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2898                 if arg != -1:
2899                     argend = find_end_of_inset(document.body, arg)
2900                     if argend == -1:
2901                         document.warning("Can't find end of Argument!")
2902                         i += 1
2903                         continue
2904                     # Find containing paragraph layout
2905                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2906                     endPlain = find_end_of_layout(document.body, beginPlain)
2907                     argcontent = document.body[beginPlain + 1 : endPlain]
2908                     # Adjust range end
2909                     z = z - len(document.body[arg : argend + 1])
2910                     # Remove arg inset
2911                     del document.body[arg : argend + 1]
2912                     pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2913                 arg = find_token(document.body, "\\begin_inset Argument 2", i, z)
2914                 if arg != -1:
2915                     argend = find_end_of_inset(document.body, arg)
2916                     if argend == -1:
2917                         document.warning("Can't find end of Argument!")
2918                         i += 1
2919                         continue
2920                     # Find containing paragraph layout
2921                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2922                     endPlain = find_end_of_layout(document.body, beginPlain)
2923                     argcontent = document.body[beginPlain + 1 : endPlain]
2924                     # Adjust range end
2925                     z = z - len(document.body[arg : argend + 1])
2926                     # Remove arg inset
2927                     del document.body[arg : argend + 1]
2928                     if flextype == "Alternative":
2929                         pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
2930                     else:
2931                         pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2932                 pre += put_cmd_in_ert("{")
2933                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2934                 endPlain = find_end_of_layout(document.body, beginPlain)
2935                 # Adjust range end
2936                 z = z - len(document.body[i : beginPlain + 1])
2937                 z += len(pre)
2938                 document.body[i : beginPlain + 1] = pre
2939                 post = put_cmd_in_ert("}")
2940                 document.body[z - 2 : z + 1] = post
2941             elif flextype in old_flexes:
2942                 pre = put_cmd_in_ert(old_flexes[flextype])
2943                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2944                 if arg == -1:
2945                     i += 1
2946                     continue
2947                 argend = find_end_of_inset(document.body, arg)
2948                 if argend == -1:
2949                     document.warning("Can't find end of Argument!")
2950                     i += 1
2951                     continue
2952                 # Find containing paragraph layout
2953                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2954                 endPlain = find_end_of_layout(document.body, beginPlain)
2955                 argcontent = document.body[beginPlain + 1 : endPlain]
2956                 # Adjust range end
2957                 z = z - len(document.body[arg : argend + 1])
2958                 # Remove arg inset
2959                 del document.body[arg : argend + 1]
2960                 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2961                 pre += put_cmd_in_ert("{")
2962                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2963                 endPlain = find_end_of_layout(document.body, beginPlain)
2964                 # Adjust range end
2965                 z = z - len(document.body[i : beginPlain + 1])
2966                 z += len(pre)
2967                 document.body[i : beginPlain + 1] = pre
2968                 post = put_cmd_in_ert("}")
2969                 document.body[z - 2 : z + 1] = post
2970         
2971         i += 1
2972
2973
2974 def revert_beamerblocks(document):
2975     " Reverts beamer block arguments to ERT "
2976     
2977     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2978     if document.textclass not in beamer_classes:
2979         return
2980
2981     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2982
2983     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2984     i = 0
2985     while True:
2986         i = find_token(document.body, "\\begin_inset Argument", i)
2987         if i == -1:
2988             return
2989         # Find containing paragraph layout
2990         parent = get_containing_layout(document.body, i)
2991         if parent == False:
2992             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2993             i += 1
2994             continue
2995         parbeg = parent[1]
2996         parend = parent[2]
2997         realparbeg = parent[3]
2998         layoutname = parent[0]
2999         realparend = parend
3000         for p in range(parbeg, parend):
3001             if p >= realparend:
3002                 i = realparend
3003                 break
3004             if layoutname in blocks:
3005                 m = rx.match(document.body[p])
3006                 if m:
3007                     argnr = m.group(1)
3008                     if argnr == "1":
3009                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3010                         endPlain = find_end_of_layout(document.body, beginPlain)
3011                         endInset = find_end_of_inset(document.body, p)
3012                         content = document.body[beginPlain + 1 : endPlain]
3013                         # Adjust range end
3014                         realparend = realparend - len(document.body[p : endInset + 1])
3015                         # Remove arg inset
3016                         del document.body[p : endInset + 1]
3017                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3018                         document.body[realparbeg : realparbeg] = subst
3019                     elif argnr == "2":
3020                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3021                         endPlain = find_end_of_layout(document.body, beginPlain)
3022                         endInset = find_end_of_inset(document.body, p)
3023                         content = document.body[beginPlain + 1 : endPlain]
3024                         # Adjust range end
3025                         realparend = realparend - len(document.body[p : endInset + 1])
3026                         # Remove arg inset
3027                         del document.body[p : endInset + 1]
3028                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3029                         document.body[realparbeg : realparbeg] = subst
3030         i = realparend
3031
3032
3033
3034 def convert_beamerblocks(document):
3035     " Converts beamer block ERT args to native InsetArgs "
3036     
3037     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3038     if document.textclass not in beamer_classes:
3039         return
3040    
3041     blocks = ["Block", "ExampleBlock", "AlertBlock"]
3042     for lay in blocks:
3043         i = 0
3044         while True:
3045             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
3046             if i == -1:
3047                 break
3048             parent = get_containing_layout(document.body, i)
3049             if parent == False or parent[1] != i:
3050                 document.warning("Wrong parent layout!")
3051                 i += 1
3052                 continue
3053             parbeg = parent[3]
3054             parend = parent[2]
3055             j = parend
3056             if i != -1:
3057                 if document.body[parbeg] == "\\begin_inset ERT":
3058                     ertcontfirstline = parbeg + 5
3059                     # Find the last ERT in this paragraph (which might also be the first)
3060                     lastertbeg = find_token_backwards(document.body, "\\begin_inset ERT", j)
3061                     if lastertbeg == -1:
3062                         document.warning("Last ERT not found!")
3063                         break
3064                     lastertend = find_end_of_inset(document.body, lastertbeg)
3065                     if lastertend == -1:
3066                         document.warning("End of last ERT not found!")
3067                         break
3068                     ertcontlastline = lastertend - 3
3069                     while True:
3070                         if document.body[ertcontfirstline].lstrip().startswith("<"):
3071                             # This is an overlay specification
3072                             # strip off the <
3073                             document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3074                             if document.body[ertcontlastline].rstrip().endswith(">"):
3075                                 # strip off the >
3076                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3077                                 # Convert to ArgInset
3078                                 document.body[parbeg] = "\\begin_inset Argument 1"
3079                             elif document.body[ertcontlastline].rstrip().endswith("}"):
3080                                 # strip off the }
3081                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3082                                 # divide the args
3083                                 ertcontdivline = ertcontfirstline
3084                                 tok = document.body[ertcontdivline].find('>{')
3085                                 if tok == -1:
3086                                     regexp = re.compile(r'.*>\{', re.IGNORECASE)
3087                                     ertcontdivline = find_re(document.body, regexp, ertcontfirstline, ertcontlastline)
3088                                     tok = document.body[ertcontdivline].find('>{')
3089                                 if tok != -1:
3090                                     if ertcontfirstline < ertcontlastline:
3091                                         # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3092                                         document.body[ertcontlastline : ertcontlastline + 1] = [
3093                                                                             document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3094                                         document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3095                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3096                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3097                                                                             '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3098                                                                             document.body[ertcontdivline][tok + 2:]]
3099                                     else:
3100                                         document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3101                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3102                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3103                                                                             document.body[ertcontdivline][tok + 2:]]
3104                                 else:
3105                                     # check if have delimiters in two different ERTs
3106                                     tok = document.body[ertcontdivline].find('>')
3107                                     if tok == -1:
3108                                         regexp = re.compile(r'.*>', re.IGNORECASE)
3109                                         ertcontdivline = find_re(document.body, regexp, ertcontfirstline, ertcontlastline)
3110                                         tok = document.body[ertcontdivline].find('>')
3111                                         if tok != -1:
3112                                             tokk = document.body[ertcontdivline].find('{')
3113                                             if tokk == -1:
3114                                                 regexp = re.compile(r'.*\{', re.IGNORECASE)
3115                                                 ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, ertcontlastline)
3116                                                 tokk = document.body[ertcontdivlinetwo].find('{')
3117                                                 if tokk != -1:
3118                                                     if ertcontfirstline < ertcontlastline:
3119                                                         # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3120                                                         document.body[ertcontlastline : ertcontlastline + 1] = [
3121                                                                                             document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3122                                                         document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3123                                                                                             '\\end_layout', '', '\\end_inset', '', '\\end_layout', '', 
3124                                                                                             '\\end_inset', '', '', '\\begin_inset Argument 2',
3125                                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3126                                                                                             '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3127                                                                                             document.body[ertcontdivlinetwo][tokk + 1:]]
3128                                                     else:
3129                                                         document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3130                                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3131                                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3132                                                                                             document.body[ertcontdivlinetwo][tokk + 1:]]
3133                                 # Convert to ArgInset
3134                                 if ertcontfirstline < ertcontlastline:
3135                                     # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3136                                     document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 1',
3137                                                                         'status collapsed', '', '\\begin_layout Plain Layout',
3138                                                                         '\\begin_inset ERT', '']
3139                                 else:
3140                                     document.body[parbeg] = "\\begin_inset Argument 1"
3141                         elif document.body[ertcontfirstline].lstrip().startswith("{"):
3142                             # This is the block title
3143                             if document.body[ertcontlastline].rstrip().endswith("}"):
3144                                 # strip off the braces
3145                                 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3146                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3147                                 if ertcontfirstline < ertcontlastline:
3148                                     # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3149                                     document.body[parend : parend + 1] = [
3150                                                                         document.body[parend], '\\end_inset', '', '\\end_layout']
3151                                     document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2',
3152                                                                         'status collapsed', '', '\\begin_layout Plain Layout',
3153                                                                         '\\begin_inset ERT', '']
3154                                 else:
3155                                     # Convert to ArgInset
3156                                     document.body[parbeg] = "\\begin_inset Argument 2"
3157                             # the overlay argument can also follow the title, so ...
3158                             elif document.body[ertcontlastline].rstrip().endswith(">"):
3159                                 # strip off the {
3160                                 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3161                                 # strip off the >
3162                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3163                                 # divide the args
3164                                 ertcontdivline = ertcontfirstline
3165                                 tok = document.body[ertcontdivline].find('}<')
3166                                 if tok == -1:
3167                                     regexp = re.compile(r'.*\}<', re.IGNORECASE)
3168                                     ertcontdivline = find_re(document.body, regexp, ertcontfirstline, ertcontlastline)
3169                                     tok = document.body[ertcontdivline].find('}<')
3170                                 if tok != -1:
3171                                     if ertcontfirstline < ertcontlastline:
3172                                         # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3173                                         document.body[ertcontlastline : ertcontlastline + 1] = [
3174                                                                             document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3175                                         document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3176                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3177                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3178                                                                             '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3179                                                                             document.body[ertcontdivline][tok + 2:]]
3180                                     else:
3181                                         document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3182                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3183                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3184                                                                             document.body[ertcontdivline][tok + 2:]]
3185                                 else:
3186                                     # check if have delimiters in two different ERTs
3187                                     tok = document.body[ertcontdivline].find('}')
3188                                     if tok == -1:
3189                                         regexp = re.compile(r'.*\}', re.IGNORECASE)
3190                                         ertcontdivline = find_re(document.body, regexp, ertcontfirstline, ertcontlastline)
3191                                         tok = document.body[ertcontdivline].find('}')
3192                                         if tok != -1:
3193                                             tokk = document.body[ertcontdivline].find('<')
3194                                             if tokk == -1:
3195                                                 regexp = re.compile(r'.*<', re.IGNORECASE)
3196                                                 ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, ertcontlastline)
3197                                                 tokk = document.body[ertcontdivlinetwo].find('<')
3198                                                 if tokk != -1:
3199                                                     if ertcontfirstline < ertcontlastline:
3200                                                         # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3201                                                         document.body[ertcontlastline : ertcontlastline + 1] = [
3202                                                                                             document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3203                                                         document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3204                                                                                             '\\end_layout', '', '\\end_inset', '', '\\end_layout', '', 
3205                                                                                             '\\end_inset', '', '', '\\begin_inset Argument 1',
3206                                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3207                                                                                             '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3208                                                                                             document.body[ertcontdivlinetwo][tokk + 1:]]
3209                                                     else:
3210                                                         document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3211                                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3212                                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3213                                                                                             document.body[ertcontdivlinetwo][tokk + 1:]]
3214                                 # Convert to ArgInset
3215                                 if ertcontfirstline < ertcontlastline:
3216                                     # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3217                                     document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2',
3218                                                                         'status collapsed', '', '\\begin_layout Plain Layout',
3219                                                                         '\\begin_inset ERT', '']
3220                                 else:
3221                                     document.body[parbeg] = "\\begin_inset Argument 2"
3222                             elif count_pars_in_inset(document.body, ertcontfirstline) > 1:
3223                                 # Multipar ERT. Skip this.
3224                                 break
3225                             else:
3226                                 convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, False)
3227                         else:
3228                             break
3229                         j = find_end_of_layout(document.body, i)
3230                         if j == -1:
3231                             document.warning("end of layout not found!")
3232                         k = find_token(document.body, "\\begin_inset Argument", i, j)
3233                         if k == -1:
3234                             document.warning("InsetArgument not found!")
3235                             break
3236                         l = find_end_of_inset(document.body, k)
3237                         m = find_token(document.body, "\\begin_inset ERT", l, j)
3238                         if m == -1:
3239                             break
3240                         ertcontfirstline = m + 5
3241                         parbeg = m
3242             i = j
3243
3244
3245 def convert_overprint(document):
3246     " Convert old beamer overprint layouts to ERT "
3247     
3248     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3249     if document.textclass not in beamer_classes:
3250         return
3251
3252     i = 0
3253     while True:
3254         i = find_token(document.body, "\\begin_layout Overprint", i)
3255         if i == -1:
3256             return
3257         # Find end of sequence
3258         j = find_end_of_sequence(document.body, i)
3259         if j == -1:
3260             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3261             i += 1
3262             continue
3263         endseq = j
3264         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3265         esubst = list()
3266         if document.body[j] == "\\end_deeper":
3267             esubst = ["", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
3268         else:
3269             esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
3270         endseq = endseq + len(esubst) - len(document.body[j : j])
3271         document.body[j : j] = esubst
3272         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3273         if argbeg != -1:
3274             argend = find_end_of_layout(document.body, argbeg)
3275             if argend == -1:
3276                 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3277                 i += 1
3278                 continue
3279             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3280             endPlain = find_end_of_layout(document.body, beginPlain)
3281             content = document.body[beginPlain + 1 : endPlain]
3282             # Adjust range end
3283             endseq = endseq - len(document.body[argbeg : argend + 1])
3284             # Remove arg inset
3285             del document.body[argbeg : argend + 1]
3286             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3287             
3288         endseq = endseq - len(document.body[i : i])
3289         document.body[i : i] = subst + ["\\end_layout"]
3290         endseq += len(subst)
3291         
3292         for p in range(i, endseq):
3293             if document.body[p] == "\\begin_layout Overprint":
3294                 document.body[p] = "\\begin_layout Standard"
3295
3296         i = endseq
3297
3298
3299 def revert_overprint(document):
3300     " Revert old beamer overprint layouts to ERT "
3301     
3302     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3303     if document.textclass not in beamer_classes:
3304         return
3305
3306     i = 0
3307     while True:
3308         i = find_token(document.body, "\\begin_layout Overprint", i)
3309         if i == -1:
3310             return
3311         # Find end of sequence
3312         j = find_end_of_sequence(document.body, i)
3313         if j == -1:
3314             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3315             i += 1
3316             continue
3317         endseq = j
3318         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3319         esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}")
3320         endseq = endseq + len(esubst) - len(document.body[j : j])
3321         if document.body[j] == "\\end_deeper":
3322             document.body[j : j] = [""] + esubst + ["", "\\end_layout"]
3323         else:
3324             document.body[j : j] = ["\\end_layout", ""] + esubst
3325         r = i
3326         while r < j:
3327             if document.body[r] == "\\begin_deeper":
3328                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3329                 if s != -1:
3330                     document.body[r] = ""
3331                     document.body[s] = ""
3332                     r = s
3333                     continue
3334             r = r + 1
3335         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3336         if argbeg != -1:
3337             # Is this really our argument?
3338             nested = find_token(document.body, "\\begin_deeper", i, argbeg)
3339             if nested != -1:
3340                 argend = find_end_of_inset(document.body, argbeg)
3341                 if argend == -1:
3342                     document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3343                     i += 1
3344                     continue
3345                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3346                 endPlain = find_end_of_layout(document.body, beginPlain)
3347                 content = document.body[beginPlain + 1 : endPlain]
3348                 # Adjust range end
3349                 endseq = endseq - len(document.body[argbeg : argend])
3350                 # Remove arg inset
3351                 del document.body[argbeg : argend + 1]
3352                 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3353             
3354         endseq = endseq - len(document.body[i : i])
3355         document.body[i : i] = subst + ["\\end_layout"]
3356         endseq += len(subst)
3357      
3358         p = i
3359         while True:
3360             if p >= endseq:
3361                 break
3362             if document.body[p] == "\\begin_layout Overprint":
3363                 q = find_end_of_layout(document.body, p)
3364                 if q == -1:
3365                     document.warning("Malformed LyX document. Cannot find end of Overprint layout!")
3366                     p += 1
3367                     continue
3368                 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\onslide")
3369                 argbeg = find_token(document.body, "\\begin_inset Argument item:1", p, q)
3370                 if argbeg != -1:
3371                     argend = find_end_of_inset(document.body, argbeg)
3372                     if argend == -1:
3373                         document.warning("Malformed LyX document. Cannot find end of Overprint item argument!")
3374                         p += 1
3375                         continue
3376                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3377                     endPlain = find_end_of_layout(document.body, beginPlain)
3378                     content = document.body[beginPlain + 1 : endPlain]
3379                     # Adjust range end
3380                     endseq = endseq - len(document.body[argbeg : argend + 1])
3381                     # Remove arg inset
3382                     del document.body[argbeg : argend + 1]
3383                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3384                 endseq = endseq - len(document.body[p : p + 1]) + len(subst)
3385                 document.body[p : p + 1] = subst
3386             p = p + 1
3387
3388         i = endseq
3389
3390
3391 def revert_frametitle(document):
3392     " Reverts beamer frametitle layout to ERT "
3393     
3394     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3395     if document.textclass not in beamer_classes:
3396         return
3397
3398     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3399     i = 0
3400     while True:
3401         i = find_token(document.body, "\\begin_layout FrameTitle", i)
3402         if i == -1:
3403             return
3404         j = find_end_of_layout(document.body, i)
3405         if j == -1:
3406             document.warning("Malformed LyX document: Can't find end of FrameTitle layout")
3407             i += 1
3408             continue
3409         endlay = j
3410         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
3411         endlay += len(put_cmd_in_ert("}"))
3412         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\frametitle")
3413         for p in range(i, j):
3414             if p >= endlay:
3415                 break
3416             m = rx.match(document.body[p])
3417             if m:
3418                 argnr = m.group(1)
3419                 if argnr == "1":
3420                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3421                     endPlain = find_end_of_layout(document.body, beginPlain)
3422                     endInset = find_end_of_inset(document.body, p)
3423                     content = document.body[beginPlain + 1 : endPlain]
3424                     # Adjust range end
3425                     endlay = endlay - len(document.body[p : endInset + 1])
3426                     # Remove arg inset
3427                     del document.body[p : endInset + 1]
3428                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3429                 elif argnr == "2":
3430                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3431                     endPlain = find_end_of_layout(document.body, beginPlain)
3432                     endInset = find_end_of_inset(document.body, p)
3433                     content = document.body[beginPlain + 1 : endPlain]
3434                     # Adjust range end
3435                     endlay = endlay - len(document.body[p : endInset + 1])
3436                     # Remove arg inset
3437                     del document.body[p : endInset + 1]
3438                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3439                     
3440         subst += put_cmd_in_ert("{")
3441         document.body[i : i + 1] = subst
3442         i = endlay
3443
3444
3445 def convert_epigraph(document):
3446     " Converts memoir epigraph to new syntax "
3447     
3448     if document.textclass != "memoir":
3449         return
3450
3451     i = 0
3452     while True:
3453         i = find_token(document.body, "\\begin_layout Epigraph", i)
3454         if i == -1:
3455             return
3456         j = find_end_of_layout(document.body, i)
3457         if j == -1:
3458             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3459             i += 1
3460             continue
3461         endlay = j
3462         subst = list()
3463         ert = find_token(document.body, "\\begin_inset ERT", i, j)
3464         if ert != -1:
3465             endInset = find_end_of_inset(document.body, ert)
3466             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", ert)
3467             endPlain = find_end_of_layout(document.body, beginPlain)
3468             ertcont = beginPlain + 2
3469             if document.body[ertcont] == "}{":
3470                 # strip off the <
3471                 # Convert to ArgInset
3472                 endlay = endlay - 2 * len(document.body[j])
3473                 begsubst = ['\\begin_inset Argument post:1', 'status collapsed', '',
3474                             '\\begin_layout Plain Layout']
3475                 endsubst = ['\\end_layout', '', '\\end_inset', '', document.body[j]]
3476                 document.body[j : j + 1] = endsubst
3477                 document.body[endInset + 1 : endInset + 1] = begsubst
3478                 # Adjust range end
3479                 endlay += len(begsubst) + len(endsubst)
3480                 endlay = endlay - len(document.body[ert : endInset + 1])
3481                 del document.body[ert : endInset + 1]
3482                     
3483         i = endlay
3484
3485
3486 def revert_epigraph(document):
3487     " Reverts memoir epigraph argument to ERT "
3488     
3489     if document.textclass != "memoir":
3490         return
3491
3492     i = 0
3493     while True:
3494         i = find_token(document.body, "\\begin_layout Epigraph", i)
3495         if i == -1:
3496             return
3497         j = find_end_of_layout(document.body, i)
3498         if j == -1:
3499             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3500             i += 1
3501             continue
3502         endlay = j
3503         subst = list()
3504         p = find_token(document.body, "\\begin_layout Argument post:1", i, j)
3505         if p != -1:
3506             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3507             endPlain = find_end_of_layout(document.body, beginPlain)
3508             endInset = find_end_of_inset(document.body, p)
3509             content = document.body[beginPlain + 1 : endPlain]
3510             # Adjust range end
3511             endlay = endlay - len(document.body[p : endInset + 1])
3512             # Remove arg inset
3513             del document.body[p : endInset + 1]
3514             subst += put_cmd_in_ert("}{") + content
3515         else:
3516             subst += put_cmd_in_ert("}{")
3517                     
3518         document.body[j : j] = subst + document.body[j : j]
3519         i = endlay
3520
3521
3522 def convert_captioninsets(document):
3523     " Converts caption insets to new syntax "
3524     
3525     i = 0
3526     while True:
3527       i = find_token(document.body, "\\begin_inset Caption", i)
3528       if i == -1:
3529           return
3530       document.body[i] = "\\begin_inset Caption Standard"
3531       i += 1
3532
3533
3534 def revert_captioninsets(document):
3535     " Reverts caption insets to old syntax "
3536     
3537     i = 0
3538     while True:
3539       i = find_token(document.body, "\\begin_inset Caption Standard", i)
3540       if i == -1:
3541           return
3542       document.body[i] = "\\begin_inset Caption"
3543       i += 1
3544
3545
3546 def convert_captionlayouts(document):
3547     " Convert caption layouts to caption insets. "
3548
3549     caption_dict = {
3550         "Captionabove":  "Above",
3551         "Captionbelow":  "Below",
3552         "FigCaption"  :  "FigCaption",
3553         "Table_Caption" :  "Table",
3554         "CenteredCaption" : "Centered",
3555         "Bicaption" : "Bicaption",
3556         }
3557
3558     i = 0
3559     while True:
3560         i = find_token(document.body, "\\begin_layout", i)
3561         if i == -1:
3562             return
3563         val = get_value(document.body, "\\begin_layout", i)
3564         if val in caption_dict.keys():
3565             j = find_end_of_layout(document.body, i)
3566             if j == -1:
3567                 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3568                 return
3569
3570             document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""]
3571             document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout,
3572                                     "\\begin_inset Caption %s" % caption_dict[val], "",
3573                                     "\\begin_layout %s" % document.default_layout]
3574         i += 1
3575
3576
3577 def revert_captionlayouts(document):
3578     " Revert caption insets to caption layouts. "
3579     
3580     caption_dict = {
3581         "Above" : "Captionabove",
3582         "Below" : "Captionbelow",
3583         "FigCaption"  :  "FigCaption",
3584         "Table" : "Table_Caption",
3585         "Centered" : "CenteredCaption",
3586         "Bicaption" : "Bicaption",
3587         }
3588     
3589     i = 0
3590     rx = re.compile(r'^\\begin_inset Caption (\S+)$')
3591     while True:
3592         i = find_token(document.body, "\\begin_inset Caption", i)
3593         if i == -1:
3594             return
3595
3596         m = rx.match(document.body[i])
3597         val = ""
3598         if m:
3599             val = m.group(1)
3600         if val not in caption_dict.keys():
3601             i += 1
3602             continue
3603         
3604         # We either need to delete the previous \begin_layout line, or we
3605         # need to end the previous layout if this inset is not in the first
3606         # position of the paragraph.
3607         layout_before = find_token_backwards(document.body, "\\begin_layout", i)
3608         if layout_before == -1:
3609             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3610             return
3611         layout_line = document.body[layout_before]
3612         del_layout_before = True
3613         l = layout_before + 1
3614         while l < i:
3615             if document.body[l] != "":
3616                 del_layout_before = False
3617                 break
3618             l = l + 1
3619         if del_layout_before:
3620             del document.body[layout_before:i]
3621             i = layout_before
3622         else:
3623             document.body[i:i] = ["\\end_layout", ""]
3624             i = i + 2
3625
3626         # Find start of layout in the inset and end of inset
3627         j = find_token(document.body, "\\begin_layout", i)
3628         if j == -1:
3629             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3630             return
3631         k = find_end_of_inset(document.body, i)
3632         if k == -1:
3633             document.warning("Malformed LyX document: Missing `\\end_inset'.")
3634             return
3635
3636         # We either need to delete the following \end_layout line, or we need
3637         # to restart the old layout if this inset is not at the paragraph end.
3638         layout_after = find_token(document.body, "\\end_layout", k)
3639         if layout_after == -1:
3640             document.warning("Malformed LyX document: Missing `\\end_layout'.")
3641             return
3642         del_layout_after = True
3643         l = k + 1
3644         while l < layout_after:
3645             if document.body[l] != "":
3646                 del_layout_after = False
3647                 break
3648             l = l + 1
3649         if del_layout_after:
3650             del document.body[k+1:layout_after+1]
3651         else:
3652             document.body[k+1:k+1] = [layout_line, ""]
3653
3654         # delete \begin_layout and \end_inset and replace \begin_inset with
3655         # "\begin_layout XXX". This works because we can only have one
3656         # paragraph in the caption inset: The old \end_layout will be recycled.
3657         del document.body[k]
3658         if document.body[k] == "":
3659             del document.body[k]
3660         del document.body[j]
3661         if document.body[j] == "":
3662             del document.body[j]
3663         document.body[i] = "\\begin_layout %s" % caption_dict[val]
3664         if document.body[i+1] == "":
3665             del document.body[i+1]
3666         i += 1
3667
3668
3669 def revert_fragileframe(document):
3670     " Reverts beamer FragileFrame layout to ERT "
3671     
3672     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3673     if document.textclass not in beamer_classes:
3674         return
3675
3676     i = 0
3677     while True:
3678         i = find_token(document.body, "\\begin_layout FragileFrame", i)
3679         if i == -1:
3680             return
3681         # Find end of sequence
3682         j = find_end_of_sequence(document.body, i)
3683         if j == -1:
3684             document.warning("Malformed LyX document. Cannot find end of FragileFrame sequence!")
3685             i += 1
3686             continue
3687         endseq = j
3688         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{frame}")
3689         esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}")
3690         endseq = endseq + len(esubst) - len(document.body[j : j])
3691         if document.body[j] == "\\end_deeper":
3692             document.body[j : j] = [""] + esubst + ["", "\\end_layout"]
3693         else:
3694             document.body[j : j] = esubst
3695         for q in range(i, j):
3696             if document.body[q] == "\\begin_layout FragileFrame":
3697                 document.body[q] = "\\begin_layout %s" % document.default_layout
3698         r = i
3699         while r < j:
3700             if document.body[r] == "\\begin_deeper":
3701                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3702                 if s != -1:
3703                     document.body[r] = ""
3704                     document.body[s] = ""
3705                     r = s
3706                     continue
3707             r = r + 1
3708         for p in range(1, 5):
3709             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, j)
3710             if arg != -1:
3711                 if p == 1:
3712                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3713                     endPlain = find_end_of_layout(document.body, beginPlain)
3714                     endInset = find_end_of_inset(document.body, arg)
3715                     content = document.body[beginPlain + 1 : endPlain]
3716                     # Adjust range end
3717                     j = j - len(document.body[arg : endInset + 1])
3718                     # Remove arg inset
3719                     del document.body[arg : endInset + 1]
3720                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3721                 elif p == 2:
3722                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3723                     endPlain = find_end_of_layout(document.body, beginPlain)
3724                     endInset = find_end_of_inset(document.body, arg)
3725                     content = document.body[beginPlain + 1 : endPlain]
3726                     # Adjust range end
3727                     j = j - len(document.body[arg : endInset + 1])
3728                     # Remove arg inset
3729                     del document.body[arg : endInset + 1]
3730                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3731                 elif p == 3:
3732                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3733                     endPlain = find_end_of_layout(document.body, beginPlain)
3734                     endInset = find_end_of_inset(document.body, arg)
3735                     content = document.body[beginPlain + 1 : endPlain]
3736                     # Adjust range end
3737                     j = j - len(document.body[arg : endInset + 1])
3738                     # Remove arg inset
3739                     del document.body[arg : endInset + 1]
3740                     subst += put_cmd_in_ert("[fragile,") + content + put_cmd_in_ert("]")
3741                 elif p == 4:
3742                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3743                     endPlain = find_end_of_layout(document.body, beginPlain)
3744                     endInset = find_end_of_inset(document.body, arg)
3745                     content = document.body[beginPlain + 1 : endPlain]
3746                     # Adjust range end
3747                     j = j - len(document.body[arg : endInset + 1])
3748                     # Remove arg inset
3749                     del document.body[arg : endInset + 1]
3750                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3751             elif p == 3:
3752                 subst += put_cmd_in_ert("[fragile]")
3753                     
3754         document.body[i : i + 1] = subst
3755         i = j
3756
3757
3758 def revert_newframes(document):
3759     " Reverts beamer Frame and PlainFrame layouts to old forms "
3760     
3761     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3762     if document.textclass not in beamer_classes:
3763         return
3764
3765     frame_dict = {
3766         "Frame" : "BeginFrame",
3767         "PlainFrame" : "BeginPlainFrame",
3768         }
3769
3770     rx = re.compile(r'^\\begin_layout (\S+)$')
3771     i = 0
3772     while True:
3773         i = find_token(document.body, "\\begin_layout", i)
3774         if i == -1:
3775             return
3776
3777         m = rx.match(document.body[i])
3778         val = ""
3779         if m:
3780             val = m.group(1)
3781         if val not in frame_dict.keys():
3782             i += 1
3783             continue
3784         # Find end of sequence
3785         j = find_end_of_sequence(document.body, i)
3786         if j == -1:
3787             document.warning("Malformed LyX document. Cannot find end of Frame sequence!")
3788             i += 1
3789             continue
3790         endseq = j
3791         subst = ["\\begin_layout %s" % frame_dict[val]]
3792         esubst = ["\\begin_layout EndFrame", "", "\\end_layout"]
3793         endseq = endseq + len(esubst) - len(document.body[j : j])
3794         if document.body[j] == "\\end_deeper":
3795             document.body[j : j] = [""] + esubst
3796         else:
3797             document.body[j : j] = esubst
3798         for q in range(i, j):
3799             if document.body[q] == "\\begin_layout %s" % val:
3800                 document.body[q] = "\\begin_layout %s" % document.default_layout
3801         r = i
3802         while r < j:
3803             if document.body[r] == "\\begin_deeper":
3804                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3805                 if s != -1:
3806                     document.body[r] = ""
3807                     document.body[s] = ""
3808                     r = s
3809                     continue
3810             r = r + 1
3811         l = find_end_of_layout(document.body, i)
3812         for p in range(1, 5):
3813             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, l)
3814             if arg != -1:
3815                 if p == 1:
3816                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3817                     endPlain = find_end_of_layout(document.body, beginPlain)
3818                     endInset = find_end_of_inset(document.body, arg)
3819                     content = document.body[beginPlain + 1 : endPlain]
3820                     # Adjust range end
3821                     l = l - len(document.body[arg : endInset + 1])
3822                     # Remove arg inset
3823                     del document.body[arg : endInset + 1]
3824                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3825                 elif p == 2:
3826                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3827                     endPlain = find_end_of_layout(document.body, beginPlain)
3828                     endInset = find_end_of_inset(document.body, arg)
3829                     content = document.body[beginPlain + 1 : endPlain]
3830                     # Adjust range end
3831                     l = l - len(document.body[arg : endInset + 1])
3832                     # Remove arg inset
3833                     del document.body[arg : endInset + 1]
3834                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3835                 elif p == 3:
3836                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3837                     endPlain = find_end_of_layout(document.body, beginPlain)
3838                     endInset = find_end_of_inset(document.body, arg)
3839                     content = document.body[beginPlain + 1 : endPlain]
3840                     # Adjust range end
3841                     l = l - len(document.body[arg : endInset + 1])
3842                     # Remove arg inset
3843                     del document.body[arg : endInset + 1]
3844                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3845                 elif p == 4:
3846                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3847                     endPlain = find_end_of_layout(document.body, beginPlain)
3848                     endInset = find_end_of_inset(document.body, arg)
3849                     content = document.body[beginPlain + 1 : endPlain]
3850                     # Adjust range end
3851                     l = l - len(document.body[arg : endInset + 1])
3852                     # Remove arg inset
3853                     del document.body[arg : endInset + 1]
3854                     subst += content
3855                     
3856         document.body[i : i + 1] = subst
3857         i = j
3858
3859 # known encodings that do not change their names (same LyX and LaTeX names)
3860 known_enc_tuple = ("auto", "default", "ansinew", "applemac", "armscii8", "ascii",
3861     "cp437", "cp437de", "cp850", "cp852", "cp855", "cp858", "cp862", "cp865", "cp866",
3862     "cp1250", "cp1251", "cp1252", "cp1255", "cp1256", "cp1257", "koi8-r", "koi8-u",
3863     "pt154", "pt254", "tis620-0", "utf8", "utf8x", "utf8-plain")
3864
3865 def convert_encodings(document):
3866     "Use the LyX names of the encodings instead of the LaTeX names."
3867     LaTeX2LyX_enc_dict = {
3868         "8859-6":     "iso8859-6",
3869         "8859-8":     "iso8859-8",
3870         "Bg5":        "big5",
3871         "euc":        "euc-jp-platex",
3872         "EUC-JP":     "euc-jp",
3873         "EUC-TW":     "euc-tw",
3874         "GB":         "euc-cn",
3875         "GBK":        "gbk",
3876         "iso88595":   "iso8859-5",
3877         "iso-8859-7": "iso8859-7",
3878         "JIS":        "jis",
3879         "jis":        "jis-platex",
3880         "KS":         "euc-kr",
3881         "l7xenc":     "iso8859-13",
3882         "latin1":     "iso8859-1",
3883         "latin2":     "iso8859-2",
3884         "latin3":     "iso8859-3",
3885         "latin4":     "iso8859-4",
3886         "latin5":     "iso8859-9",
3887         "latin9":     "iso8859-15",
3888         "latin10":    "iso8859-16",
3889         "SJIS":       "shift-jis",
3890         "sjis":       "shift-jis-platex",
3891         "UTF8":       "utf8-cjk"
3892     }
3893     i = find_token(document.header, "\\inputencoding" , 0)
3894     if i == -1:
3895         return
3896     val = get_value(document.header, "\\inputencoding", i)
3897     if val in LaTeX2LyX_enc_dict.keys():
3898         document.header[i] = "\\inputencoding %s" % LaTeX2LyX_enc_dict[val]
3899     elif val not in known_enc_tuple:
3900         document.warning("Ignoring unknown input encoding: `%s'" % val)
3901
3902
3903 def revert_encodings(document):
3904     """Revert to using the LaTeX names of the encodings instead of the LyX names.
3905     Also revert utf8-platex to sjis, the language default when using Japanese.
3906     """
3907     LyX2LaTeX_enc_dict = {
3908         "big5":             "Bg5",
3909         "euc-cn":           "GB",
3910         "euc-kr":           "KS",
3911         "euc-jp":           "EUC-JP",
3912         "euc-jp-platex":    "euc",
3913         "euc-tw":           "EUC-TW",
3914         "gbk":              "GBK",
3915         "iso8859-1":        "latin1",
3916         "iso8859-2":        "latin2",
3917         "iso8859-3":        "latin3",
3918         "iso8859-4":        "latin4",
3919         "iso8859-5":        "iso88595",
3920         "iso8859-6":        "8859-6",
3921         "iso8859-7":        "iso-8859-7",
3922         "iso8859-8":        "8859-8",
3923         "iso8859-9":        "latin5",
3924         "iso8859-13":       "l7xenc",
3925         "iso8859-15":       "latin9",
3926         "iso8859-16":       "latin10",
3927         "jis":              "JIS",
3928         "jis-platex":       "jis",
3929         "shift-jis":        "SJIS",
3930         "shift-jis-platex": "sjis",
3931         "utf8-cjk":         "UTF8",
3932         "utf8-platex":      "sjis"
3933     }
3934     i = find_token(document.header, "\\inputencoding" , 0)
3935     if i == -1:
3936         return
3937     val = get_value(document.header, "\\inputencoding", i)
3938     if val in LyX2LaTeX_enc_dict.keys():
3939         document.header[i] = "\\inputencoding %s" % LyX2LaTeX_enc_dict[val]
3940     elif val not in known_enc_tuple:
3941         document.warning("Ignoring unknown input encoding: `%s'" % val)
3942
3943
3944 def revert_IEEEtran_3(document):
3945   '''
3946   Reverts Flex Insets to TeX-code
3947   '''
3948   if document.textclass == "IEEEtran":
3949     h = 0
3950     i = 0
3951     j = 0
3952     while True:
3953       if h != -1:
3954         h = find_token(document.body, "\\begin_inset Flex Author Mark", h)
3955       if h != -1:
3956         endh = find_end_of_inset(document.body, h)
3957         document.body[endh - 2 : endh + 1] = put_cmd_in_ert("}")
3958         document.body[h : h + 4] = put_cmd_in_ert("\\IEEEauthorrefmark{")
3959         h = h + 5
3960       if i != -1:
3961         i = find_token(document.body, "\\begin_inset Flex Author Name", i)
3962       if i != -1:
3963         endi = find_end_of_inset(document.body, i)
3964         document.body[endi - 2 : endi + 1] = put_cmd_in_ert("}")
3965         document.body[i : i + 4] = put_cmd_in_ert("\\IEEEauthorblockN{")
3966         i = i + 5
3967       if j != -1:
3968         j = find_token(document.body, "\\begin_inset Flex Author Affiliation", j)
3969       if j != -1:
3970         endj = find_end_of_inset(document.body, j)
3971         document.body[endj - 2 : endj + 1] = put_cmd_in_ert("}")
3972         document.body[j : j + 4] = put_cmd_in_ert("\\IEEEauthorblockA{")
3973         j = j + 5
3974       if i == -1 and j == -1 and h == -1:
3975         return
3976
3977
3978 def revert_kurier_fonts(document):
3979   " Revert kurier font definition to LaTeX "
3980   
3981   i = find_token(document.header, "\\font_math", 0)
3982   if i != -1:
3983     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3984       val = get_value(document.header, "\\font_math", i)
3985       if val == "kurier-math":
3986         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
3987           "\\usepackage[math]{kurier}\n" \
3988           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
3989         document.header[i] = "\\font_math auto"
3990   
3991   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3992     kurier_fonts = ["kurier", "kurierc", "kurierl", "kurierlc"]
3993     k = find_token(document.header, "\\font_sans kurier", 0)
3994     if k != -1:
3995       sf = get_value(document.header, "\\font_sans", k)
3996       if sf in kurier_fonts:
3997         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
3998         document.header[k] = "\\font_sans default"
3999
4000 def revert_iwona_fonts(document):
4001   " Revert iwona font definition to LaTeX "
4002   
4003   i = find_token(document.header, "\\font_math", 0)
4004   if i != -1:
4005     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
4006       val = get_value(document.header, "\\font_math", i)
4007       if val == "iwona-math":
4008         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
4009           "\\usepackage[math]{iwona}\n" \
4010           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
4011         document.header[i] = "\\font_math auto"
4012   
4013   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
4014     iwona_fonts = ["iwona", "iwonac", "iwonal", "iwonalc"]
4015     k = find_token(document.header, "\\font_sans iwona", 0)
4016     if k != -1:
4017       sf = get_value(document.header, "\\font_sans", k)
4018       if sf in iwona_fonts:
4019         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
4020         document.header[k] = "\\font_sans default"
4021
4022
4023 def revert_new_libertines(document):
4024     " Revert new libertine font definition to LaTeX "
4025   
4026     if find_token(document.header, "\\use_non_tex_fonts true", 0) != -1:
4027         return
4028
4029     i = find_token(document.header, "\\font_typewriter libertine-mono", 0)
4030     if i != -1:
4031         preamble = "\\usepackage"
4032         sc = find_token(document.header, "\\font_tt_scale", 0)
4033         if sc != -1:
4034             scval = get_value(document.header, "\\font_tt_scale", sc)
4035             if scval != "100":
4036                 preamble += "[scale=%f]" % (float(scval) / 100)
4037                 document.header[sc] = "\\font_tt_scale 100"
4038         preamble += "{libertineMono-type1}"
4039         add_to_preamble(document, [preamble])
4040         document.header[i] = "\\font_typewriter default"
4041    
4042     k = find_token(document.header, "\\font_sans biolinum", 0)
4043     if k != -1:
4044         preamble = "\\usepackage"
4045         options = ""
4046         j = find_token(document.header, "\\font_osf true", 0)
4047         if j != -1:
4048             options += "osf"
4049         else:
4050             options += "lining"
4051         sc = find_token(document.header, "\\font_sf_scale", 0)
4052         if sc != -1:
4053             scval = get_value(document.header, "\\font_sf_scale", sc)
4054             if scval != "100":
4055                 options += ",scale=%f" % (float(scval) / 100)
4056                 document.header[sc] = "\\font_sf_scale 100"
4057         if options != "":
4058             preamble += "[" + options +"]"
4059         preamble += "{biolinum-type1}"
4060         add_to_preamble(document, [preamble])
4061         document.header[k] = "\\font_sans default"
4062
4063
4064 def convert_lyxframes(document):
4065     " Converts old beamer frames to new style "
4066     
4067     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
4068     if document.textclass not in beamer_classes:
4069         return
4070    
4071     framebeg = ["BeginFrame", "BeginPlainFrame"]
4072     frameend = ["Frame", "PlainFrame", "EndFrame", "BeginFrame", "BeginPlainFrame", "AgainFrame",
4073                 "Section", "Section*", "Subsection", "Subsection*", "Subsubsection", "Subsubsection*"]
4074     for lay in framebeg:
4075         i = 0
4076         while True:
4077             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
4078             if i == -1:
4079                 break
4080             parent = get_containing_layout(document.body, i)
4081             if parent == False or parent[1] != i:
4082                 document.warning("Wrong parent layout!")
4083                 i += 1
4084                 continue
4085             frametype = parent[0]
4086             j = parent[2]
4087             parbeg = parent[3]
4088             if i != -1:
4089                 # Step I: Convert ERT arguments
4090                 # FIXME: See restrictions in convert_beamerframeargs method
4091                 ertend = convert_beamerframeargs(document, i, parbeg)
4092                 if ertend == -1:
4093                     break
4094                 # Step II: Now rename the layout and convert the title to an argument
4095                 j = find_end_of_layout(document.body, i)
4096                 document.body[j : j + 1] = ['\\end_layout', '', '\\end_inset', '', '\\end_layout']
4097                 if lay == "BeginFrame":
4098                     document.body[i] = "\\begin_layout Frame"
4099                 else:
4100                     document.body[i] = "\\begin_layout PlainFrame"
4101                 document.body[ertend + 1 : ertend + 1] = ['\\begin_inset Argument 4',
4102                                                 'status open', '', '\\begin_layout Plain Layout']
4103                 # Step III: find real frame end
4104                 j = j + 8
4105                 jj = j
4106                 while True:
4107                     fend = find_token(document.body, "\\begin_layout", jj)
4108                     if fend == -1:
4109                         document.warning("Malformed LyX document: No real frame end!")
4110                         return
4111                     val = get_value(document.body, "\\begin_layout", fend)
4112                     if val not in frameend:
4113                         jj = fend + 1
4114                         continue
4115                     old = document.body[fend]
4116                     if val == frametype:
4117                         document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
4118                     # consider explicit EndFrames between two identical frame types
4119                     elif val == "EndFrame":
4120                         nextlayout = find_token(document.body, "\\begin_layout", fend + 1)
4121                         if nextlayout != -1 and get_value(document.body, "\\begin_layout", nextlayout) == frametype:
4122                             document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
4123                         else:
4124                             document.body[fend : fend] = ['\\end_deeper']
4125                     else:
4126                         document.body[fend : fend] = ['\\end_deeper']
4127                     document.body[j + 1 : j + 1] = ['', '\\begin_deeper']
4128                     break
4129             i = j
4130
4131
4132 def remove_endframes(document):
4133     " Remove deprecated beamer endframes "
4134     
4135     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
4136     if document.textclass not in beamer_classes:
4137         return
4138    
4139     i = 0
4140     while True:
4141         i = find_token_exact(document.body, "\\begin_layout EndFrame", i)
4142         if i == -1:
4143             break
4144         j = find_end_of_layout(document.body, i)
4145         if j == -1:
4146             document.warning("Malformed LyX document: Missing \\end_layout to EndFrame")
4147             i += 1
4148             continue
4149         del document.body[i : j + 1]
4150
4151
4152 def revert_powerdot_flexes(document):
4153     " Reverts powerdot flex insets "
4154     
4155     if document.textclass != "powerdot":
4156         return
4157
4158     flexes = {"Onslide" : "\\onslide",
4159               "Onslide*" : "\\onslide*",
4160               "Onslide+" : "\\onslide+"}
4161     rx = re.compile(r'^\\begin_inset Flex (.+)$')
4162
4163     i = 0
4164     while True:
4165         i = find_token(document.body, "\\begin_inset Flex", i)
4166         if i == -1:
4167             return
4168         m = rx.match(document.body[i])
4169         if m:
4170             flextype = m.group(1)
4171             z = find_end_of_inset(document.body, i)
4172             if z == -1:
4173                 document.warning("Can't find end of Flex " + flextype + " inset.")
4174                 i += 1
4175                 continue
4176             if flextype in flexes:
4177                 pre = put_cmd_in_ert(flexes[flextype])
4178                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
4179                 if arg != -1:
4180                     argend = find_end_of_inset(document.body, arg)
4181                     if argend == -1:
4182                         document.warning("Can't find end of Argument!")
4183                         i += 1
4184                         continue
4185                     # Find containing paragraph layout
4186                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
4187                     endPlain = find_end_of_layout(document.body, beginPlain)
4188                     argcontent = document.body[beginPlain + 1 : endPlain]
4189                     # Adjust range end
4190                     z = z - len(document.body[arg : argend + 1])
4191                     # Remove arg inset
4192                     del document.body[arg : argend + 1]
4193                     pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
4194                 pre += put_cmd_in_ert("{")
4195                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4196                 endPlain = find_end_of_layout(document.body, beginPlain)
4197                 # Adjust range end
4198                 z = z - len(document.body[i : beginPlain + 1])
4199                 z += len(pre)
4200                 document.body[i : beginPlain + 1] = pre
4201                 post = put_cmd_in_ert("}")
4202                 document.body[z - 2 : z + 1] = post     
4203         i += 1
4204
4205
4206 def revert_powerdot_pause(document):
4207     " Reverts powerdot pause layout to ERT "
4208     
4209     if document.textclass != "powerdot":
4210         return
4211
4212     i = 0
4213     while True:
4214         i = find_token(document.body, "\\begin_layout Pause", i)
4215         if i == -1:
4216             return
4217         j = find_end_of_layout(document.body, i)
4218         if j == -1:
4219             document.warning("Malformed LyX document: Can't find end of Pause layout")
4220             i += 1
4221             continue
4222         endlay = j
4223         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\pause")
4224         for p in range(i, j):
4225             if p >= endlay:
4226                 break
4227             arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
4228             if arg != -1:
4229                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4230                 endPlain = find_end_of_layout(document.body, beginPlain)
4231                 endInset = find_end_of_inset(document.body, p)
4232                 content = document.body[beginPlain + 1 : endPlain]
4233                 # Adjust range end
4234                 endlay = endlay - len(document.body[p : endInset + 1])
4235                 # Remove arg inset
4236                 del document.body[p : endInset + 1]
4237                 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4238                     
4239         document.body[i : i + 1] = subst
4240         i = endlay
4241
4242
4243 def revert_powerdot_itemargs(document):
4244     " Reverts powerdot item arguments to ERT "
4245     
4246     if document.textclass != "powerdot":
4247         return
4248
4249     i = 0
4250     list_layouts = ["Itemize", "ItemizeType1", "Enumerate", "EnumerateType1"]
4251     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4252
4253     while True:
4254         i = find_token(document.body, "\\begin_inset Argument", i)
4255         if i == -1:
4256             return
4257         # Find containing paragraph layout
4258         parent = get_containing_layout(document.body, i)
4259         if parent == False:
4260             document.warning("Malformed LyX document: Can't find parent paragraph layout")
4261             i += 1
4262             continue
4263         parbeg = parent[1]
4264         parend = parent[2]
4265         realparbeg = parent[3]
4266         layoutname = parent[0]
4267         realparend = parend
4268         for p in range(parbeg, parend):
4269             if p >= realparend:
4270                 i = realparend
4271                 break
4272             if layoutname in list_layouts:
4273                 m = rx.match(document.body[p])
4274                 if m:
4275                     argnr = m.group(1)
4276                     if argnr == "item:1":
4277                         j = find_end_of_inset(document.body, i)
4278                         # Find containing paragraph layout
4279                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4280                         endPlain = find_end_of_layout(document.body, beginPlain)
4281                         content = document.body[beginPlain + 1 : endPlain]
4282                         del document.body[i:j+1]
4283                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4284                         document.body[realparbeg : realparbeg] = subst
4285                     elif argnr == "item:2":
4286                         j = find_end_of_inset(document.body, i)
4287                         # Find containing paragraph layout
4288                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4289                         endPlain = find_end_of_layout(document.body, beginPlain)
4290                         content = document.body[beginPlain + 1 : endPlain]
4291                         del document.body[i:j+1]
4292                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
4293                         document.body[realparbeg : realparbeg] = subst
4294         
4295         i = realparend
4296
4297
4298 def revert_powerdot_columns(document):
4299     " Reverts powerdot twocolumn to TeX-code "
4300     if document.textclass != "powerdot":
4301         return
4302
4303     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4304     i = 0
4305     while True:
4306         i = find_token(document.body, "\\begin_layout Twocolumn", i)
4307         if i == -1:
4308             return
4309         j = find_end_of_layout(document.body, i)
4310         if j == -1:
4311             document.warning("Malformed LyX document: Can't find end of Twocolumn layout")
4312             i += 1
4313             continue
4314         endlay = j
4315         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
4316         endlay += len(put_cmd_in_ert("}"))
4317         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\twocolumn")
4318         for p in range(i, j):
4319             if p >= endlay:
4320                 break
4321             m = rx.match(document.body[p])
4322             if m:
4323                 argnr = m.group(1)
4324                 if argnr == "1":
4325                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4326                     endPlain = find_end_of_layout(document.body, beginPlain)
4327                     endInset = find_end_of_inset(document.body, p)
4328                     content = document.body[beginPlain + 1 : endPlain]
4329                     # Adjust range end
4330                     endlay = endlay - len(document.body[p : endInset + 1])
4331                     # Remove arg inset
4332                     del document.body[p : endInset + 1]
4333                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4334                 elif argnr == "2":
4335                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4336                     endPlain = find_end_of_layout(document.body, beginPlain)
4337                     endInset = find_end_of_inset(document.body, p)
4338                     content = document.body[beginPlain + 1 : endPlain]
4339                     # Adjust range end
4340                     endlay = endlay - len(document.body[p : endInset + 1])
4341                     # Remove arg inset
4342                     del document.body[p : endInset + 1]
4343                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
4344                     
4345         subst += put_cmd_in_ert("{")
4346         document.body[i : i + 1] = subst
4347         i = endlay
4348
4349
4350 def revert_mbox_fbox(document):
4351     'Convert revert mbox/fbox boxes to TeX-code'
4352     i = 0
4353     while True:
4354         i = find_token(document.body, "\\begin_inset Box", i)
4355         if i == -1:
4356             return
4357         j = find_token(document.body, "width", i)
4358         if j != i + 7:
4359             document.warning("Malformed LyX document: Can't find box width")
4360             return
4361         width = get_value(document.body, "width", j)
4362         k = find_end_of_inset(document.body, j)
4363         if k == -1:
4364             document.warning("Malformed LyX document: Can't find end of box inset")
4365             i += 1
4366             continue
4367         BeginLayout = find_token(document.body, "\\begin_layout Plain Layout", j)
4368         EndLayout = find_end_of_layout(document.body, BeginLayout)
4369         # replace if width is ""
4370         if (width == '""'):
4371             document.body[EndLayout:k + 1] = put_cmd_in_ert("}")
4372             if document.body[i] == "\\begin_inset Box Frameless":
4373                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\mbox{")
4374             if document.body[i] == "\\begin_inset Box Boxed":
4375                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\fbox{")
4376         i += 1
4377
4378
4379 def revert_starred_caption(document):
4380     " Reverts unnumbered longtable caption insets "
4381     
4382     i = 0
4383     while True:
4384       i = find_token(document.body, "\\begin_inset Caption LongTableNoNumber", i)
4385       if i == -1:
4386           return
4387       # This is not equivalent, but since the caption inset is a full blown
4388       # text inset a true conversion to ERT is too difficult.
4389       document.body[i] = "\\begin_inset Caption Standard"
4390       i += 1
4391
4392
4393 def revert_forced_local_layout(document):
4394     i = 0
4395     while True:
4396         i = find_token(document.header, "\\begin_forced_local_layout", i)
4397         if i == -1:
4398             return
4399         j = find_end_of(document.header, i, "\\begin_forced_local_layout", "\\end_forced_local_layout")
4400         if j == -1:
4401             # this should not happen
4402             break
4403         regexp = re.compile(r'\s*forcelocal', re.IGNORECASE)
4404         k = find_re(document.header, regexp, i, j)
4405         while k != -1:
4406             del document.header[k]
4407             j = j - 1
4408             k = find_re(document.header, regexp, i, j)
4409         k = find_token(document.header, "\\begin_local_layout", 0)
4410         if k == -1:
4411             document.header[i] = "\\begin_local_layout"
4412             document.header[j] = "\\end_local_layout"
4413         else:
4414             l = find_end_of(document.header, k, "\\begin_local_layout", "\\end_local_layout")
4415             if j == -1:
4416                 # this should not happen
4417                 break
4418             lines = document.header[i+1 : j]
4419             if k > i:
4420                 document.header[k+1 : k+1] = lines
4421                 document.header[i   : j  ] = []
4422             else:
4423                 document.header[i   : j  ] = []
4424                 document.header[k+1 : k+1] = lines
4425
4426
4427 def revert_aa1(document):
4428   " Reverts InsetArguments of aa to TeX-code "
4429   if document.textclass == "aa":
4430     i = 0
4431     while True:
4432       if i != -1:
4433         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4434       if i != -1:
4435         revert_Argument_to_TeX_brace(document, i, 0, 1, 4, False, False)
4436         i += 1
4437       if i == -1:
4438         return
4439
4440
4441 def revert_aa2(document):
4442   " Reverts InsetArguments of aa to TeX-code "
4443   if document.textclass == "aa":
4444     i = 0
4445     while True:
4446       if i != -1:
4447         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4448       if i != -1:
4449         document.body[i] = "\\begin_layout Abstract"
4450         i += 1
4451       if i == -1:
4452         return
4453
4454
4455 def revert_tibetan(document):
4456     "Set the document language for Tibetan to English" 
4457
4458     if document.language == "tibetan":
4459         document.language = "english"
4460         i = find_token(document.header, "\\language", 0) 
4461         if i != -1: 
4462             document.header[i] = "\\language english" 
4463     j = 0
4464     while j < len(document.body): 
4465         j = find_token(document.body, "\\lang tibetan", j)
4466         if j != -1:
4467             document.body[j] = document.body[j].replace("\\lang tibetan", "\\lang english")
4468             j += 1
4469         else:
4470             j = len(document.body)
4471
4472
4473 #############
4474 #
4475 # Chunk stuff
4476 #
4477 #############
4478
4479 # The idea here is that we will have a sequence of chunk paragraphs.
4480 # We want to convert them to paragraphs in one or several chunk insets.
4481 # Individual chunks are terminated by the character @ on the last line.
4482 # This line will be discarded, and following lines are treated as new
4483 # chunks, which go into their own insets.
4484 # The first line of a chunk should look like: <<CONTENT>>=
4485 # We will discard the delimiters, and put the CONTENT into the
4486 # optional argument of the inset, if the CONTENT is non-empty.
4487 def convert_chunks(document):
4488     first_re = re.compile(r'<<(.*)>>=(.*)')
4489     file_pos = 0
4490     while True:
4491         # find start of a block of chunks
4492         i = find_token(document.body, "\\begin_layout Chunk", file_pos)
4493         if i == -1:
4494             return
4495         start = i
4496         end = -1
4497         contents = []
4498         chunk_started = False
4499
4500         while True:
4501             # process the one we just found
4502             j = find_end_of_layout(document.body, i)
4503             if j == -1:
4504                 document.warning("Malformed LyX documents. Can't find end of Chunk layout!")
4505                 # there is no point continuing, as we will run into the same error again.
4506                 return
4507             this_chunk = "".join(document.body[i + 1:j])
4508             
4509             # there may be empty lines between chunks
4510             # we just skip them.
4511             if not chunk_started:
4512                 if this_chunk != "":
4513                     # new chunk starts
4514                     chunk_started = True
4515             
4516             if chunk_started:
4517                 contents.append(document.body[i + 1:j])
4518
4519             # look for potential chunk terminator
4520             # on the last line of the chunk paragraph            
4521             if document.body[j - 1] == "@":
4522                 break
4523
4524             # look for subsequent chunk paragraph
4525             i = find_token(document.body, "\\begin_layout", j)
4526             if i == -1:
4527                 break
4528
4529             if get_value(document.body, "\\begin_layout", i) != "Chunk":
4530                 break
4531
4532         file_pos = end = j + 1
4533         
4534         # The last chunk should simply have an "@" in it
4535         # or at least end with "@" (can happen if @ is
4536         # preceded by a newline)
4537         lastpar = ''.join(contents[-1])
4538         if not lastpar.endswith("@"):
4539             document.warning("Unexpected chunk content: chunk not terminated by '@'!")
4540             continue
4541
4542         if lastpar == "@":
4543             # chunk par only contains "@". Just drop it.
4544             contents.pop()
4545         else:
4546             # chunk par contains more. Only drop the "@".
4547             contents[-1].pop()
4548
4549         # The first line should look like: <<CONTENT>>=
4550         # We want the CONTENT
4551         optarg = ' '.join(contents[0])
4552         optarg.strip()
4553         # We can already have real chunk content in
4554         # the first par (separated from the options by a newline).
4555         # We collect such stuff to re-insert it later.
4556         postoptstuff = []
4557         
4558         match = first_re.search(optarg)
4559         if match:
4560             optarg = match.groups()[0]
4561             if match.groups()[1] != "":
4562                 postopt = False
4563                 for c in contents[0]:
4564                     if c.endswith(">>="):
4565                         postopt = True
4566                         continue
4567                     if postopt:
4568                         postoptstuff.append(c)
4569             # We have stripped everything. This can be deleted.
4570             contents.pop(0)
4571
4572         newstuff = ['\\begin_layout Standard',
4573                     '\\begin_inset Flex Chunk',
4574                     'status open', '',
4575                     '\\begin_layout Plain Layout', '']
4576
4577         # If we have a non-empty optional argument, insert it.
4578         if match and optarg != "":
4579             newstuff.extend(
4580                 ['\\begin_inset Argument 1',
4581                  'status open', '',
4582                  '\\begin_layout Plain Layout',
4583                  optarg,
4584                  '\\end_layout', '',
4585                  '\\end_inset', ''])
4586
4587         # Since we already opened a Plain layout, the first paragraph
4588         # does not need to do that.
4589         did_one_par = False
4590         if postoptstuff:
4591             newstuff.extend(postoptstuff)
4592             newstuff.append('\\end_layout')
4593             did_one_par = True
4594         for c in contents:
4595             if did_one_par:
4596                 newstuff.extend(['', '\\begin_layout Plain Layout', ''])
4597             else:
4598                 did_one_par = True
4599             newstuff.extend(c)
4600             newstuff.append('\\end_layout')
4601
4602         newstuff.extend(['', '\\end_inset', '', '\\end_layout', ''])
4603
4604         document.body[start:end] = newstuff
4605
4606         file_pos += len(newstuff) - (end - start)
4607
4608
4609 def revert_chunks(document):
4610     i = 0
4611     while True:
4612         i = find_token(document.body, "\\begin_inset Flex Chunk", i)
4613         if i == -1:
4614             return
4615
4616         iend = find_end_of_inset(document.body, i)
4617         if iend == -1:
4618             document.warning("Can't find end of Chunk!")
4619             i += 1
4620             continue
4621
4622         # Look for optional argument
4623         have_optarg = False
4624         ostart = find_token(document.body, "\\begin_inset Argument 1", i, iend)
4625         if ostart != -1:
4626             oend = find_end_of_inset(document.body, ostart)
4627             k = find_token(document.body, "\\begin_layout Plain Layout", ostart, oend)
4628             if k == -1:
4629                 document.warning("Malformed LyX document: Can't find argument contents!")
4630             else:
4631                 m = find_end_of_layout(document.body, k)
4632                 optarg = "".join(document.body[k+1:m])
4633                 have_optarg = True
4634
4635             # We now remove the optional argument, so we have something
4636             # uniform on which to work
4637             document.body[ostart : oend + 1] = []
4638             # iend is now invalid
4639             iend = find_end_of_inset(document.body, i)
4640
4641         retval = get_containing_layout(document.body, i)
4642         if not retval:
4643             document.warning("Can't find containing layout for Chunk!")
4644             i = iend
4645             continue
4646         (lname, lstart, lend, pstart)  = retval
4647         # we now want to work through the various paragraphs, and collect their contents
4648         parlist = []
4649         k = i
4650         while True:
4651             k = find_token(document.body, "\\begin_layout Plain Layout", k, lend)
4652             if k == -1:
4653                 break
4654             j = find_end_of_layout(document.body, k)
4655             if j == -1:
4656                 document.warning("Can't find end of layout inside chunk!")
4657                 break
4658             parlist.append(document.body[k+1:j])
4659             k = j
4660         # we now need to wrap all of these paragraphs in chunks
4661         newlines = []
4662         if have_optarg:
4663             newlines.extend(["\\begin_layout Chunk", "", "<<" + optarg + ">>=", "\\end_layout", ""])
4664         for stuff in parlist:
4665             newlines.extend(["\\begin_layout Chunk"] + stuff + ["\\end_layout", ""])
4666         newlines.extend(["\\begin_layout Chunk", "", "@", "\\end_layout", ""])
4667         # replace old content with new content
4668         document.body[lstart : lend + 1] = newlines
4669         i = lstart + len(newlines)
4670         
4671
4672 ##
4673 # Conversion hub
4674 #
4675
4676 supported_versions = ["2.1.0","2.1"]
4677 convert = [
4678            [414, []],
4679            [415, [convert_undertilde]],
4680            [416, []],
4681            [417, [convert_japanese_encodings]],
4682            [418, [convert_justification]],
4683            [419, []],
4684            [420, [convert_biblio_style]],
4685            [421, [convert_longtable_captions]],
4686            [422, [convert_use_packages]],
4687            [423, [convert_use_mathtools]],
4688            [424, [convert_cite_engine_type]],
4689            # No convert_cancel, since cancel will be loaded automatically
4690            # in format 425 without any possibility to switch it off.
4691            # This has been fixed in format 464.
4692            [425, []],
4693            [426, []],
4694            [427, []],
4695            [428, [convert_cell_rotation]],
4696            [429, [convert_table_rotation]],
4697            [430, [convert_listoflistings]],
4698            [431, [convert_use_amssymb]],
4699            [432, []],
4700            [433, [convert_armenian]],
4701            [434, []],
4702            [435, []],
4703            [436, []],
4704            [437, []],
4705            [438, []],
4706            [439, []],
4707            [440, []],
4708            [441, [convert_mdnomath]],
4709            [442, []],
4710            [443, []],
4711            [444, []],
4712            [445, []],
4713            [446, [convert_latexargs]],
4714            [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV, convert_Initials, convert_ModernCV]],
4715            [448, [convert_literate]],
4716            [449, []],
4717            [450, []],
4718            [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]],
4719            [452, [convert_beamerblocks]],
4720            [453, [convert_use_stmaryrd]],
4721            [454, [convert_overprint]],
4722            [455, []],
4723            [456, [convert_epigraph]],
4724            [457, [convert_use_stackrel]],
4725            [458, [convert_captioninsets, convert_captionlayouts]],
4726            [459, []],
4727            [460, []],
4728            [461, []],
4729            [462, []],
4730            [463, [convert_encodings]],
4731            [464, [convert_use_cancel]],
4732            [465, [convert_lyxframes, remove_endframes]],
4733            [466, []],
4734            [467, []],
4735            [468, []],
4736            [469, []],
4737            [470, []],
4738            [471, [convert_cite_engine_type_default]],
4739            [472, []],
4740            [473, []],
4741            [474, [convert_chunks, cleanup_beamerargs]],
4742           ]
4743
4744 revert =  [
4745            [473, [revert_chunks]],
4746            [472, [revert_tibetan]],
4747            [471, [revert_aa1,revert_aa2]],
4748            [470, [revert_cite_engine_type_default]],
4749            [469, [revert_forced_local_layout]],
4750            [468, [revert_starred_caption]],
4751            [467, [revert_mbox_fbox]],
4752            [466, [revert_iwona_fonts]],
4753            [465, [revert_powerdot_flexes, revert_powerdot_pause, revert_powerdot_itemargs, revert_powerdot_columns]],
4754            [464, []],
4755            [463, [revert_use_cancel]],
4756            [462, [revert_encodings]],
4757            [461, [revert_new_libertines]],
4758            [460, [revert_kurier_fonts]],
4759            [459, [revert_IEEEtran_3]],
4760            [458, [revert_fragileframe, revert_newframes]],
4761            [457, [revert_captioninsets, revert_captionlayouts]],
4762            [456, [revert_use_stackrel]],
4763            [455, [revert_epigraph]],
4764            [454, [revert_frametitle]],
4765            [453, [revert_overprint]],
4766            [452, [revert_use_stmaryrd]],
4767            [451, [revert_beamerblocks]],
4768            [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
4769            [449, [revert_garamondx, revert_garamondx_newtxmath]],
4770            [448, [revert_itemargs]],
4771            [447, [revert_literate]],
4772            [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]],
4773            [445, [revert_latexargs]],
4774            [444, [revert_uop]],
4775            [443, [revert_biolinum]],
4776            [442, []],
4777            [441, [revert_newtxmath]],
4778            [440, [revert_mdnomath]],
4779            [439, [revert_mathfonts]],
4780            [438, [revert_minionpro]],
4781            [437, [revert_ipadeco, revert_ipachar]],
4782            [436, [revert_texgyre]],
4783            [435, [revert_mathdesign]],
4784            [434, [revert_txtt]],
4785            [433, [revert_libertine]],
4786            [432, [revert_armenian]],
4787            [431, [revert_languages, revert_ancientgreek]],
4788            [430, [revert_use_amssymb]],
4789            [429, [revert_listoflistings]],
4790            [428, [revert_table_rotation]],
4791            [427, [revert_cell_rotation]],
4792            [426, [revert_tipa]],
4793            [425, [revert_verbatim]],
4794            [424, [revert_cancel]],
4795            [423, [revert_cite_engine_type]],
4796            [422, [revert_use_mathtools]],
4797            [421, [revert_use_packages]],
4798            [420, [revert_longtable_captions]],
4799            [419, [revert_biblio_style]],
4800            [418, [revert_australian]],
4801            [417, [revert_justification]],
4802            [416, [revert_japanese_encodings]],
4803            [415, [revert_negative_space, revert_math_spaces]],
4804            [414, [revert_undertilde]],
4805            [413, [revert_visible_space]]
4806           ]
4807
4808
4809 if __name__ == "__main__":
4810     pass