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