]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_1.py
d9bedf405686fd5a3a4141412e0a2b885f9c61ee
[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                     lastertbeg = -1
3066                     lastertend = -1
3067                     while True:
3068                         # Find the last ERT in this paragraph used for arguments
3069                         # (which might also be the first)
3070                         lastertbeg = find_token_backwards(document.body, "\\begin_inset ERT", j)
3071                         if lastertbeg == -1:
3072                             document.warning("Last ERT not found!")
3073                             break
3074                         lastertend = find_end_of_inset(document.body, lastertbeg)
3075                         if lastertend == -1:
3076                             document.warning("End of last ERT not found!")
3077                             break
3078                         # Is this ERT really used for an argument?
3079                         # Note: This will fail when non-argument ERTs actually use brackets
3080                         #       (e.g. \pause{})
3081                         regexp = re.compile(r'.*[>\]\}]', re.IGNORECASE)
3082                         cbracket = find_re(document.body, regexp, lastertbeg, lastertend)
3083                         if cbracket != -1:
3084                             break
3085                         if lastertbeg == parbeg:
3086                             break
3087                         j = lastertbeg - 1
3088                     if lastertbeg == -1 or lastertend == -1:
3089                         break
3090                     ertcontlastline = lastertend - 3
3091                     while True:
3092                         if document.body[ertcontfirstline].lstrip().startswith("<"):
3093                             # This is an overlay specification
3094                             # strip off the <
3095                             document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3096                             if document.body[ertcontlastline].rstrip().endswith(">"):
3097                                 # strip off the >
3098                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3099                                 # Convert to ArgInset
3100                                 document.body[parbeg] = "\\begin_inset Argument 1"
3101                             elif document.body[ertcontlastline].rstrip().endswith("}"):
3102                                 # strip off the }
3103                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3104                                 # divide the args
3105                                 ertcontdivline = ertcontfirstline
3106                                 tok = document.body[ertcontdivline].find('>{')
3107                                 if tok == -1:
3108                                     regexp = re.compile(r'.*>\{', re.IGNORECASE)
3109                                     ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3110                                     tok = document.body[ertcontdivline].find('>{')
3111                                 if tok != -1:
3112                                     if ertcontfirstline < ertcontlastline:
3113                                         # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3114                                         document.body[ertcontlastline : ertcontlastline + 1] = [
3115                                                                             document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3116                                         if ertcontdivline == ertcontfirstline:
3117                                             document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3118                                                                                 '\\end_layout', '', '\\end_inset', '',
3119                                                                                 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3120                                                                                 'status collapsed', '', '\\begin_layout Plain Layout',
3121                                                                                 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3122                                                                                 document.body[ertcontdivline][tok + 2:]]
3123                                         else:
3124                                             document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3125                                                                                 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3126                                                                                 'status collapsed', '', '\\begin_layout Plain Layout',
3127                                                                                 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3128                                                                                 document.body[ertcontdivline][tok + 2:]]
3129                                     else:
3130                                         document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3131                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3132                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3133                                                                             document.body[ertcontdivline][tok + 2:]]
3134                                 else:
3135                                     # check if have delimiters in two different ERTs
3136                                     tok = document.body[ertcontdivline].find('>')
3137                                     if tok == -1:
3138                                         regexp = re.compile(r'.*>', re.IGNORECASE)
3139                                         ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3140                                         tok = document.body[ertcontdivline].find('>')
3141                                     if tok != -1:
3142                                         tokk = document.body[ertcontdivline].find('{')
3143                                         if tokk == -1:
3144                                             regexp = re.compile(r'.*\{', re.IGNORECASE)
3145                                             ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, lastertend)
3146                                             tokk = document.body[ertcontdivlinetwo].find('{')
3147                                         if tokk != -1:
3148                                             if ertcontfirstline < ertcontlastline:
3149                                                 # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3150                                                 document.body[ertcontlastline : ertcontlastline + 1] = [
3151                                                                                     document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3152                                                 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3153                                                                                     '\\end_layout', '', '\\end_inset', '', '\\end_layout', '', 
3154                                                                                     '\\end_inset', '', '', '\\begin_inset Argument 2',
3155                                                                                     'status collapsed', '', '\\begin_layout Plain Layout',
3156                                                                                     '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3157                                                                                     document.body[ertcontdivlinetwo][tokk + 1:]]
3158                                             else:
3159                                                 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3160                                                                                     '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3161                                                                                     'status collapsed', '', '\\begin_layout Plain Layout',
3162                                                                                     document.body[ertcontdivlinetwo][tokk + 1:]]
3163                                 # Convert to ArgInset
3164                                 if ertcontfirstline < ertcontlastline:
3165                                     # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3166                                     document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 1',
3167                                                                         'status collapsed', '', '\\begin_layout Plain Layout',
3168                                                                         '\\begin_inset ERT', '']
3169                                 else:
3170                                     document.body[parbeg] = "\\begin_inset Argument 1"
3171                         elif document.body[ertcontfirstline].lstrip().startswith("{"):
3172                             # This is the block title
3173                             if document.body[ertcontlastline].rstrip().endswith("}"):
3174                                 # strip off the braces
3175                                 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3176                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3177                                 if ertcontfirstline < ertcontlastline:
3178                                     # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3179                                     document.body[parend : parend + 1] = [
3180                                                                         document.body[parend], '\\end_inset', '', '\\end_layout']
3181                                     document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2',
3182                                                                         'status collapsed', '', '\\begin_layout Plain Layout',
3183                                                                         '\\begin_inset ERT', '']
3184                                 else:
3185                                     # Convert to ArgInset
3186                                     document.body[parbeg] = "\\begin_inset Argument 2"
3187                             # the overlay argument can also follow the title, so ...
3188                             elif document.body[ertcontlastline].rstrip().endswith(">"):
3189                                 # strip off the {
3190                                 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3191                                 # strip off the >
3192                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3193                                 # divide the args
3194                                 ertcontdivline = ertcontfirstline
3195                                 tok = document.body[ertcontdivline].find('}<')
3196                                 if tok == -1:
3197                                     regexp = re.compile(r'.*\}<', re.IGNORECASE)
3198                                     ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3199                                     tok = document.body[ertcontdivline].find('}<')
3200                                 if tok != -1:
3201                                     if ertcontfirstline < ertcontlastline:
3202                                         # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3203                                         document.body[ertcontlastline : ertcontlastline + 1] = [
3204                                                                             document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3205                                         document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3206                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3207                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3208                                                                             '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3209                                                                             document.body[ertcontdivline][tok + 2:]]
3210                                     else:
3211                                         document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3212                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3213                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3214                                                                             document.body[ertcontdivline][tok + 2:]]
3215                                 else:
3216                                     # check if have delimiters in two different ERTs
3217                                     tok = document.body[ertcontdivline].find('}')
3218                                     if tok == -1:
3219                                         regexp = re.compile(r'.*\}', re.IGNORECASE)
3220                                         ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3221                                         tok = document.body[ertcontdivline].find('}')
3222                                         if tok != -1:
3223                                             tokk = document.body[ertcontdivline].find('<')
3224                                             if tokk == -1:
3225                                                 regexp = re.compile(r'.*<', re.IGNORECASE)
3226                                                 ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, lastertend)
3227                                                 tokk = document.body[ertcontdivlinetwo].find('<')
3228                                                 if tokk != -1:
3229                                                     if ertcontfirstline < ertcontlastline:
3230                                                         # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3231                                                         document.body[ertcontlastline : ertcontlastline + 1] = [
3232                                                                                             document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3233                                                         document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3234                                                                                             '\\end_layout', '', '\\end_inset', '', '\\end_layout', '', 
3235                                                                                             '\\end_inset', '', '', '\\begin_inset Argument 1',
3236                                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3237                                                                                             '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3238                                                                                             document.body[ertcontdivlinetwo][tokk + 1:]]
3239                                                     else:
3240                                                         document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3241                                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3242                                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3243                                                                                             document.body[ertcontdivlinetwo][tokk + 1:]]
3244                                 # Convert to ArgInset
3245                                 if ertcontfirstline < ertcontlastline:
3246                                     # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3247                                     document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2',
3248                                                                         'status collapsed', '', '\\begin_layout Plain Layout',
3249                                                                         '\\begin_inset ERT', '']
3250                                 else:
3251                                     document.body[parbeg] = "\\begin_inset Argument 2"
3252                             elif count_pars_in_inset(document.body, ertcontfirstline) > 1:
3253                                 # Multipar ERT. Skip this.
3254                                 break
3255                             else:
3256                                 # ERT has contents after the closing bracket. We cannot convert this.
3257                                 # convert_TeX_brace_to_Argument cannot either.
3258                                 #convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, False)
3259                                 break
3260                         else:
3261                             break
3262                         j = find_end_of_layout(document.body, i)
3263                         if j == -1:
3264                             document.warning("end of layout not found!")
3265                         k = find_token(document.body, "\\begin_inset Argument", i, j)
3266                         if k == -1:
3267                             document.warning("InsetArgument not found!")
3268                             break
3269                         l = find_end_of_inset(document.body, k)
3270                         m = find_token(document.body, "\\begin_inset ERT", l, j)
3271                         if m == -1:
3272                             break
3273                         ertcontfirstline = m + 5
3274                         parbeg = m
3275             i = j
3276
3277
3278 def convert_overprint(document):
3279     " Convert old beamer overprint layouts to ERT "
3280     
3281     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3282     if document.textclass not in beamer_classes:
3283         return
3284
3285     i = 0
3286     while True:
3287         i = find_token(document.body, "\\begin_layout Overprint", i)
3288         if i == -1:
3289             return
3290         # Find end of sequence
3291         j = find_end_of_sequence(document.body, i)
3292         if j == -1:
3293             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3294             i += 1
3295             continue
3296         endseq = j
3297         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3298         esubst = list()
3299         if document.body[j] == "\\end_deeper":
3300             esubst = ["", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
3301         else:
3302             esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
3303         endseq = endseq + len(esubst) - len(document.body[j : j])
3304         document.body[j : j] = esubst
3305         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3306         if argbeg != -1:
3307             argend = find_end_of_layout(document.body, argbeg)
3308             if argend == -1:
3309                 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3310                 i += 1
3311                 continue
3312             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3313             endPlain = find_end_of_layout(document.body, beginPlain)
3314             content = document.body[beginPlain + 1 : endPlain]
3315             # Adjust range end
3316             endseq = endseq - len(document.body[argbeg : argend + 1])
3317             # Remove arg inset
3318             del document.body[argbeg : argend + 1]
3319             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3320             
3321         endseq = endseq - len(document.body[i : i])
3322         document.body[i : i] = subst + ["\\end_layout"]
3323         endseq += len(subst)
3324         
3325         for p in range(i, endseq):
3326             if document.body[p] == "\\begin_layout Overprint":
3327                 document.body[p] = "\\begin_layout Standard"
3328
3329         i = endseq
3330
3331
3332 def revert_overprint(document):
3333     " Revert old beamer overprint layouts to ERT "
3334     
3335     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3336     if document.textclass not in beamer_classes:
3337         return
3338
3339     i = 0
3340     while True:
3341         i = find_token(document.body, "\\begin_layout Overprint", i)
3342         if i == -1:
3343             return
3344         # Find end of sequence
3345         j = find_end_of_sequence(document.body, i)
3346         if j == -1:
3347             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3348             i += 1
3349             continue
3350         endseq = j
3351         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3352         esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}")
3353         endseq = endseq + len(esubst) - len(document.body[j : j])
3354         if document.body[j] == "\\end_deeper":
3355             document.body[j : j] = [""] + esubst + ["", "\\end_layout"]
3356         else:
3357             document.body[j : j] = ["\\end_layout", ""] + esubst
3358         r = i
3359         while r < j:
3360             if document.body[r] == "\\begin_deeper":
3361                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3362                 if s != -1:
3363                     document.body[r] = ""
3364                     document.body[s] = ""
3365                     r = s
3366                     continue
3367             r = r + 1
3368         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3369         if argbeg != -1:
3370             # Is this really our argument?
3371             nested = find_token(document.body, "\\begin_deeper", i, argbeg)
3372             if nested != -1:
3373                 argend = find_end_of_inset(document.body, argbeg)
3374                 if argend == -1:
3375                     document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3376                     i += 1
3377                     continue
3378                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3379                 endPlain = find_end_of_layout(document.body, beginPlain)
3380                 content = document.body[beginPlain + 1 : endPlain]
3381                 # Adjust range end
3382                 endseq = endseq - len(document.body[argbeg : argend])
3383                 # Remove arg inset
3384                 del document.body[argbeg : argend + 1]
3385                 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3386             
3387         endseq = endseq - len(document.body[i : i])
3388         document.body[i : i] = subst + ["\\end_layout"]
3389         endseq += len(subst)
3390      
3391         p = i
3392         while True:
3393             if p >= endseq:
3394                 break
3395             if document.body[p] == "\\begin_layout Overprint":
3396                 q = find_end_of_layout(document.body, p)
3397                 if q == -1:
3398                     document.warning("Malformed LyX document. Cannot find end of Overprint layout!")
3399                     p += 1
3400                     continue
3401                 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\onslide")
3402                 argbeg = find_token(document.body, "\\begin_inset Argument item:1", p, q)
3403                 if argbeg != -1:
3404                     argend = find_end_of_inset(document.body, argbeg)
3405                     if argend == -1:
3406                         document.warning("Malformed LyX document. Cannot find end of Overprint item argument!")
3407                         p += 1
3408                         continue
3409                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3410                     endPlain = find_end_of_layout(document.body, beginPlain)
3411                     content = document.body[beginPlain + 1 : endPlain]
3412                     # Adjust range end
3413                     endseq = endseq - len(document.body[argbeg : argend + 1])
3414                     # Remove arg inset
3415                     del document.body[argbeg : argend + 1]
3416                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3417                 endseq = endseq - len(document.body[p : p + 1]) + len(subst)
3418                 document.body[p : p + 1] = subst
3419             p = p + 1
3420
3421         i = endseq
3422
3423
3424 def revert_frametitle(document):
3425     " Reverts beamer frametitle layout to ERT "
3426     
3427     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3428     if document.textclass not in beamer_classes:
3429         return
3430
3431     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3432     i = 0
3433     while True:
3434         i = find_token(document.body, "\\begin_layout FrameTitle", i)
3435         if i == -1:
3436             return
3437         j = find_end_of_layout(document.body, i)
3438         if j == -1:
3439             document.warning("Malformed LyX document: Can't find end of FrameTitle layout")
3440             i += 1
3441             continue
3442         endlay = j
3443         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
3444         endlay += len(put_cmd_in_ert("}"))
3445         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\frametitle")
3446         for p in range(i, j):
3447             if p >= endlay:
3448                 break
3449             m = rx.match(document.body[p])
3450             if m:
3451                 argnr = m.group(1)
3452                 if argnr == "1":
3453                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3454                     endPlain = find_end_of_layout(document.body, beginPlain)
3455                     endInset = find_end_of_inset(document.body, p)
3456                     content = document.body[beginPlain + 1 : endPlain]
3457                     # Adjust range end
3458                     endlay = endlay - len(document.body[p : endInset + 1])
3459                     # Remove arg inset
3460                     del document.body[p : endInset + 1]
3461                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3462                 elif argnr == "2":
3463                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3464                     endPlain = find_end_of_layout(document.body, beginPlain)
3465                     endInset = find_end_of_inset(document.body, p)
3466                     content = document.body[beginPlain + 1 : endPlain]
3467                     # Adjust range end
3468                     endlay = endlay - len(document.body[p : endInset + 1])
3469                     # Remove arg inset
3470                     del document.body[p : endInset + 1]
3471                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3472                     
3473         subst += put_cmd_in_ert("{")
3474         document.body[i : i + 1] = subst
3475         i = endlay
3476
3477
3478 def convert_epigraph(document):
3479     " Converts memoir epigraph to new syntax "
3480     
3481     if document.textclass != "memoir":
3482         return
3483
3484     i = 0
3485     while True:
3486         i = find_token(document.body, "\\begin_layout Epigraph", i)
3487         if i == -1:
3488             return
3489         j = find_end_of_layout(document.body, i)
3490         if j == -1:
3491             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3492             i += 1
3493             continue
3494         endlay = j
3495         subst = list()
3496         ert = find_token(document.body, "\\begin_inset ERT", i, j)
3497         if ert != -1:
3498             endInset = find_end_of_inset(document.body, ert)
3499             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", ert)
3500             endPlain = find_end_of_layout(document.body, beginPlain)
3501             ertcont = beginPlain + 2
3502             if document.body[ertcont] == "}{":
3503                 # strip off the <
3504                 # Convert to ArgInset
3505                 endlay = endlay - 2 * len(document.body[j])
3506                 begsubst = ['\\begin_inset Argument post:1', 'status collapsed', '',
3507                             '\\begin_layout Plain Layout']
3508                 endsubst = ['\\end_layout', '', '\\end_inset', '', document.body[j]]
3509                 document.body[j : j + 1] = endsubst
3510                 document.body[endInset + 1 : endInset + 1] = begsubst
3511                 # Adjust range end
3512                 endlay += len(begsubst) + len(endsubst)
3513                 endlay = endlay - len(document.body[ert : endInset + 1])
3514                 del document.body[ert : endInset + 1]
3515                     
3516         i = endlay
3517
3518
3519 def revert_epigraph(document):
3520     " Reverts memoir epigraph argument to ERT "
3521     
3522     if document.textclass != "memoir":
3523         return
3524
3525     i = 0
3526     while True:
3527         i = find_token(document.body, "\\begin_layout Epigraph", i)
3528         if i == -1:
3529             return
3530         j = find_end_of_layout(document.body, i)
3531         if j == -1:
3532             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3533             i += 1
3534             continue
3535         endlay = j
3536         subst = list()
3537         p = find_token(document.body, "\\begin_layout Argument post:1", i, j)
3538         if p != -1:
3539             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3540             endPlain = find_end_of_layout(document.body, beginPlain)
3541             endInset = find_end_of_inset(document.body, p)
3542             content = document.body[beginPlain + 1 : endPlain]
3543             # Adjust range end
3544             endlay = endlay - len(document.body[p : endInset + 1])
3545             # Remove arg inset
3546             del document.body[p : endInset + 1]
3547             subst += put_cmd_in_ert("}{") + content
3548         else:
3549             subst += put_cmd_in_ert("}{")
3550                     
3551         document.body[j : j] = subst + document.body[j : j]
3552         i = endlay
3553
3554
3555 def convert_captioninsets(document):
3556     " Converts caption insets to new syntax "
3557     
3558     i = 0
3559     while True:
3560       i = find_token(document.body, "\\begin_inset Caption", i)
3561       if i == -1:
3562           return
3563       document.body[i] = "\\begin_inset Caption Standard"
3564       i += 1
3565
3566
3567 def revert_captioninsets(document):
3568     " Reverts caption insets to old syntax "
3569     
3570     i = 0
3571     while True:
3572       i = find_token(document.body, "\\begin_inset Caption Standard", i)
3573       if i == -1:
3574           return
3575       document.body[i] = "\\begin_inset Caption"
3576       i += 1
3577
3578
3579 def convert_captionlayouts(document):
3580     " Convert caption layouts to caption insets. "
3581
3582     caption_dict = {
3583         "Captionabove":  "Above",
3584         "Captionbelow":  "Below",
3585         "FigCaption"  :  "FigCaption",
3586         "Table_Caption" :  "Table",
3587         "CenteredCaption" : "Centered",
3588         "Bicaption" : "Bicaption",
3589         }
3590
3591     i = 0
3592     while True:
3593         i = find_token(document.body, "\\begin_layout", i)
3594         if i == -1:
3595             return
3596         val = get_value(document.body, "\\begin_layout", i)
3597         if val in caption_dict.keys():
3598             j = find_end_of_layout(document.body, i)
3599             if j == -1:
3600                 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3601                 return
3602
3603             document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""]
3604             document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout,
3605                                     "\\begin_inset Caption %s" % caption_dict[val], "",
3606                                     "\\begin_layout %s" % document.default_layout]
3607         i += 1
3608
3609
3610 def revert_captionlayouts(document):
3611     " Revert caption insets to caption layouts. "
3612     
3613     caption_dict = {
3614         "Above" : "Captionabove",
3615         "Below" : "Captionbelow",
3616         "FigCaption"  :  "FigCaption",
3617         "Table" : "Table_Caption",
3618         "Centered" : "CenteredCaption",
3619         "Bicaption" : "Bicaption",
3620         }
3621     
3622     i = 0
3623     rx = re.compile(r'^\\begin_inset Caption (\S+)$')
3624     while True:
3625         i = find_token(document.body, "\\begin_inset Caption", i)
3626         if i == -1:
3627             return
3628
3629         m = rx.match(document.body[i])
3630         val = ""
3631         if m:
3632             val = m.group(1)
3633         if val not in caption_dict.keys():
3634             i += 1
3635             continue
3636         
3637         # We either need to delete the previous \begin_layout line, or we
3638         # need to end the previous layout if this inset is not in the first
3639         # position of the paragraph.
3640         layout_before = find_token_backwards(document.body, "\\begin_layout", i)
3641         if layout_before == -1:
3642             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3643             return
3644         layout_line = document.body[layout_before]
3645         del_layout_before = True
3646         l = layout_before + 1
3647         while l < i:
3648             if document.body[l] != "":
3649                 del_layout_before = False
3650                 break
3651             l = l + 1
3652         if del_layout_before:
3653             del document.body[layout_before:i]
3654             i = layout_before
3655         else:
3656             document.body[i:i] = ["\\end_layout", ""]
3657             i = i + 2
3658
3659         # Find start of layout in the inset and end of inset
3660         j = find_token(document.body, "\\begin_layout", i)
3661         if j == -1:
3662             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3663             return
3664         k = find_end_of_inset(document.body, i)
3665         if k == -1:
3666             document.warning("Malformed LyX document: Missing `\\end_inset'.")
3667             return
3668
3669         # We either need to delete the following \end_layout line, or we need
3670         # to restart the old layout if this inset is not at the paragraph end.
3671         layout_after = find_token(document.body, "\\end_layout", k)
3672         if layout_after == -1:
3673             document.warning("Malformed LyX document: Missing `\\end_layout'.")
3674             return
3675         del_layout_after = True
3676         l = k + 1
3677         while l < layout_after:
3678             if document.body[l] != "":
3679                 del_layout_after = False
3680                 break
3681             l = l + 1
3682         if del_layout_after:
3683             del document.body[k+1:layout_after+1]
3684         else:
3685             document.body[k+1:k+1] = [layout_line, ""]
3686
3687         # delete \begin_layout and \end_inset and replace \begin_inset with
3688         # "\begin_layout XXX". This works because we can only have one
3689         # paragraph in the caption inset: The old \end_layout will be recycled.
3690         del document.body[k]
3691         if document.body[k] == "":
3692             del document.body[k]
3693         del document.body[j]
3694         if document.body[j] == "":
3695             del document.body[j]
3696         document.body[i] = "\\begin_layout %s" % caption_dict[val]
3697         if document.body[i+1] == "":
3698             del document.body[i+1]
3699         i += 1
3700
3701
3702 def revert_fragileframe(document):
3703     " Reverts beamer FragileFrame layout to ERT "
3704     
3705     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3706     if document.textclass not in beamer_classes:
3707         return
3708
3709     i = 0
3710     while True:
3711         i = find_token(document.body, "\\begin_layout FragileFrame", i)
3712         if i == -1:
3713             return
3714         # Find end of sequence
3715         j = find_end_of_sequence(document.body, i)
3716         if j == -1:
3717             document.warning("Malformed LyX document. Cannot find end of FragileFrame sequence!")
3718             i += 1
3719             continue
3720         endseq = j
3721         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{frame}")
3722         esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}")
3723         endseq = endseq + len(esubst) - len(document.body[j : j])
3724         if document.body[j] == "\\end_deeper":
3725             document.body[j : j] = [""] + esubst + ["", "\\end_layout"]
3726         else:
3727             document.body[j : j] = esubst
3728         for q in range(i, j):
3729             if document.body[q] == "\\begin_layout FragileFrame":
3730                 document.body[q] = "\\begin_layout %s" % document.default_layout
3731         r = i
3732         while r < j:
3733             if document.body[r] == "\\begin_deeper":
3734                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3735                 if s != -1:
3736                     document.body[r] = ""
3737                     document.body[s] = ""
3738                     r = s
3739                     continue
3740             r = r + 1
3741         for p in range(1, 5):
3742             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, j)
3743             if arg != -1:
3744                 if p == 1:
3745                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3746                     endPlain = find_end_of_layout(document.body, beginPlain)
3747                     endInset = find_end_of_inset(document.body, arg)
3748                     content = document.body[beginPlain + 1 : endPlain]
3749                     # Adjust range end
3750                     j = j - len(document.body[arg : endInset + 1])
3751                     # Remove arg inset
3752                     del document.body[arg : endInset + 1]
3753                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3754                 elif p == 2:
3755                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3756                     endPlain = find_end_of_layout(document.body, beginPlain)
3757                     endInset = find_end_of_inset(document.body, arg)
3758                     content = document.body[beginPlain + 1 : endPlain]
3759                     # Adjust range end
3760                     j = j - len(document.body[arg : endInset + 1])
3761                     # Remove arg inset
3762                     del document.body[arg : endInset + 1]
3763                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3764                 elif p == 3:
3765                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3766                     endPlain = find_end_of_layout(document.body, beginPlain)
3767                     endInset = find_end_of_inset(document.body, arg)
3768                     content = document.body[beginPlain + 1 : endPlain]
3769                     # Adjust range end
3770                     j = j - len(document.body[arg : endInset + 1])
3771                     # Remove arg inset
3772                     del document.body[arg : endInset + 1]
3773                     subst += put_cmd_in_ert("[fragile,") + content + put_cmd_in_ert("]")
3774                 elif p == 4:
3775                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3776                     endPlain = find_end_of_layout(document.body, beginPlain)
3777                     endInset = find_end_of_inset(document.body, arg)
3778                     content = document.body[beginPlain + 1 : endPlain]
3779                     # Adjust range end
3780                     j = j - len(document.body[arg : endInset + 1])
3781                     # Remove arg inset
3782                     del document.body[arg : endInset + 1]
3783                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3784             elif p == 3:
3785                 subst += put_cmd_in_ert("[fragile]")
3786                     
3787         document.body[i : i + 1] = subst
3788         i = j
3789
3790
3791 def revert_newframes(document):
3792     " Reverts beamer Frame and PlainFrame layouts to old forms "
3793     
3794     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3795     if document.textclass not in beamer_classes:
3796         return
3797
3798     frame_dict = {
3799         "Frame" : "BeginFrame",
3800         "PlainFrame" : "BeginPlainFrame",
3801         }
3802
3803     rx = re.compile(r'^\\begin_layout (\S+)$')
3804     i = 0
3805     while True:
3806         i = find_token(document.body, "\\begin_layout", i)
3807         if i == -1:
3808             return
3809
3810         m = rx.match(document.body[i])
3811         val = ""
3812         if m:
3813             val = m.group(1)
3814         if val not in frame_dict.keys():
3815             i += 1
3816             continue
3817         # Find end of sequence
3818         j = find_end_of_sequence(document.body, i)
3819         if j == -1:
3820             document.warning("Malformed LyX document. Cannot find end of Frame sequence!")
3821             i += 1
3822             continue
3823         endseq = j
3824         subst = ["\\begin_layout %s" % frame_dict[val]]
3825         esubst = ["", "\\begin_layout EndFrame", "", "\\end_layout"]
3826         endseq = endseq + len(esubst) - len(document.body[j : j])
3827         if document.body[j] == "\\end_deeper":
3828             document.body[j : j] = esubst
3829         else:
3830             document.body[j+1 : j+1] = esubst
3831         for q in range(i, j):
3832             if document.body[q] == "\\begin_layout %s" % val:
3833                 document.body[q] = "\\begin_layout %s" % document.default_layout
3834         r = i
3835         while r < j:
3836             if document.body[r] == "\\begin_deeper":
3837                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3838                 if s != -1:
3839                     document.body[r] = ""
3840                     document.body[s] = ""
3841                     r = s
3842                     continue
3843             r = r + 1
3844         l = find_end_of_layout(document.body, i)
3845         for p in range(1, 5):
3846             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, l)
3847             if arg != -1:
3848                 if p == 1:
3849                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3850                     endPlain = find_end_of_layout(document.body, beginPlain)
3851                     endInset = find_end_of_inset(document.body, arg)
3852                     content = document.body[beginPlain + 1 : endPlain]
3853                     # Adjust range end
3854                     l = l - len(document.body[arg : endInset + 1])
3855                     # Remove arg inset
3856                     del document.body[arg : endInset + 1]
3857                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3858                 elif p == 2:
3859                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3860                     endPlain = find_end_of_layout(document.body, beginPlain)
3861                     endInset = find_end_of_inset(document.body, arg)
3862                     content = document.body[beginPlain + 1 : endPlain]
3863                     # Adjust range end
3864                     l = l - len(document.body[arg : endInset + 1])
3865                     # Remove arg inset
3866                     del document.body[arg : endInset + 1]
3867                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3868                 elif p == 3:
3869                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3870                     endPlain = find_end_of_layout(document.body, beginPlain)
3871                     endInset = find_end_of_inset(document.body, arg)
3872                     content = document.body[beginPlain + 1 : endPlain]
3873                     # Adjust range end
3874                     l = l - len(document.body[arg : endInset + 1])
3875                     # Remove arg inset
3876                     del document.body[arg : endInset + 1]
3877                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3878                 elif p == 4:
3879                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3880                     endPlain = find_end_of_layout(document.body, beginPlain)
3881                     endInset = find_end_of_inset(document.body, arg)
3882                     content = document.body[beginPlain + 1 : endPlain]
3883                     # Adjust range end
3884                     l = l - len(document.body[arg : endInset + 1])
3885                     # Remove arg inset
3886                     del document.body[arg : endInset + 1]
3887                     subst += content
3888                     
3889         document.body[i : i + 1] = subst
3890         i = j
3891
3892 # known encodings that do not change their names (same LyX and LaTeX names)
3893 known_enc_tuple = ("auto", "default", "ansinew", "applemac", "armscii8", "ascii",
3894     "cp437", "cp437de", "cp850", "cp852", "cp855", "cp858", "cp862", "cp865", "cp866",
3895     "cp1250", "cp1251", "cp1252", "cp1255", "cp1256", "cp1257", "koi8-r", "koi8-u",
3896     "pt154", "pt254", "tis620-0", "utf8", "utf8x", "utf8-plain")
3897
3898 def convert_encodings(document):
3899     "Use the LyX names of the encodings instead of the LaTeX names."
3900     LaTeX2LyX_enc_dict = {
3901         "8859-6":     "iso8859-6",
3902         "8859-8":     "iso8859-8",
3903         "Bg5":        "big5",
3904         "euc":        "euc-jp-platex",
3905         "EUC-JP":     "euc-jp",
3906         "EUC-TW":     "euc-tw",
3907         "GB":         "euc-cn",
3908         "GBK":        "gbk",
3909         "iso88595":   "iso8859-5",
3910         "iso-8859-7": "iso8859-7",
3911         "JIS":        "jis",
3912         "jis":        "jis-platex",
3913         "KS":         "euc-kr",
3914         "l7xenc":     "iso8859-13",
3915         "latin1":     "iso8859-1",
3916         "latin2":     "iso8859-2",
3917         "latin3":     "iso8859-3",
3918         "latin4":     "iso8859-4",
3919         "latin5":     "iso8859-9",
3920         "latin9":     "iso8859-15",
3921         "latin10":    "iso8859-16",
3922         "SJIS":       "shift-jis",
3923         "sjis":       "shift-jis-platex",
3924         "UTF8":       "utf8-cjk"
3925     }
3926     i = find_token(document.header, "\\inputencoding" , 0)
3927     if i == -1:
3928         return
3929     val = get_value(document.header, "\\inputencoding", i)
3930     if val in LaTeX2LyX_enc_dict.keys():
3931         document.header[i] = "\\inputencoding %s" % LaTeX2LyX_enc_dict[val]
3932     elif val not in known_enc_tuple:
3933         document.warning("Ignoring unknown input encoding: `%s'" % val)
3934
3935
3936 def revert_encodings(document):
3937     """Revert to using the LaTeX names of the encodings instead of the LyX names.
3938     Also revert utf8-platex to sjis, the language default when using Japanese.
3939     """
3940     LyX2LaTeX_enc_dict = {
3941         "big5":             "Bg5",
3942         "euc-cn":           "GB",
3943         "euc-kr":           "KS",
3944         "euc-jp":           "EUC-JP",
3945         "euc-jp-platex":    "euc",
3946         "euc-tw":           "EUC-TW",
3947         "gbk":              "GBK",
3948         "iso8859-1":        "latin1",
3949         "iso8859-2":        "latin2",
3950         "iso8859-3":        "latin3",
3951         "iso8859-4":        "latin4",
3952         "iso8859-5":        "iso88595",
3953         "iso8859-6":        "8859-6",
3954         "iso8859-7":        "iso-8859-7",
3955         "iso8859-8":        "8859-8",
3956         "iso8859-9":        "latin5",
3957         "iso8859-13":       "l7xenc",
3958         "iso8859-15":       "latin9",
3959         "iso8859-16":       "latin10",
3960         "jis":              "JIS",
3961         "jis-platex":       "jis",
3962         "shift-jis":        "SJIS",
3963         "shift-jis-platex": "sjis",
3964         "utf8-cjk":         "UTF8",
3965         "utf8-platex":      "sjis"
3966     }
3967     i = find_token(document.header, "\\inputencoding" , 0)
3968     if i == -1:
3969         return
3970     val = get_value(document.header, "\\inputencoding", i)
3971     if val in LyX2LaTeX_enc_dict.keys():
3972         document.header[i] = "\\inputencoding %s" % LyX2LaTeX_enc_dict[val]
3973     elif val not in known_enc_tuple:
3974         document.warning("Ignoring unknown input encoding: `%s'" % val)
3975
3976
3977 def revert_IEEEtran_3(document):
3978   '''
3979   Reverts Flex Insets to TeX-code
3980   '''
3981   if document.textclass == "IEEEtran":
3982     h = 0
3983     i = 0
3984     j = 0
3985     while True:
3986       if h != -1:
3987         h = find_token(document.body, "\\begin_inset Flex Author Mark", h)
3988       if h != -1:
3989         endh = find_end_of_inset(document.body, h)
3990         document.body[endh - 2 : endh + 1] = put_cmd_in_ert("}")
3991         document.body[h : h + 4] = put_cmd_in_ert("\\IEEEauthorrefmark{")
3992         h = h + 5
3993       if i != -1:
3994         i = find_token(document.body, "\\begin_inset Flex Author Name", i)
3995       if i != -1:
3996         endi = find_end_of_inset(document.body, i)
3997         document.body[endi - 2 : endi + 1] = put_cmd_in_ert("}")
3998         document.body[i : i + 4] = put_cmd_in_ert("\\IEEEauthorblockN{")
3999         i = i + 5
4000       if j != -1:
4001         j = find_token(document.body, "\\begin_inset Flex Author Affiliation", j)
4002       if j != -1:
4003         endj = find_end_of_inset(document.body, j)
4004         document.body[endj - 2 : endj + 1] = put_cmd_in_ert("}")
4005         document.body[j : j + 4] = put_cmd_in_ert("\\IEEEauthorblockA{")
4006         j = j + 5
4007       if i == -1 and j == -1 and h == -1:
4008         return
4009
4010
4011 def revert_kurier_fonts(document):
4012   " Revert kurier font definition to LaTeX "
4013   
4014   i = find_token(document.header, "\\font_math", 0)
4015   if i != -1:
4016     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
4017       val = get_value(document.header, "\\font_math", i)
4018       if val == "kurier-math":
4019         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
4020           "\\usepackage[math]{kurier}\n" \
4021           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
4022         document.header[i] = "\\font_math auto"
4023   
4024   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
4025     kurier_fonts = ["kurier", "kurierc", "kurierl", "kurierlc"]
4026     k = find_token(document.header, "\\font_sans kurier", 0)
4027     if k != -1:
4028       sf = get_value(document.header, "\\font_sans", k)
4029       if sf in kurier_fonts:
4030         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
4031         document.header[k] = "\\font_sans default"
4032
4033 def revert_iwona_fonts(document):
4034   " Revert iwona font definition to LaTeX "
4035   
4036   i = find_token(document.header, "\\font_math", 0)
4037   if i != -1:
4038     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
4039       val = get_value(document.header, "\\font_math", i)
4040       if val == "iwona-math":
4041         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
4042           "\\usepackage[math]{iwona}\n" \
4043           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
4044         document.header[i] = "\\font_math auto"
4045   
4046   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
4047     iwona_fonts = ["iwona", "iwonac", "iwonal", "iwonalc"]
4048     k = find_token(document.header, "\\font_sans iwona", 0)
4049     if k != -1:
4050       sf = get_value(document.header, "\\font_sans", k)
4051       if sf in iwona_fonts:
4052         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
4053         document.header[k] = "\\font_sans default"
4054
4055
4056 def revert_new_libertines(document):
4057     " Revert new libertine font definition to LaTeX "
4058   
4059     if find_token(document.header, "\\use_non_tex_fonts true", 0) != -1:
4060         return
4061
4062     i = find_token(document.header, "\\font_typewriter libertine-mono", 0)
4063     if i != -1:
4064         preamble = "\\usepackage"
4065         sc = find_token(document.header, "\\font_tt_scale", 0)
4066         if sc != -1:
4067             scval = get_value(document.header, "\\font_tt_scale", sc)
4068             if scval != "100":
4069                 preamble += "[scale=%f]" % (float(scval) / 100)
4070                 document.header[sc] = "\\font_tt_scale 100"
4071         preamble += "{libertineMono-type1}"
4072         add_to_preamble(document, [preamble])
4073         document.header[i] = "\\font_typewriter default"
4074    
4075     k = find_token(document.header, "\\font_sans biolinum", 0)
4076     if k != -1:
4077         preamble = "\\usepackage"
4078         options = ""
4079         j = find_token(document.header, "\\font_osf true", 0)
4080         if j != -1:
4081             options += "osf"
4082         else:
4083             options += "lining"
4084         sc = find_token(document.header, "\\font_sf_scale", 0)
4085         if sc != -1:
4086             scval = get_value(document.header, "\\font_sf_scale", sc)
4087             if scval != "100":
4088                 options += ",scale=%f" % (float(scval) / 100)
4089                 document.header[sc] = "\\font_sf_scale 100"
4090         if options != "":
4091             preamble += "[" + options +"]"
4092         preamble += "{biolinum-type1}"
4093         add_to_preamble(document, [preamble])
4094         document.header[k] = "\\font_sans default"
4095
4096
4097 def convert_lyxframes(document):
4098     " Converts old beamer frames to new style "
4099     
4100     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
4101     if document.textclass not in beamer_classes:
4102         return
4103    
4104     framebeg = ["BeginFrame", "BeginPlainFrame"]
4105     frameend = ["Frame", "PlainFrame", "EndFrame", "BeginFrame", "BeginPlainFrame", "AgainFrame",
4106                 "Section", "Section*", "Subsection", "Subsection*", "Subsubsection", "Subsubsection*"]
4107     for lay in framebeg:
4108         i = 0
4109         while True:
4110             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
4111             if i == -1:
4112                 break
4113             parent = get_containing_layout(document.body, i)
4114             if parent == False or parent[1] != i:
4115                 document.warning("Wrong parent layout!")
4116                 i += 1
4117                 continue
4118             frametype = parent[0]
4119             j = parent[2]
4120             parbeg = parent[3]
4121             if i != -1:
4122                 # Step I: Convert ERT arguments
4123                 # FIXME: See restrictions in convert_beamerframeargs method
4124                 ertend = convert_beamerframeargs(document, i, parbeg)
4125                 if ertend == -1:
4126                     break
4127                 # Step II: Now rename the layout and convert the title to an argument
4128                 j = find_end_of_layout(document.body, i)
4129                 document.body[j : j + 1] = ['\\end_layout', '', '\\end_inset', '', '\\end_layout']
4130                 if lay == "BeginFrame":
4131                     document.body[i] = "\\begin_layout Frame"
4132                 else:
4133                     document.body[i] = "\\begin_layout PlainFrame"
4134                 document.body[ertend + 1 : ertend + 1] = ['\\begin_inset Argument 4',
4135                                                 'status open', '', '\\begin_layout Plain Layout']
4136                 # Step III: find real frame end
4137                 j = j + 8
4138                 jj = j
4139                 while True:
4140                     fend = find_token(document.body, "\\begin_layout", jj)
4141                     if fend == -1:
4142                         document.warning("Malformed LyX document: No real frame end!")
4143                         return
4144                     val = get_value(document.body, "\\begin_layout", fend)
4145                     if val not in frameend:
4146                         jj = fend + 1
4147                         continue
4148                     old = document.body[fend]
4149                     if val == frametype:
4150                         document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
4151                     # consider explicit EndFrames between two identical frame types
4152                     elif val == "EndFrame":
4153                         nextlayout = find_token(document.body, "\\begin_layout", fend + 1)
4154                         if nextlayout != -1 and get_value(document.body, "\\begin_layout", nextlayout) == frametype:
4155                             document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
4156                         else:
4157                             document.body[fend : fend] = ['\\end_deeper']
4158                     else:
4159                         document.body[fend : fend] = ['\\end_deeper']
4160                     document.body[j + 1 : j + 1] = ['', '\\begin_deeper']
4161                     break
4162             i = j
4163
4164
4165 def remove_endframes(document):
4166     " Remove deprecated beamer endframes "
4167     
4168     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
4169     if document.textclass not in beamer_classes:
4170         return
4171    
4172     i = 0
4173     while True:
4174         i = find_token_exact(document.body, "\\begin_layout EndFrame", i)
4175         if i == -1:
4176             break
4177         j = find_end_of_layout(document.body, i)
4178         if j == -1:
4179             document.warning("Malformed LyX document: Missing \\end_layout to EndFrame")
4180             i += 1
4181             continue
4182         del document.body[i : j + 1]
4183
4184
4185 def revert_powerdot_flexes(document):
4186     " Reverts powerdot flex insets "
4187     
4188     if document.textclass != "powerdot":
4189         return
4190
4191     flexes = {"Onslide" : "\\onslide",
4192               "Onslide*" : "\\onslide*",
4193               "Onslide+" : "\\onslide+"}
4194     rx = re.compile(r'^\\begin_inset Flex (.+)$')
4195
4196     i = 0
4197     while True:
4198         i = find_token(document.body, "\\begin_inset Flex", i)
4199         if i == -1:
4200             return
4201         m = rx.match(document.body[i])
4202         if m:
4203             flextype = m.group(1)
4204             z = find_end_of_inset(document.body, i)
4205             if z == -1:
4206                 document.warning("Can't find end of Flex " + flextype + " inset.")
4207                 i += 1
4208                 continue
4209             if flextype in flexes:
4210                 pre = put_cmd_in_ert(flexes[flextype])
4211                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
4212                 if arg != -1:
4213                     argend = find_end_of_inset(document.body, arg)
4214                     if argend == -1:
4215                         document.warning("Can't find end of Argument!")
4216                         i += 1
4217                         continue
4218                     # Find containing paragraph layout
4219                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
4220                     endPlain = find_end_of_layout(document.body, beginPlain)
4221                     argcontent = document.body[beginPlain + 1 : endPlain]
4222                     # Adjust range end
4223                     z = z - len(document.body[arg : argend + 1])
4224                     # Remove arg inset
4225                     del document.body[arg : argend + 1]
4226                     pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
4227                 pre += put_cmd_in_ert("{")
4228                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4229                 endPlain = find_end_of_layout(document.body, beginPlain)
4230                 # Adjust range end
4231                 z = z - len(document.body[i : beginPlain + 1])
4232                 z += len(pre)
4233                 document.body[i : beginPlain + 1] = pre
4234                 post = put_cmd_in_ert("}")
4235                 document.body[z - 2 : z + 1] = post     
4236         i += 1
4237
4238
4239 def revert_powerdot_pause(document):
4240     " Reverts powerdot pause layout to ERT "
4241     
4242     if document.textclass != "powerdot":
4243         return
4244
4245     i = 0
4246     while True:
4247         i = find_token(document.body, "\\begin_layout Pause", i)
4248         if i == -1:
4249             return
4250         j = find_end_of_layout(document.body, i)
4251         if j == -1:
4252             document.warning("Malformed LyX document: Can't find end of Pause layout")
4253             i += 1
4254             continue
4255         endlay = j
4256         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\pause")
4257         for p in range(i, j):
4258             if p >= endlay:
4259                 break
4260             arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
4261             if arg != -1:
4262                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4263                 endPlain = find_end_of_layout(document.body, beginPlain)
4264                 endInset = find_end_of_inset(document.body, p)
4265                 content = document.body[beginPlain + 1 : endPlain]
4266                 # Adjust range end
4267                 endlay = endlay - len(document.body[p : endInset + 1])
4268                 # Remove arg inset
4269                 del document.body[p : endInset + 1]
4270                 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4271                     
4272         document.body[i : i + 1] = subst
4273         i = endlay
4274
4275
4276 def revert_powerdot_itemargs(document):
4277     " Reverts powerdot item arguments to ERT "
4278     
4279     if document.textclass != "powerdot":
4280         return
4281
4282     i = 0
4283     list_layouts = ["Itemize", "ItemizeType1", "Enumerate", "EnumerateType1"]
4284     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4285
4286     while True:
4287         i = find_token(document.body, "\\begin_inset Argument", i)
4288         if i == -1:
4289             return
4290         # Find containing paragraph layout
4291         parent = get_containing_layout(document.body, i)
4292         if parent == False:
4293             document.warning("Malformed LyX document: Can't find parent paragraph layout")
4294             i += 1
4295             continue
4296         parbeg = parent[1]
4297         parend = parent[2]
4298         realparbeg = parent[3]
4299         layoutname = parent[0]
4300         realparend = parend
4301         for p in range(parbeg, parend):
4302             if p >= realparend:
4303                 i = realparend
4304                 break
4305             if layoutname in list_layouts:
4306                 m = rx.match(document.body[p])
4307                 if m:
4308                     argnr = m.group(1)
4309                     if argnr == "item:1":
4310                         j = find_end_of_inset(document.body, i)
4311                         # Find containing paragraph layout
4312                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4313                         endPlain = find_end_of_layout(document.body, beginPlain)
4314                         content = document.body[beginPlain + 1 : endPlain]
4315                         del document.body[i:j+1]
4316                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4317                         document.body[realparbeg : realparbeg] = subst
4318                     elif argnr == "item:2":
4319                         j = find_end_of_inset(document.body, i)
4320                         # Find containing paragraph layout
4321                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4322                         endPlain = find_end_of_layout(document.body, beginPlain)
4323                         content = document.body[beginPlain + 1 : endPlain]
4324                         del document.body[i:j+1]
4325                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
4326                         document.body[realparbeg : realparbeg] = subst
4327         
4328         i = realparend
4329
4330
4331 def revert_powerdot_columns(document):
4332     " Reverts powerdot twocolumn to TeX-code "
4333     if document.textclass != "powerdot":
4334         return
4335
4336     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4337     i = 0
4338     while True:
4339         i = find_token(document.body, "\\begin_layout Twocolumn", i)
4340         if i == -1:
4341             return
4342         j = find_end_of_layout(document.body, i)
4343         if j == -1:
4344             document.warning("Malformed LyX document: Can't find end of Twocolumn layout")
4345             i += 1
4346             continue
4347         endlay = j
4348         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
4349         endlay += len(put_cmd_in_ert("}"))
4350         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\twocolumn")
4351         for p in range(i, j):
4352             if p >= endlay:
4353                 break
4354             m = rx.match(document.body[p])
4355             if m:
4356                 argnr = m.group(1)
4357                 if argnr == "1":
4358                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4359                     endPlain = find_end_of_layout(document.body, beginPlain)
4360                     endInset = find_end_of_inset(document.body, p)
4361                     content = document.body[beginPlain + 1 : endPlain]
4362                     # Adjust range end
4363                     endlay = endlay - len(document.body[p : endInset + 1])
4364                     # Remove arg inset
4365                     del document.body[p : endInset + 1]
4366                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4367                 elif argnr == "2":
4368                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4369                     endPlain = find_end_of_layout(document.body, beginPlain)
4370                     endInset = find_end_of_inset(document.body, p)
4371                     content = document.body[beginPlain + 1 : endPlain]
4372                     # Adjust range end
4373                     endlay = endlay - len(document.body[p : endInset + 1])
4374                     # Remove arg inset
4375                     del document.body[p : endInset + 1]
4376                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
4377                     
4378         subst += put_cmd_in_ert("{")
4379         document.body[i : i + 1] = subst
4380         i = endlay
4381
4382
4383 def revert_mbox_fbox(document):
4384     'Convert revert mbox/fbox boxes to TeX-code'
4385     i = 0
4386     while True:
4387         i = find_token(document.body, "\\begin_inset Box", i)
4388         if i == -1:
4389             return
4390         j = find_token(document.body, "width", i)
4391         if j != i + 7:
4392             document.warning("Malformed LyX document: Can't find box width")
4393             return
4394         width = get_value(document.body, "width", j)
4395         k = find_end_of_inset(document.body, j)
4396         if k == -1:
4397             document.warning("Malformed LyX document: Can't find end of box inset")
4398             i += 1
4399             continue
4400         BeginLayout = find_token(document.body, "\\begin_layout Plain Layout", j)
4401         EndLayout = find_end_of_layout(document.body, BeginLayout)
4402         # replace if width is ""
4403         if (width == '""'):
4404             document.body[EndLayout:k + 1] = put_cmd_in_ert("}")
4405             if document.body[i] == "\\begin_inset Box Frameless":
4406                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\mbox{")
4407             if document.body[i] == "\\begin_inset Box Boxed":
4408                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\fbox{")
4409         i += 1
4410
4411
4412 def revert_starred_caption(document):
4413     " Reverts unnumbered longtable caption insets "
4414     
4415     i = 0
4416     while True:
4417       i = find_token(document.body, "\\begin_inset Caption LongTableNoNumber", i)
4418       if i == -1:
4419           return
4420       # This is not equivalent, but since the caption inset is a full blown
4421       # text inset a true conversion to ERT is too difficult.
4422       document.body[i] = "\\begin_inset Caption Standard"
4423       i += 1
4424
4425
4426 def revert_forced_local_layout(document):
4427     i = 0
4428     while True:
4429         i = find_token(document.header, "\\begin_forced_local_layout", i)
4430         if i == -1:
4431             return
4432         j = find_end_of(document.header, i, "\\begin_forced_local_layout", "\\end_forced_local_layout")
4433         if j == -1:
4434             # this should not happen
4435             break
4436         regexp = re.compile(r'\s*forcelocal', re.IGNORECASE)
4437         k = find_re(document.header, regexp, i, j)
4438         while k != -1:
4439             del document.header[k]
4440             j = j - 1
4441             k = find_re(document.header, regexp, i, j)
4442         k = find_token(document.header, "\\begin_local_layout", 0)
4443         if k == -1:
4444             document.header[i] = "\\begin_local_layout"
4445             document.header[j] = "\\end_local_layout"
4446         else:
4447             l = find_end_of(document.header, k, "\\begin_local_layout", "\\end_local_layout")
4448             if j == -1:
4449                 # this should not happen
4450                 break
4451             lines = document.header[i+1 : j]
4452             if k > i:
4453                 document.header[k+1 : k+1] = lines
4454                 document.header[i   : j  ] = []
4455             else:
4456                 document.header[i   : j  ] = []
4457                 document.header[k+1 : k+1] = lines
4458
4459
4460 def revert_aa1(document):
4461   " Reverts InsetArguments of aa to TeX-code "
4462   if document.textclass == "aa":
4463     i = 0
4464     while True:
4465       if i != -1:
4466         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4467       if i != -1:
4468         revert_Argument_to_TeX_brace(document, i, 0, 1, 4, False, False)
4469         i += 1
4470       if i == -1:
4471         return
4472
4473
4474 def revert_aa2(document):
4475   " Reverts InsetArguments of aa to TeX-code "
4476   if document.textclass == "aa":
4477     i = 0
4478     while True:
4479       if i != -1:
4480         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4481       if i != -1:
4482         document.body[i] = "\\begin_layout Abstract"
4483         i += 1
4484       if i == -1:
4485         return
4486
4487
4488 def revert_tibetan(document):
4489     "Set the document language for Tibetan to English" 
4490
4491     if document.language == "tibetan":
4492         document.language = "english"
4493         i = find_token(document.header, "\\language", 0) 
4494         if i != -1: 
4495             document.header[i] = "\\language english" 
4496     j = 0
4497     while j < len(document.body): 
4498         j = find_token(document.body, "\\lang tibetan", j)
4499         if j != -1:
4500             document.body[j] = document.body[j].replace("\\lang tibetan", "\\lang english")
4501             j += 1
4502         else:
4503             j = len(document.body)
4504
4505
4506 #############
4507 #
4508 # Chunk stuff
4509 #
4510 #############
4511
4512 # The idea here is that we will have a sequence of chunk paragraphs.
4513 # We want to convert them to paragraphs in one or several chunk insets.
4514 # Individual chunks are terminated by the character @ on the last line.
4515 # This line will be discarded, and following lines are treated as new
4516 # chunks, which go into their own insets.
4517 # The first line of a chunk should look like: <<CONTENT>>=
4518 # We will discard the delimiters, and put the CONTENT into the
4519 # optional argument of the inset, if the CONTENT is non-empty.
4520 def convert_chunks(document):
4521     first_re = re.compile(r'<<(.*)>>=(.*)')
4522     file_pos = 0
4523     while True:
4524         # find start of a block of chunks
4525         i = find_token(document.body, "\\begin_layout Chunk", file_pos)
4526         if i == -1:
4527             return
4528         start = i
4529         end = -1
4530         contents = []
4531         chunk_started = False
4532
4533         while True:
4534             # process the one we just found
4535             j = find_end_of_layout(document.body, i)
4536             if j == -1:
4537                 document.warning("Malformed LyX documents. Can't find end of Chunk layout!")
4538                 # there is no point continuing, as we will run into the same error again.
4539                 return
4540             this_chunk = "".join(document.body[i + 1:j])
4541             
4542             # there may be empty lines between chunks
4543             # we just skip them.
4544             if not chunk_started:
4545                 if this_chunk != "":
4546                     # new chunk starts
4547                     chunk_started = True
4548             
4549             if chunk_started:
4550                 contents.append(document.body[i + 1:j])
4551
4552             # look for potential chunk terminator
4553             # on the last line of the chunk paragraph            
4554             if document.body[j - 1] == "@":
4555                 break
4556
4557             # look for subsequent chunk paragraph
4558             i = find_token(document.body, "\\begin_layout", j)
4559             if i == -1:
4560                 break
4561
4562             if get_value(document.body, "\\begin_layout", i) != "Chunk":
4563                 break
4564
4565         file_pos = end = j + 1
4566         
4567         # The last chunk should simply have an "@" in it
4568         # or at least end with "@" (can happen if @ is
4569         # preceded by a newline)
4570         lastpar = ''.join(contents[-1])
4571         if not lastpar.endswith("@"):
4572             document.warning("Unexpected chunk content: chunk not terminated by '@'!")
4573             continue
4574
4575         if lastpar == "@":
4576             # chunk par only contains "@". Just drop it.
4577             contents.pop()
4578         else:
4579             # chunk par contains more. Only drop the "@".
4580             contents[-1].pop()
4581
4582         # The first line should look like: <<CONTENT>>=
4583         # We want the CONTENT
4584         optarg = ' '.join(contents[0])
4585         optarg.strip()
4586         # We can already have real chunk content in
4587         # the first par (separated from the options by a newline).
4588         # We collect such stuff to re-insert it later.
4589         postoptstuff = []
4590         
4591         match = first_re.search(optarg)
4592         if match:
4593             optarg = match.groups()[0]
4594             if match.groups()[1] != "":
4595                 postopt = False
4596                 for c in contents[0]:
4597                     if c.endswith(">>="):
4598                         postopt = True
4599                         continue
4600                     if postopt:
4601                         postoptstuff.append(c)
4602             # We have stripped everything. This can be deleted.
4603             contents.pop(0)
4604
4605         newstuff = ['\\begin_layout Standard',
4606                     '\\begin_inset Flex Chunk',
4607                     'status open', '',
4608                     '\\begin_layout Plain Layout', '']
4609
4610         # If we have a non-empty optional argument, insert it.
4611         if match and optarg != "":
4612             newstuff.extend(
4613                 ['\\begin_inset Argument 1',
4614                  'status open', '',
4615                  '\\begin_layout Plain Layout',
4616                  optarg,
4617                  '\\end_layout', '',
4618                  '\\end_inset', ''])
4619
4620         # Since we already opened a Plain layout, the first paragraph
4621         # does not need to do that.
4622         did_one_par = False
4623         if postoptstuff:
4624             newstuff.extend(postoptstuff)
4625             newstuff.append('\\end_layout')
4626             did_one_par = True
4627         for c in contents:
4628             if did_one_par:
4629                 newstuff.extend(['', '\\begin_layout Plain Layout', ''])
4630             else:
4631                 did_one_par = True
4632             newstuff.extend(c)
4633             newstuff.append('\\end_layout')
4634
4635         newstuff.extend(['', '\\end_inset', '', '\\end_layout', ''])
4636
4637         document.body[start:end] = newstuff
4638
4639         file_pos += len(newstuff) - (end - start)
4640
4641
4642 def revert_chunks(document):
4643     i = 0
4644     while True:
4645         i = find_token(document.body, "\\begin_inset Flex Chunk", i)
4646         if i == -1:
4647             return
4648
4649         iend = find_end_of_inset(document.body, i)
4650         if iend == -1:
4651             document.warning("Can't find end of Chunk!")
4652             i += 1
4653             continue
4654
4655         # Look for optional argument
4656         have_optarg = False
4657         ostart = find_token(document.body, "\\begin_inset Argument 1", i, iend)
4658         if ostart != -1:
4659             oend = find_end_of_inset(document.body, ostart)
4660             k = find_token(document.body, "\\begin_layout Plain Layout", ostart, oend)
4661             if k == -1:
4662                 document.warning("Malformed LyX document: Can't find argument contents!")
4663             else:
4664                 m = find_end_of_layout(document.body, k)
4665                 optarg = "".join(document.body[k+1:m])
4666                 have_optarg = True
4667
4668             # We now remove the optional argument, so we have something
4669             # uniform on which to work
4670             document.body[ostart : oend + 1] = []
4671             # iend is now invalid
4672             iend = find_end_of_inset(document.body, i)
4673
4674         retval = get_containing_layout(document.body, i)
4675         if not retval:
4676             document.warning("Can't find containing layout for Chunk!")
4677             i = iend
4678             continue
4679         (lname, lstart, lend, pstart)  = retval
4680         # we now want to work through the various paragraphs, and collect their contents
4681         parlist = []
4682         k = i
4683         while True:
4684             k = find_token(document.body, "\\begin_layout Plain Layout", k, lend)
4685             if k == -1:
4686                 break
4687             j = find_end_of_layout(document.body, k)
4688             if j == -1:
4689                 document.warning("Can't find end of layout inside chunk!")
4690                 break
4691             parlist.append(document.body[k+1:j])
4692             k = j
4693         # we now need to wrap all of these paragraphs in chunks
4694         newlines = []
4695         if have_optarg:
4696             newlines.extend(["\\begin_layout Chunk", "", "<<" + optarg + ">>=", "\\end_layout", ""])
4697         for stuff in parlist:
4698             newlines.extend(["\\begin_layout Chunk"] + stuff + ["\\end_layout", ""])
4699         newlines.extend(["\\begin_layout Chunk", "", "@", "\\end_layout", ""])
4700         # replace old content with new content
4701         document.body[lstart : lend + 1] = newlines
4702         i = lstart + len(newlines)
4703         
4704
4705 ##
4706 # Conversion hub
4707 #
4708
4709 supported_versions = ["2.1.0","2.1"]
4710 convert = [
4711            [414, []],
4712            [415, [convert_undertilde]],
4713            [416, []],
4714            [417, [convert_japanese_encodings]],
4715            [418, [convert_justification]],
4716            [419, []],
4717            [420, [convert_biblio_style]],
4718            [421, [convert_longtable_captions]],
4719            [422, [convert_use_packages]],
4720            [423, [convert_use_mathtools]],
4721            [424, [convert_cite_engine_type]],
4722            # No convert_cancel, since cancel will be loaded automatically
4723            # in format 425 without any possibility to switch it off.
4724            # This has been fixed in format 464.
4725            [425, []],
4726            [426, []],
4727            [427, []],
4728            [428, [convert_cell_rotation]],
4729            [429, [convert_table_rotation]],
4730            [430, [convert_listoflistings]],
4731            [431, [convert_use_amssymb]],
4732            [432, []],
4733            [433, [convert_armenian]],
4734            [434, []],
4735            [435, []],
4736            [436, []],
4737            [437, []],
4738            [438, []],
4739            [439, []],
4740            [440, []],
4741            [441, [convert_mdnomath]],
4742            [442, []],
4743            [443, []],
4744            [444, []],
4745            [445, []],
4746            [446, [convert_latexargs]],
4747            [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV, convert_Initials, convert_ModernCV]],
4748            [448, [convert_literate]],
4749            [449, []],
4750            [450, []],
4751            [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]],
4752            [452, [convert_beamerblocks]],
4753            [453, [convert_use_stmaryrd]],
4754            [454, [convert_overprint]],
4755            [455, []],
4756            [456, [convert_epigraph]],
4757            [457, [convert_use_stackrel]],
4758            [458, [convert_captioninsets, convert_captionlayouts]],
4759            [459, []],
4760            [460, []],
4761            [461, []],
4762            [462, []],
4763            [463, [convert_encodings]],
4764            [464, [convert_use_cancel]],
4765            [465, [convert_lyxframes, remove_endframes]],
4766            [466, []],
4767            [467, []],
4768            [468, []],
4769            [469, []],
4770            [470, []],
4771            [471, [convert_cite_engine_type_default]],
4772            [472, []],
4773            [473, []],
4774            [474, [convert_chunks, cleanup_beamerargs]],
4775           ]
4776
4777 revert =  [
4778            [473, [revert_chunks]],
4779            [472, [revert_tibetan]],
4780            [471, [revert_aa1,revert_aa2]],
4781            [470, [revert_cite_engine_type_default]],
4782            [469, [revert_forced_local_layout]],
4783            [468, [revert_starred_caption]],
4784            [467, [revert_mbox_fbox]],
4785            [466, [revert_iwona_fonts]],
4786            [465, [revert_powerdot_flexes, revert_powerdot_pause, revert_powerdot_itemargs, revert_powerdot_columns]],
4787            [464, []],
4788            [463, [revert_use_cancel]],
4789            [462, [revert_encodings]],
4790            [461, [revert_new_libertines]],
4791            [460, [revert_kurier_fonts]],
4792            [459, [revert_IEEEtran_3]],
4793            [458, [revert_fragileframe, revert_newframes]],
4794            [457, [revert_captioninsets, revert_captionlayouts]],
4795            [456, [revert_use_stackrel]],
4796            [455, [revert_epigraph]],
4797            [454, [revert_frametitle]],
4798            [453, [revert_overprint]],
4799            [452, [revert_use_stmaryrd]],
4800            [451, [revert_beamerblocks]],
4801            [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
4802            [449, [revert_garamondx, revert_garamondx_newtxmath]],
4803            [448, [revert_itemargs]],
4804            [447, [revert_literate]],
4805            [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]],
4806            [445, [revert_latexargs]],
4807            [444, [revert_uop]],
4808            [443, [revert_biolinum]],
4809            [442, []],
4810            [441, [revert_newtxmath]],
4811            [440, [revert_mdnomath]],
4812            [439, [revert_mathfonts]],
4813            [438, [revert_minionpro]],
4814            [437, [revert_ipadeco, revert_ipachar]],
4815            [436, [revert_texgyre]],
4816            [435, [revert_mathdesign]],
4817            [434, [revert_txtt]],
4818            [433, [revert_libertine]],
4819            [432, [revert_armenian]],
4820            [431, [revert_languages, revert_ancientgreek]],
4821            [430, [revert_use_amssymb]],
4822            [429, [revert_listoflistings]],
4823            [428, [revert_table_rotation]],
4824            [427, [revert_cell_rotation]],
4825            [426, [revert_tipa]],
4826            [425, [revert_verbatim]],
4827            [424, [revert_cancel]],
4828            [423, [revert_cite_engine_type]],
4829            [422, [revert_use_mathtools]],
4830            [421, [revert_use_packages]],
4831            [420, [revert_longtable_captions]],
4832            [419, [revert_biblio_style]],
4833            [418, [revert_australian]],
4834            [417, [revert_justification]],
4835            [416, [revert_japanese_encodings]],
4836            [415, [revert_negative_space, revert_math_spaces]],
4837            [414, [revert_undertilde]],
4838            [413, [revert_visible_space]]
4839           ]
4840
4841
4842 if __name__ == "__main__":
4843     pass