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