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