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