]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_1.py
041ed919c153e48b5814e57638e1c7d081f6e9ca
[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 def convert_againframe_args(document):
2188     " Converts beamer AgainFrame to new layout "
2189
2190     # FIXME: This currently only works if the arguments are in one single ERT
2191     
2192     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2193     if document.textclass not in beamer_classes:
2194         return
2195    
2196     i = 0
2197     while True:
2198         i = find_token(document.body, "\\begin_layout AgainFrame", i)
2199         if i == -1:
2200             break
2201         parent = get_containing_layout(document.body, i)
2202         if parent[1] != i:
2203             document.warning("Wrong parent layout!")
2204         j = parent[2]
2205         parbeg = parent[3]
2206         if i != -1:
2207             if document.body[parbeg] == "\\begin_inset ERT":
2208                 ertcont = parbeg + 5
2209                 if document.body[ertcont].startswith("[<"):
2210                     # This is a default overlay specification
2211                     # strip off the [<
2212                     document.body[ertcont] = document.body[ertcont][2:]
2213                     if document.body[ertcont].endswith(">]"):
2214                         # strip off the >]
2215                         document.body[ertcont] = document.body[ertcont][:-2]
2216                     elif document.body[ertcont].endswith("]"):
2217                         # divide the args
2218                         tok = document.body[ertcont].find('>][')
2219                         if tok != -1:
2220                             subst = [document.body[ertcont][:tok],
2221                                      '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2222                                      'status collapsed', '', '\\begin_layout Plain Layout',
2223                                      document.body[ertcont][tok + 3:-1]]
2224                             document.body[ertcont : ertcont + 1] = subst
2225                      # Convert to ArgInset
2226                     document.body[parbeg] = "\\begin_inset Argument 2"
2227                     i = j
2228                     continue
2229                 elif document.body[ertcont].startswith("<"):
2230                     # This is an overlay specification
2231                     # strip off the <
2232                     document.body[ertcont] = document.body[ertcont][1:]
2233                     if document.body[ertcont].endswith(">"):
2234                         # strip off the >
2235                         document.body[ertcont] = document.body[ertcont][:-1]
2236                         # Convert to ArgInset
2237                         document.body[parbeg] = "\\begin_inset Argument 1"
2238                     elif document.body[ertcont].endswith(">]"):
2239                         # divide the args
2240                         tok = document.body[ertcont].find('>[<')
2241                         if tok != -1:
2242                            document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2243                                                            '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2244                                                            'status collapsed', '', '\\begin_layout Plain Layout',
2245                                                            document.body[ertcont][tok + 3:-2]]
2246                         # Convert to ArgInset
2247                         document.body[parbeg] = "\\begin_inset Argument 1"
2248                     elif document.body[ertcont].endswith("]"):
2249                         # divide the args
2250                         tok = document.body[ertcont].find('>[<')
2251                         if tok != -1:
2252                            # divide the args
2253                            tokk = document.body[ertcont].find('>][')
2254                            if tokk != -1:
2255                                document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2256                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2257                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2258                                                                document.body[ertcont][tok + 3:tokk],
2259                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2260                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2261                                                                document.body[ertcont][tokk + 3:-1]]
2262                         else:
2263                             tokk = document.body[ertcont].find('>[')
2264                             if tokk != -1:
2265                                 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
2266                                                                 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2267                                                                 'status collapsed', '', '\\begin_layout Plain Layout',
2268                                                                 document.body[ertcont][tokk + 2:-1]]
2269                         # Convert to ArgInset
2270                         document.body[parbeg] = "\\begin_inset Argument 1"
2271                     i = j
2272                     continue
2273                 elif document.body[ertcont].startswith("["):
2274                     # This is an ERT option
2275                     # strip off the [
2276                     document.body[ertcont] = document.body[ertcont][1:]
2277                     if document.body[ertcont].endswith("]"):
2278                         # strip off the ]
2279                         document.body[ertcont] = document.body[ertcont][:-1]
2280                         # Convert to ArgInset
2281                         document.body[parbeg] = "\\begin_inset Argument 3"
2282                     i = j
2283                     continue
2284         i = j
2285
2286
2287 def convert_corollary_args(document):
2288     " Converts beamer corrolary-style ERT arguments native InsetArgs "
2289     
2290     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2291     if document.textclass not in beamer_classes:
2292         return
2293    
2294     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2295     for lay in corollary_layouts:
2296         i = 0
2297         while True:
2298             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2299             if i == -1:
2300                 break
2301             parent = get_containing_layout(document.body, i)
2302             if parent[1] != i:
2303                 document.warning("Wrong parent layout!")
2304             j = parent[2]
2305             parbeg = parent[3]
2306             if i != -1:
2307                 if document.body[parbeg] == "\\begin_inset ERT":
2308                     ertcont = parbeg + 5
2309                     if document.body[ertcont].startswith("<"):
2310                         # This is an overlay specification
2311                         # strip off the <
2312                         document.body[ertcont] = document.body[ertcont][1:]
2313                         if document.body[ertcont].endswith(">"):
2314                             # strip off the >
2315                             document.body[ertcont] = document.body[ertcont][:-1]
2316                         elif document.body[ertcont].endswith("]"):
2317                             # divide the args
2318                             tok = document.body[ertcont].find('>[')
2319                             if tok != -1:
2320                                 subst = [document.body[ertcont][:tok],
2321                                          '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2322                                          'status collapsed', '', '\\begin_layout Plain Layout',
2323                                          document.body[ertcont][tok + 2:-1]]
2324                                 document.body[ertcont : ertcont + 1] = subst
2325                         # Convert to ArgInset
2326                         document.body[parbeg] = "\\begin_inset Argument 1"
2327                         i = j
2328                         continue
2329                     elif document.body[ertcont].startswith("["):
2330                         if document.body[ertcont].endswith("]"):
2331                             # This is an ERT option
2332                             # strip off the [
2333                             document.body[ertcont] = document.body[ertcont][1:]
2334                             # strip off the ]
2335                             document.body[ertcont] = document.body[ertcont][:-1]
2336                             # Convert to ArgInset
2337                             document.body[parbeg] = "\\begin_inset Argument 2"
2338                         else:
2339                             convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, True)
2340                     i += 1
2341                     continue
2342             i = j
2343
2344
2345
2346 def convert_quote_args(document):
2347     " Converts beamer quote style ERT args to native InsetArgs "
2348     
2349     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2350     if document.textclass not in beamer_classes:
2351         return
2352    
2353     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2354     for lay in quote_layouts:
2355         i = 0
2356         while True:
2357             i = find_token(document.body, "\\begin_layout " + lay, i)
2358             if i == -1:
2359                 break
2360             parent = get_containing_layout(document.body, i)
2361             if parent[1] != i:
2362                 document.warning("Wrong parent layout!")
2363             j = parent[2]
2364             parbeg = parent[3]
2365             if i != -1:
2366                 if document.body[parbeg] == "\\begin_inset ERT":
2367                     if document.body[i + 6].startswith("<"):
2368                         # This is an overlay specification
2369                         # strip off the <
2370                         document.body[i + 6] = document.body[i + 6][1:]
2371                         if document.body[i + 6].endswith(">"):
2372                             # strip off the >
2373                             document.body[i + 6] = document.body[i + 6][:-1]
2374                             # Convert to ArgInset
2375                             document.body[i + 1] = "\\begin_inset Argument 1"
2376             i = j
2377
2378
2379 def revert_beamerargs(document):
2380     " Reverts beamer arguments to old layout "
2381     
2382     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2383     if document.textclass not in beamer_classes:
2384         return
2385
2386     i = 0
2387     list_layouts = ["Itemize", "Enumerate", "Description"]
2388     headings = ["Part", "Section", "Section*", "Subsection", "Subsection*",
2389                 "Subsubsection", "Subsubsection*", "FrameSubtitle", "NoteItem"]
2390     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2391     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2392     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2393
2394     while True:
2395         i = find_token(document.body, "\\begin_inset Argument", i)
2396         if i == -1:
2397             return
2398         # Find containing paragraph layout
2399         parent = get_containing_layout(document.body, i)
2400         if parent == False:
2401             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2402             i += 1
2403             continue
2404         parbeg = parent[1]
2405         parend = parent[2]
2406         realparbeg = parent[3]
2407         layoutname = parent[0]
2408         realparend = parend
2409         for p in range(parbeg, parend):
2410             if p >= realparend:
2411                 i = realparend
2412                 break
2413             if layoutname in headings:
2414                 m = rx.match(document.body[p])
2415                 if m:
2416                     argnr = m.group(1)
2417                     if argnr == "1":
2418                         # Find containing paragraph layout
2419                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2420                         endPlain = find_end_of_layout(document.body, beginPlain)
2421                         endInset = find_end_of_inset(document.body, p)
2422                         argcontent = document.body[beginPlain + 1 : endPlain]
2423                         # Adjust range end
2424                         realparend = realparend - len(document.body[p : endInset + 1])
2425                         # Remove arg inset
2426                         del document.body[p : endInset + 1]
2427                         if layoutname == "FrameSubtitle":
2428                             pre = put_cmd_in_ert("\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2429                         elif layoutname == "NoteItem":
2430                             pre = put_cmd_in_ert("\\note<") + argcontent + put_cmd_in_ert(">[item]")
2431                         elif layoutname.endswith('*'):
2432                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower()[:-1] + "<") + argcontent + put_cmd_in_ert(">*")
2433                         else:
2434                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2435                         secarg = find_token(document.body, "\\begin_inset Argument 2", parbeg, parend)
2436                         if secarg != -1:
2437                             # Find containing paragraph layout
2438                             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", secarg)
2439                             endPlain = find_end_of_layout(document.body, beginPlain)
2440                             endInset = find_end_of_inset(document.body, secarg)
2441                             argcontent = document.body[beginPlain + 1 : endPlain]
2442                             # Adjust range end
2443                             realparend = realparend - len(document.body[secarg : endInset + 1])
2444                             del document.body[secarg : endInset + 1]
2445                             pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2446                         pre += put_cmd_in_ert("{")
2447                         document.body[parbeg] = "\\begin_layout Standard"
2448                         document.body[realparbeg : realparbeg] = pre
2449                         pe = find_end_of_layout(document.body, parbeg)
2450                         post = put_cmd_in_ert("}")
2451                         document.body[pe : pe] = post
2452                         realparend += len(pre) + len(post)
2453             if layoutname == "AgainFrame":
2454                 m = rx.match(document.body[p])
2455                 if m:
2456                     argnr = m.group(1)
2457                     if argnr == "3":
2458                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2459                         endPlain = find_end_of_layout(document.body, beginPlain)
2460                         endInset = find_end_of_inset(document.body, p)
2461                         content = document.body[beginPlain + 1 : endPlain]
2462                         # Adjust range end
2463                         realparend = realparend - len(document.body[p : endInset + 1])
2464                         # Remove arg inset
2465                         del document.body[p : endInset + 1]
2466                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2467                         document.body[realparbeg : realparbeg] = subst
2468             if layoutname == "Overprint":
2469                 m = rx.match(document.body[p])
2470                 if m:
2471                     argnr = m.group(1)
2472                     if argnr == "1":
2473                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2474                         endPlain = find_end_of_layout(document.body, beginPlain)
2475                         endInset = find_end_of_inset(document.body, p)
2476                         content = document.body[beginPlain + 1 : endPlain]
2477                         # Adjust range end
2478                         realparend = realparend - len(document.body[p : endInset + 1])
2479                         # Remove arg inset
2480                         del document.body[p : endInset + 1]
2481                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2482                         document.body[realparbeg : realparbeg] = subst
2483             if layoutname == "OverlayArea":
2484                 m = rx.match(document.body[p])
2485                 if m:
2486                     argnr = m.group(1)
2487                     if argnr == "2":
2488                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2489                         endPlain = find_end_of_layout(document.body, beginPlain)
2490                         endInset = find_end_of_inset(document.body, p)
2491                         content = document.body[beginPlain + 1 : endPlain]
2492                         # Adjust range end
2493                         realparend = realparend - len(document.body[p : endInset + 1])
2494                         # Remove arg inset
2495                         del document.body[p : endInset + 1]
2496                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2497                         document.body[realparbeg : realparbeg] = subst
2498             if layoutname in list_layouts:
2499                 m = rx.match(document.body[p])
2500                 if m:
2501                     argnr = m.group(1)
2502                     if argnr == "1":
2503                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2504                         endPlain = find_end_of_layout(document.body, beginPlain)
2505                         endInset = find_end_of_inset(document.body, p)
2506                         content = document.body[beginPlain + 1 : endPlain]
2507                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2508                         realparend = realparend + len(subst) - len(content)
2509                         document.body[beginPlain + 1 : endPlain] = subst
2510                     elif argnr == "item:1":
2511                         j = find_end_of_inset(document.body, i)
2512                         # Find containing paragraph layout
2513                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2514                         endPlain = find_end_of_layout(document.body, beginPlain)
2515                         content = document.body[beginPlain + 1 : endPlain]
2516                         del document.body[i:j+1]
2517                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2518                         document.body[realparbeg : realparbeg] = subst
2519                     elif argnr == "item:2":
2520                         j = find_end_of_inset(document.body, i)
2521                         # Find containing paragraph layout
2522                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2523                         endPlain = find_end_of_layout(document.body, beginPlain)
2524                         content = document.body[beginPlain + 1 : endPlain]
2525                         del document.body[i:j+1]
2526                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2527                         document.body[realparbeg : realparbeg] = subst
2528             if layoutname in quote_layouts:
2529                 m = rx.match(document.body[p])
2530                 if m:
2531                     argnr = m.group(1)
2532                     if argnr == "1":
2533                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2534                         endPlain = find_end_of_layout(document.body, beginPlain)
2535                         endInset = find_end_of_inset(document.body, p)
2536                         content = document.body[beginPlain + 1 : endPlain]
2537                         # Adjust range end
2538                         realparend = realparend - len(document.body[p : endInset + 1])
2539                         # Remove arg inset
2540                         del document.body[p : endInset + 1]
2541                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2542                         document.body[realparbeg : realparbeg] = subst
2543             if layoutname in corollary_layouts:
2544                 m = rx.match(document.body[p])
2545                 if m:
2546                     argnr = m.group(1)
2547                     if argnr == "2":
2548                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2549                         endPlain = find_end_of_layout(document.body, beginPlain)
2550                         endInset = find_end_of_inset(document.body, p)
2551                         content = document.body[beginPlain + 1 : endPlain]
2552                         # Adjust range end
2553                         realparend = realparend - len(document.body[p : endInset + 1])
2554                         # Remove arg inset
2555                         del document.body[p : endInset + 1]
2556                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2557                         document.body[realparbeg : realparbeg] = subst
2558         
2559         i = realparend
2560
2561
2562 def revert_beamerargs2(document):
2563     " Reverts beamer arguments to old layout, step 2 "
2564     
2565     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2566     if document.textclass not in beamer_classes:
2567         return
2568
2569     i = 0
2570     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2571     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2572     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2573
2574     while True:
2575         i = find_token(document.body, "\\begin_inset Argument", i)
2576         if i == -1:
2577             return
2578         # Find containing paragraph layout
2579         parent = get_containing_layout(document.body, i)
2580         if parent == False:
2581             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2582             i += 1
2583             continue
2584         parbeg = parent[1]
2585         parend = parent[2]
2586         realparbeg = parent[3]
2587         layoutname = parent[0]
2588         realparend = parend
2589         for p in range(parbeg, parend):
2590             if p >= realparend:
2591                 i = realparend
2592                 break
2593             if layoutname in shifted_layouts:
2594                 m = rx.match(document.body[p])
2595                 if m:
2596                     argnr = m.group(1)
2597                     if argnr == "2":
2598                         document.body[p] = "\\begin_inset Argument 1"       
2599             if layoutname in corollary_layouts:
2600                 m = rx.match(document.body[p])
2601                 if m:
2602                     argnr = m.group(1)
2603                     if argnr == "1":
2604                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2605                         endPlain = find_end_of_layout(document.body, beginPlain)
2606                         endInset = find_end_of_inset(document.body, p)
2607                         content = document.body[beginPlain + 1 : endPlain]
2608                         # Adjust range end
2609                         realparend = realparend - len(document.body[p : endInset + 1])
2610                         # Remove arg inset
2611                         del document.body[p : endInset + 1]
2612                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2613                         document.body[realparbeg : realparbeg] = subst
2614             if layoutname == "OverlayArea":
2615                 m = rx.match(document.body[p])
2616                 if m:
2617                     argnr = m.group(1)
2618                     if argnr == "1":
2619                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2620                         endPlain = find_end_of_layout(document.body, beginPlain)
2621                         endInset = find_end_of_inset(document.body, p)
2622                         content = document.body[beginPlain + 1 : endPlain]
2623                         # Adjust range end
2624                         realparend = realparend - len(document.body[p : endInset + 1])
2625                         # Remove arg inset
2626                         del document.body[p : endInset + 1]
2627                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2628                         document.body[realparbeg : realparbeg] = subst
2629             if layoutname == "AgainFrame":
2630                 m = rx.match(document.body[p])
2631                 if m:
2632                     argnr = m.group(1)
2633                     if argnr == "2":
2634                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2635                         endPlain = find_end_of_layout(document.body, beginPlain)
2636                         endInset = find_end_of_inset(document.body, p)
2637                         content = document.body[beginPlain + 1 : endPlain]
2638                         # Adjust range end
2639                         realparend = realparend - len(document.body[p : endInset + 1])
2640                         # Remove arg inset
2641                         del document.body[p : endInset + 1]
2642                         subst = put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
2643                         document.body[realparbeg : realparbeg] = subst
2644         i = realparend
2645
2646
2647 def revert_beamerargs3(document):
2648     " Reverts beamer arguments to old layout, step 3 "
2649     
2650     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2651     if document.textclass not in beamer_classes:
2652         return
2653
2654     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2655     i = 0
2656     while True:
2657         i = find_token(document.body, "\\begin_inset Argument", i)
2658         if i == -1:
2659             return
2660         # Find containing paragraph layout
2661         parent = get_containing_layout(document.body, i)
2662         if parent == False:
2663             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2664             i += 1
2665             continue
2666         parbeg = parent[1]
2667         parend = parent[2]
2668         realparbeg = parent[3]
2669         layoutname = parent[0]
2670         realparend = parend
2671         for p in range(parbeg, parend):
2672             if p >= realparend:
2673                 i = realparend
2674                 break
2675             if layoutname == "AgainFrame":
2676                 m = rx.match(document.body[p])
2677                 if m:
2678                     argnr = m.group(1)
2679                     if argnr == "1":
2680                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2681                         endPlain = find_end_of_layout(document.body, beginPlain)
2682                         endInset = find_end_of_inset(document.body, p)
2683                         content = document.body[beginPlain + 1 : endPlain]
2684                         # Adjust range end
2685                         realparend = realparend - len(document.body[p : endInset + 1])
2686                         # Remove arg inset
2687                         del document.body[p : endInset + 1]
2688                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2689                         document.body[realparbeg : realparbeg] = subst
2690         i = realparend
2691
2692
2693 def revert_beamerflex(document):
2694     " Reverts beamer Flex insets "
2695     
2696     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2697     if document.textclass not in beamer_classes:
2698         return
2699
2700     new_flexes = {"Bold" : "\\textbf", "Emphasize" : "\\emph", "Only" : "\\only",
2701                   "Uncover" : "\\uncover", "Visible" : "\\visible",
2702                   "Invisible" : "\\invisible", "Alternative" : "\\alt",
2703                   "Beamer_Note" : "\\note"}
2704     old_flexes = {"Alert" : "\\alert", "Structure" : "\\structure"}
2705     rx = re.compile(r'^\\begin_inset Flex (.+)$')
2706
2707     i = 0
2708     while True:
2709         i = find_token(document.body, "\\begin_inset Flex", i)
2710         if i == -1:
2711             return
2712         m = rx.match(document.body[i])
2713         if m:
2714             flextype = m.group(1)
2715             z = find_end_of_inset(document.body, i)
2716             if z == -1:
2717                 document.warning("Can't find end of Flex " + flextype + " inset.")
2718                 i += 1
2719                 continue
2720             if flextype in new_flexes:
2721                 pre = put_cmd_in_ert(new_flexes[flextype])
2722                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2723                 if arg != -1:
2724                     argend = find_end_of_inset(document.body, arg)
2725                     if argend == -1:
2726                         document.warning("Can't find end of Argument!")
2727                         i += 1
2728                         continue
2729                     # Find containing paragraph layout
2730                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2731                     endPlain = find_end_of_layout(document.body, beginPlain)
2732                     argcontent = document.body[beginPlain + 1 : endPlain]
2733                     # Adjust range end
2734                     z = z - len(document.body[arg : argend + 1])
2735                     # Remove arg inset
2736                     del document.body[arg : argend + 1]
2737                     pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2738                 arg = find_token(document.body, "\\begin_inset Argument 2", i, z)
2739                 if arg != -1:
2740                     argend = find_end_of_inset(document.body, arg)
2741                     if argend == -1:
2742                         document.warning("Can't find end of Argument!")
2743                         i += 1
2744                         continue
2745                     # Find containing paragraph layout
2746                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2747                     endPlain = find_end_of_layout(document.body, beginPlain)
2748                     argcontent = document.body[beginPlain + 1 : endPlain]
2749                     # Adjust range end
2750                     z = z - len(document.body[arg : argend + 1])
2751                     # Remove arg inset
2752                     del document.body[arg : argend + 1]
2753                     if flextype == "Alternative":
2754                         pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
2755                     else:
2756                         pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2757                 pre += put_cmd_in_ert("{")
2758                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2759                 endPlain = find_end_of_layout(document.body, beginPlain)
2760                 # Adjust range end
2761                 z = z - len(document.body[i : beginPlain + 1])
2762                 z += len(pre)
2763                 document.body[i : beginPlain + 1] = pre
2764                 post = put_cmd_in_ert("}")
2765                 document.body[z - 2 : z + 1] = post
2766             elif flextype in old_flexes:
2767                 pre = put_cmd_in_ert(old_flexes[flextype])
2768                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2769                 if arg == -1:
2770                     i += 1
2771                     continue
2772                 argend = find_end_of_inset(document.body, arg)
2773                 if argend == -1:
2774                     document.warning("Can't find end of Argument!")
2775                     i += 1
2776                     continue
2777                 # Find containing paragraph layout
2778                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2779                 endPlain = find_end_of_layout(document.body, beginPlain)
2780                 argcontent = document.body[beginPlain + 1 : endPlain]
2781                 # Adjust range end
2782                 z = z - len(document.body[arg : argend + 1])
2783                 # Remove arg inset
2784                 del document.body[arg : argend + 1]
2785                 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2786                 pre += put_cmd_in_ert("{")
2787                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2788                 endPlain = find_end_of_layout(document.body, beginPlain)
2789                 # Adjust range end
2790                 z = z - len(document.body[i : beginPlain + 1])
2791                 z += len(pre)
2792                 document.body[i : beginPlain + 1] = pre
2793                 post = put_cmd_in_ert("}")
2794                 document.body[z - 2 : z + 1] = post
2795         
2796         i += 1
2797
2798
2799 def revert_beamerblocks(document):
2800     " Reverts beamer block arguments to ERT "
2801     
2802     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2803     if document.textclass not in beamer_classes:
2804         return
2805
2806     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2807
2808     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2809     i = 0
2810     while True:
2811         i = find_token(document.body, "\\begin_inset Argument", i)
2812         if i == -1:
2813             return
2814         # Find containing paragraph layout
2815         parent = get_containing_layout(document.body, i)
2816         if parent == False:
2817             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2818             i += 1
2819             continue
2820         parbeg = parent[1]
2821         parend = parent[2]
2822         realparbeg = parent[3]
2823         layoutname = parent[0]
2824         realparend = parend
2825         for p in range(parbeg, parend):
2826             if p >= realparend:
2827                 i = realparend
2828                 break
2829             if layoutname in blocks:
2830                 m = rx.match(document.body[p])
2831                 if m:
2832                     argnr = m.group(1)
2833                     if argnr == "1":
2834                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2835                         endPlain = find_end_of_layout(document.body, beginPlain)
2836                         endInset = find_end_of_inset(document.body, p)
2837                         content = document.body[beginPlain + 1 : endPlain]
2838                         # Adjust range end
2839                         realparend = realparend - len(document.body[p : endInset + 1])
2840                         # Remove arg inset
2841                         del document.body[p : endInset + 1]
2842                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2843                         document.body[realparbeg : realparbeg] = subst
2844                     elif argnr == "2":
2845                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2846                         endPlain = find_end_of_layout(document.body, beginPlain)
2847                         endInset = find_end_of_inset(document.body, p)
2848                         content = document.body[beginPlain + 1 : endPlain]
2849                         # Adjust range end
2850                         realparend = realparend - len(document.body[p : endInset + 1])
2851                         # Remove arg inset
2852                         del document.body[p : endInset + 1]
2853                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2854                         document.body[realparbeg : realparbeg] = subst
2855         i = realparend
2856
2857
2858
2859 def convert_beamerblocks(document):
2860     " Converts beamer block ERT args to native InsetArgs "
2861     
2862     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2863     if document.textclass not in beamer_classes:
2864         return
2865    
2866     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2867     for lay in blocks:
2868         i = 0
2869         while True:
2870             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2871             if i == -1:
2872                 break
2873             parent = get_containing_layout(document.body, i)
2874             if parent == False or parent[1] != i:
2875                 document.warning("Wrong parent layout!")
2876                 i += 1
2877                 continue
2878             j = parent[2]
2879             parbeg = parent[3]
2880             if i != -1:
2881                 if document.body[parbeg] == "\\begin_inset ERT":
2882                     ertcont = parbeg + 5
2883                     while True:
2884                         if document.body[ertcont].startswith("<"):
2885                             # This is an overlay specification
2886                             # strip off the <
2887                             document.body[ertcont] = document.body[ertcont][1:]
2888                             if document.body[ertcont].endswith(">"):
2889                                 # strip off the >
2890                                 document.body[ertcont] = document.body[ertcont][:-1]
2891                                 # Convert to ArgInset
2892                                 document.body[parbeg] = "\\begin_inset Argument 1"
2893                             elif document.body[ertcont].endswith("}"):
2894                                 # divide the args
2895                                 tok = document.body[ertcont].find('>{')
2896                                 if tok != -1:
2897                                     document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2898                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2899                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
2900                                                                             document.body[ertcont][tok + 2:-1]]
2901                             # Convert to ArgInset
2902                             document.body[parbeg] = "\\begin_inset Argument 1"
2903                         elif document.body[ertcont].startswith("{"):
2904                             # This is the block title
2905                             if document.body[ertcont].endswith("}"):
2906                                 # strip off the braces
2907                                 document.body[ertcont] = document.body[ertcont][1:-1]
2908                                 # Convert to ArgInset
2909                                 document.body[parbeg] = "\\begin_inset Argument 2"
2910                             elif count_pars_in_inset(document.body, ertcont) > 1:
2911                                 # Multipar ERT. Skip this.
2912                                 break
2913                             else:
2914                                 convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, False)
2915                         else:
2916                             break
2917                         j = find_end_of_layout(document.body, i)
2918                         if j == -1:
2919                             document.warning("end of layout not found!")
2920                         k = find_token(document.body, "\\begin_inset Argument", i, j)
2921                         if k == -1:
2922                             document.warning("InsetArgument not found!")
2923                             break
2924                         l = find_end_of_inset(document.body, k)
2925                         m = find_token(document.body, "\\begin_inset ERT", l, j)
2926                         if m == -1:
2927                             break
2928                         ertcont = m + 5
2929                         parbeg = m
2930             i = j
2931
2932
2933 def convert_overprint(document):
2934     " Convert old beamer overprint layouts to ERT "
2935     
2936     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2937     if document.textclass not in beamer_classes:
2938         return
2939
2940     i = 0
2941     while True:
2942         i = find_token(document.body, "\\begin_layout Overprint", i)
2943         if i == -1:
2944             return
2945         # Find end of sequence
2946         j = find_end_of_sequence(document.body, i)
2947         if j == -1:
2948             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
2949             i += 1
2950             continue
2951         endseq = j
2952         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
2953         esubst = list()
2954         if document.body[j] == "\\end_deeper":
2955             esubst = ["", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2956         else:
2957             esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2958         endseq = endseq + len(esubst) - len(document.body[j : j])
2959         document.body[j : j] = esubst
2960         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2961         if argbeg != -1:
2962             argend = find_end_of_layout(document.body, argbeg)
2963             if argend == -1:
2964                 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
2965                 i += 1
2966                 continue
2967             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2968             endPlain = find_end_of_layout(document.body, beginPlain)
2969             content = document.body[beginPlain + 1 : endPlain]
2970             # Adjust range end
2971             endseq = endseq - len(document.body[argbeg : argend + 1])
2972             # Remove arg inset
2973             del document.body[argbeg : argend + 1]
2974             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2975             
2976         endseq = endseq - len(document.body[i : i])
2977         document.body[i : i] = subst + ["\\end_layout"]
2978         endseq += len(subst)
2979         
2980         for p in range(i, endseq):
2981             if document.body[p] == "\\begin_layout Overprint":
2982                 document.body[p] = "\\begin_layout Standard"
2983
2984         i = endseq
2985
2986
2987 def revert_overprint(document):
2988     " Revert old beamer overprint layouts to ERT "
2989     
2990     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2991     if document.textclass not in beamer_classes:
2992         return
2993
2994     i = 0
2995     while True:
2996         i = find_token(document.body, "\\begin_layout Overprint", i)
2997         if i == -1:
2998             return
2999         # Find end of sequence
3000         j = find_end_of_sequence(document.body, i)
3001         if j == -1:
3002             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3003             i += 1
3004             continue
3005         endseq = j
3006         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3007         esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}")
3008         endseq = endseq + len(esubst) - len(document.body[j : j])
3009         if document.body[j] == "\\end_deeper":
3010             document.body[j : j] = ["\\end_deeper", ""] + esubst
3011         else:
3012             document.body[j : j] = esubst
3013         r = i
3014         while r < j:
3015             if document.body[r] == "\\begin_deeper":
3016                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3017                 if s != -1:
3018                     document.body[r] = ""
3019                     document.body[s] = ""
3020                     r = s
3021                     continue
3022             r = r + 1
3023         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3024         if argbeg != -1:
3025             argend = find_end_of_inset(document.body, argbeg)
3026             if argend == -1:
3027                 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3028                 i += 1
3029                 continue
3030             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3031             endPlain = find_end_of_layout(document.body, beginPlain)
3032             content = document.body[beginPlain + 1 : endPlain]
3033             # Adjust range end
3034             endseq = endseq - len(document.body[argbeg : argend])
3035             # Remove arg inset
3036             del document.body[argbeg : argend + 1]
3037             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3038             
3039         endseq = endseq - len(document.body[i : i])
3040         document.body[i : i] = subst + ["\\end_layout"]
3041         endseq += len(subst)
3042      
3043         p = i
3044         while True:
3045             if p >= endseq:
3046                 break
3047             if document.body[p] == "\\begin_layout Overprint":
3048                 q = find_end_of_layout(document.body, p)
3049                 if q == -1:
3050                     document.warning("Malformed LyX document. Cannot find end of Overprint layout!")
3051                     p += 1
3052                     continue
3053                 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\onslide")
3054                 argbeg = find_token(document.body, "\\begin_inset Argument item:1", p, q)
3055                 if argbeg != -1:
3056                     argend = find_end_of_inset(document.body, argbeg)
3057                     if argend == -1:
3058                         document.warning("Malformed LyX document. Cannot find end of Overprint item argument!")
3059                         p += 1
3060                         continue
3061                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3062                     endPlain = find_end_of_layout(document.body, beginPlain)
3063                     content = document.body[beginPlain + 1 : endPlain]
3064                     # Adjust range end
3065                     endseq = endseq - len(document.body[argbeg : argend + 1])
3066                     # Remove arg inset
3067                     del document.body[argbeg : argend + 1]
3068                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3069                 endseq = endseq - len(document.body[p : p + 1]) + len(subst)
3070                 document.body[p : p + 1] = subst
3071             p = p + 1
3072
3073         i = endseq
3074
3075
3076 def revert_frametitle(document):
3077     " Reverts beamer frametitle layout to ERT "
3078     
3079     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3080     if document.textclass not in beamer_classes:
3081         return
3082
3083     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3084     i = 0
3085     while True:
3086         i = find_token(document.body, "\\begin_layout FrameTitle", i)
3087         if i == -1:
3088             return
3089         j = find_end_of_layout(document.body, i)
3090         if j == -1:
3091             document.warning("Malformed LyX document: Can't find end of FrameTitle layout")
3092             i += 1
3093             continue
3094         endlay = j
3095         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
3096         endlay += len(put_cmd_in_ert("}"))
3097         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\frametitle")
3098         for p in range(i, j):
3099             if p >= endlay:
3100                 break
3101             m = rx.match(document.body[p])
3102             if m:
3103                 argnr = m.group(1)
3104                 if argnr == "1":
3105                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3106                     endPlain = find_end_of_layout(document.body, beginPlain)
3107                     endInset = find_end_of_inset(document.body, p)
3108                     content = document.body[beginPlain + 1 : endPlain]
3109                     # Adjust range end
3110                     endlay = endlay - len(document.body[p : endInset + 1])
3111                     # Remove arg inset
3112                     del document.body[p : endInset + 1]
3113                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3114                 elif argnr == "2":
3115                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3116                     endPlain = find_end_of_layout(document.body, beginPlain)
3117                     endInset = find_end_of_inset(document.body, p)
3118                     content = document.body[beginPlain + 1 : endPlain]
3119                     # Adjust range end
3120                     endlay = endlay - len(document.body[p : endInset + 1])
3121                     # Remove arg inset
3122                     del document.body[p : endInset + 1]
3123                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3124                     
3125         subst += put_cmd_in_ert("{")
3126         document.body[i : i + 1] = subst
3127         i = endlay
3128
3129
3130 def convert_epigraph(document):
3131     " Converts memoir epigraph to new syntax "
3132     
3133     if document.textclass != "memoir":
3134         return
3135
3136     i = 0
3137     while True:
3138         i = find_token(document.body, "\\begin_layout Epigraph", i)
3139         if i == -1:
3140             return
3141         j = find_end_of_layout(document.body, i)
3142         if j == -1:
3143             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3144             i += 1
3145             continue
3146         endlay = j
3147         subst = list()
3148         ert = find_token(document.body, "\\begin_inset ERT", i, j)
3149         if ert != -1:
3150             endInset = find_end_of_inset(document.body, ert)
3151             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", ert)
3152             endPlain = find_end_of_layout(document.body, beginPlain)
3153             ertcont = beginPlain + 2
3154             if document.body[ertcont] == "}{":
3155                 # strip off the <
3156                 # Convert to ArgInset
3157                 endlay = endlay - 2 * len(document.body[j])
3158                 begsubst = ['\\begin_inset Argument post:1', 'status collapsed', '',
3159                             '\\begin_layout Plain Layout']
3160                 endsubst = ['\\end_layout', '', '\\end_inset', '', document.body[j]]
3161                 document.body[j : j + 1] = endsubst
3162                 document.body[endInset + 1 : endInset + 1] = begsubst
3163                 # Adjust range end
3164                 endlay += len(begsubst) + len(endsubst)
3165                 endlay = endlay - len(document.body[ert : endInset + 1])
3166                 del document.body[ert : endInset + 1]
3167                     
3168         i = endlay
3169
3170
3171 def revert_epigraph(document):
3172     " Reverts memoir epigraph argument to ERT "
3173     
3174     if document.textclass != "memoir":
3175         return
3176
3177     i = 0
3178     while True:
3179         i = find_token(document.body, "\\begin_layout Epigraph", i)
3180         if i == -1:
3181             return
3182         j = find_end_of_layout(document.body, i)
3183         if j == -1:
3184             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3185             i += 1
3186             continue
3187         endlay = j
3188         subst = list()
3189         p = find_token(document.body, "\\begin_layout Argument post:1", i, j)
3190         if p != -1:
3191             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3192             endPlain = find_end_of_layout(document.body, beginPlain)
3193             endInset = find_end_of_inset(document.body, p)
3194             content = document.body[beginPlain + 1 : endPlain]
3195             # Adjust range end
3196             endlay = endlay - len(document.body[p : endInset + 1])
3197             # Remove arg inset
3198             del document.body[p : endInset + 1]
3199             subst += put_cmd_in_ert("}{") + content
3200         else:
3201             subst += put_cmd_in_ert("}{")
3202                     
3203         document.body[j : j] = subst + document.body[j : j]
3204         i = endlay
3205
3206
3207 def convert_captioninsets(document):
3208     " Converts caption insets to new syntax "
3209     
3210     i = 0
3211     while True:
3212       i = find_token(document.body, "\\begin_inset Caption", i)
3213       if i == -1:
3214           return
3215       document.body[i] = "\\begin_inset Caption Standard"
3216       i += 1
3217
3218
3219 def revert_captioninsets(document):
3220     " Reverts caption insets to old syntax "
3221     
3222     i = 0
3223     while True:
3224       i = find_token(document.body, "\\begin_inset Caption Standard", i)
3225       if i == -1:
3226           return
3227       document.body[i] = "\\begin_inset Caption"
3228       i += 1
3229
3230
3231 def convert_captionlayouts(document):
3232     " Convert caption layouts to caption insets. "
3233
3234     caption_dict = {
3235         "Captionabove":  "Above",
3236         "Captionbelow":  "Below",
3237         "FigCaption"  :  "FigCaption",
3238         "Table_Caption" :  "Table",
3239         "CenteredCaption" : "Centered",
3240         "Bicaption" : "Bicaption",
3241         }
3242
3243     i = 0
3244     while True:
3245         i = find_token(document.body, "\\begin_layout", i)
3246         if i == -1:
3247             return
3248         val = get_value(document.body, "\\begin_layout", i)
3249         if val in caption_dict.keys():
3250             j = find_end_of_layout(document.body, i)
3251             if j == -1:
3252                 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3253                 return
3254
3255             document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""]
3256             document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout,
3257                                     "\\begin_inset Caption %s" % caption_dict[val], "",
3258                                     "\\begin_layout %s" % document.default_layout]
3259         i += 1
3260
3261
3262 def revert_captionlayouts(document):
3263     " Revert caption insets to caption layouts. "
3264     
3265     caption_dict = {
3266         "Above" : "Captionabove",
3267         "Below" : "Captionbelow",
3268         "FigCaption"  :  "FigCaption",
3269         "Table" : "Table_Caption",
3270         "Centered" : "CenteredCaption",
3271         "Bicaption" : "Bicaption",
3272         }
3273     
3274     i = 0
3275     rx = re.compile(r'^\\begin_inset Caption (\S+)$')
3276     while True:
3277         i = find_token(document.body, "\\begin_inset Caption", i)
3278         if i == -1:
3279             return
3280
3281         m = rx.match(document.body[i])
3282         val = ""
3283         if m:
3284             val = m.group(1)
3285         if val not in caption_dict.keys():
3286             i += 1
3287             continue
3288         
3289         # We either need to delete the previous \begin_layout line, or we
3290         # need to end the previous layout if this inset is not in the first
3291         # position of the paragraph.
3292         layout_before = find_token_backwards(document.body, "\\begin_layout", i)
3293         if layout_before == -1:
3294             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3295             return
3296         layout_line = document.body[layout_before]
3297         del_layout_before = True
3298         l = layout_before + 1
3299         while l < i:
3300             if document.body[l] != "":
3301                 del_layout_before = False
3302                 break
3303             l = l + 1
3304         if del_layout_before:
3305             del document.body[layout_before:i]
3306             i = layout_before
3307         else:
3308             document.body[i:i] = ["\\end_layout", ""]
3309             i = i + 2
3310
3311         # Find start of layout in the inset and end of inset
3312         j = find_token(document.body, "\\begin_layout", i)
3313         if j == -1:
3314             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3315             return
3316         k = find_end_of_inset(document.body, i)
3317         if k == -1:
3318             document.warning("Malformed LyX document: Missing `\\end_inset'.")
3319             return
3320
3321         # We either need to delete the following \end_layout line, or we need
3322         # to restart the old layout if this inset is not at the paragraph end.
3323         layout_after = find_token(document.body, "\\end_layout", k)
3324         if layout_after == -1:
3325             document.warning("Malformed LyX document: Missing `\\end_layout'.")
3326             return
3327         del_layout_after = True
3328         l = k + 1
3329         while l < layout_after:
3330             if document.body[l] != "":
3331                 del_layout_after = False
3332                 break
3333             l = l + 1
3334         if del_layout_after:
3335             del document.body[k+1:layout_after+1]
3336         else:
3337             document.body[k+1:k+1] = [layout_line, ""]
3338
3339         # delete \begin_layout and \end_inset and replace \begin_inset with
3340         # "\begin_layout XXX". This works because we can only have one
3341         # paragraph in the caption inset: The old \end_layout will be recycled.
3342         del document.body[k]
3343         if document.body[k] == "":
3344             del document.body[k]
3345         del document.body[j]
3346         if document.body[j] == "":
3347             del document.body[j]
3348         document.body[i] = "\\begin_layout %s" % caption_dict[val]
3349         if document.body[i+1] == "":
3350             del document.body[i+1]
3351         i += 1
3352
3353
3354 def revert_fragileframe(document):
3355     " Reverts beamer FragileFrame layout to ERT "
3356     
3357     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3358     if document.textclass not in beamer_classes:
3359         return
3360
3361     i = 0
3362     while True:
3363         i = find_token(document.body, "\\begin_layout FragileFrame", i)
3364         if i == -1:
3365             return
3366         # Find end of sequence
3367         j = find_end_of_sequence(document.body, i)
3368         if j == -1:
3369             document.warning("Malformed LyX document. Cannot find end of FragileFrame sequence!")
3370             i += 1
3371             continue
3372         endseq = j
3373         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{frame}")
3374         esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}")
3375         endseq = endseq + len(esubst) - len(document.body[j : j])
3376         if document.body[j] == "\\end_deeper":
3377             document.body[j : j] = ["\\end_deeper", ""] + esubst
3378         else:
3379             document.body[j : j] = esubst
3380         for q in range(i, j):
3381             if document.body[q] == "\\begin_layout FragileFrame":
3382                 document.body[q] = "\\begin_layout %s" % document.default_layout
3383         r = i
3384         while r < j:
3385             if document.body[r] == "\\begin_deeper":
3386                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3387                 if s != -1:
3388                     document.body[r] = ""
3389                     document.body[s] = ""
3390                     r = s
3391                     continue
3392             r = r + 1
3393         for p in range(1, 5):
3394             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, j)
3395             if arg != -1:
3396                 if p == 1:
3397                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3398                     endPlain = find_end_of_layout(document.body, beginPlain)
3399                     endInset = find_end_of_inset(document.body, arg)
3400                     content = document.body[beginPlain + 1 : endPlain]
3401                     # Adjust range end
3402                     j = j - len(document.body[arg : endInset + 1])
3403                     # Remove arg inset
3404                     del document.body[arg : endInset + 1]
3405                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3406                 elif p == 2:
3407                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3408                     endPlain = find_end_of_layout(document.body, beginPlain)
3409                     endInset = find_end_of_inset(document.body, arg)
3410                     content = document.body[beginPlain + 1 : endPlain]
3411                     # Adjust range end
3412                     j = j - len(document.body[arg : endInset + 1])
3413                     # Remove arg inset
3414                     del document.body[arg : endInset + 1]
3415                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3416                 elif p == 3:
3417                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3418                     endPlain = find_end_of_layout(document.body, beginPlain)
3419                     endInset = find_end_of_inset(document.body, arg)
3420                     content = document.body[beginPlain + 1 : endPlain]
3421                     # Adjust range end
3422                     j = j - len(document.body[arg : endInset + 1])
3423                     # Remove arg inset
3424                     del document.body[arg : endInset + 1]
3425                     subst += put_cmd_in_ert("[fragile,") + content + put_cmd_in_ert("]")
3426                 elif p == 4:
3427                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3428                     endPlain = find_end_of_layout(document.body, beginPlain)
3429                     endInset = find_end_of_inset(document.body, arg)
3430                     content = document.body[beginPlain + 1 : endPlain]
3431                     # Adjust range end
3432                     j = j - len(document.body[arg : endInset + 1])
3433                     # Remove arg inset
3434                     del document.body[arg : endInset + 1]
3435                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3436             elif p == 3:
3437                 subst += put_cmd_in_ert("[fragile]")
3438                     
3439         document.body[i : i + 1] = subst
3440         i = j
3441
3442
3443 def revert_newframes(document):
3444     " Reverts beamer Frame and PlainFrame layouts to old forms "
3445     
3446     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3447     if document.textclass not in beamer_classes:
3448         return
3449
3450     frame_dict = {
3451         "Frame" : "BeginFrame",
3452         "PlainFrame" : "BeginPlainFrame",
3453         }
3454
3455     rx = re.compile(r'^\\begin_layout (\S+)$')
3456     i = 0
3457     while True:
3458         i = find_token(document.body, "\\begin_layout", i)
3459         if i == -1:
3460             return
3461
3462         m = rx.match(document.body[i])
3463         val = ""
3464         if m:
3465             val = m.group(1)
3466         if val not in frame_dict.keys():
3467             i += 1
3468             continue
3469         # Find end of sequence
3470         j = find_end_of_sequence(document.body, i)
3471         if j == -1:
3472             document.warning("Malformed LyX document. Cannot find end of Frame sequence!")
3473             i += 1
3474             continue
3475         endseq = j
3476         subst = ["\\begin_layout %s" % frame_dict[val]]
3477         esubst = ["\\end_layout", "", "\\begin_layout EndFrame", "", "\\end_layout"]
3478         endseq = endseq + len(esubst) - len(document.body[j : j])
3479         if document.body[j] == "\\end_deeper":
3480             document.body[j : j] = ["\\end_deeper", ""] + esubst
3481         else:
3482             document.body[j : j] = esubst
3483         for q in range(i, j):
3484             if document.body[q] == "\\begin_layout %s" % val:
3485                 document.body[q] = "\\begin_layout %s" % document.default_layout
3486         r = i
3487         while r < j:
3488             if document.body[r] == "\\begin_deeper":
3489                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3490                 if s != -1:
3491                     document.body[r] = ""
3492                     document.body[s] = ""
3493                     r = s
3494                     continue
3495             r = r + 1
3496         l = find_end_of_layout(document.body, i)
3497         for p in range(1, 5):
3498             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, l)
3499             if arg != -1:
3500                 if p == 1:
3501                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3502                     endPlain = find_end_of_layout(document.body, beginPlain)
3503                     endInset = find_end_of_inset(document.body, arg)
3504                     content = document.body[beginPlain + 1 : endPlain]
3505                     # Adjust range end
3506                     l = l - len(document.body[arg : endInset + 1])
3507                     # Remove arg inset
3508                     del document.body[arg : endInset + 1]
3509                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3510                 elif p == 2:
3511                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3512                     endPlain = find_end_of_layout(document.body, beginPlain)
3513                     endInset = find_end_of_inset(document.body, arg)
3514                     content = document.body[beginPlain + 1 : endPlain]
3515                     # Adjust range end
3516                     l = l - len(document.body[arg : endInset + 1])
3517                     # Remove arg inset
3518                     del document.body[arg : endInset + 1]
3519                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3520                 elif p == 3:
3521                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3522                     endPlain = find_end_of_layout(document.body, beginPlain)
3523                     endInset = find_end_of_inset(document.body, arg)
3524                     content = document.body[beginPlain + 1 : endPlain]
3525                     # Adjust range end
3526                     l = l - len(document.body[arg : endInset + 1])
3527                     # Remove arg inset
3528                     del document.body[arg : endInset + 1]
3529                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3530                 elif p == 4:
3531                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3532                     endPlain = find_end_of_layout(document.body, beginPlain)
3533                     endInset = find_end_of_inset(document.body, arg)
3534                     content = document.body[beginPlain + 1 : endPlain]
3535                     # Adjust range end
3536                     l = l - len(document.body[arg : endInset + 1])
3537                     # Remove arg inset
3538                     del document.body[arg : endInset + 1]
3539                     subst += content
3540                     
3541         document.body[i : i + 1] = subst
3542         i = j
3543
3544 # known encodings that do not change their names (same LyX and LaTeX names)
3545 known_enc_tuple = ("auto", "default", "ansinew", "applemac", "armscii8", "ascii",
3546     "cp437", "cp437de", "cp850", "cp852", "cp855", "cp858", "cp862", "cp865", "cp866",
3547     "cp1250", "cp1251", "cp1252", "cp1255", "cp1256", "cp1257", "koi8-r", "koi8-u",
3548     "pt154", "pt254", "tis620-0", "utf8", "utf8x", "utf8-plain")
3549
3550 def convert_encodings(document):
3551     "Use the LyX names of the encodings instead of the LaTeX names."
3552     LaTeX2LyX_enc_dict = {
3553         "8859-6":     "iso8859-6",
3554         "8859-8":     "iso8859-8",
3555         "Bg5":        "big5",
3556         "euc":        "euc-jp-platex",
3557         "EUC-JP":     "euc-jp",
3558         "EUC-TW":     "euc-tw",
3559         "GB":         "euc-cn",
3560         "GBK":        "gbk",
3561         "iso88595":   "iso8859-5",
3562         "iso-8859-7": "iso8859-7",
3563         "JIS":        "jis",
3564         "jis":        "jis-platex",
3565         "KS":         "euc-kr",
3566         "l7xenc":     "iso8859-13",
3567         "latin1":     "iso8859-1",
3568         "latin2":     "iso8859-2",
3569         "latin3":     "iso8859-3",
3570         "latin4":     "iso8859-4",
3571         "latin5":     "iso8859-9",
3572         "latin9":     "iso8859-15",
3573         "latin10":    "iso8859-16",
3574         "SJIS":       "shift-jis",
3575         "sjis":       "shift-jis-platex",
3576         "UTF8":       "utf8-cjk"
3577     }
3578     i = find_token(document.header, "\\inputencoding" , 0)
3579     if i == -1:
3580         return
3581     val = get_value(document.header, "\\inputencoding", i)
3582     if val in LaTeX2LyX_enc_dict.keys():
3583         document.header[i] = "\\inputencoding %s" % LaTeX2LyX_enc_dict[val]
3584     elif val not in known_enc_tuple:
3585         document.warning("Ignoring unknown input encoding: `%s'" % val)
3586
3587
3588 def revert_encodings(document):
3589     """Revert to using the LaTeX names of the encodings instead of the LyX names.
3590     Also revert utf8-platex to sjis, the language default when using Japanese.
3591     """
3592     LyX2LaTeX_enc_dict = {
3593         "big5":             "Bg5",
3594         "euc-cn":           "GB",
3595         "euc-kr":           "KS",
3596         "euc-jp":           "EUC-JP",
3597         "euc-jp-platex":    "euc",
3598         "euc-tw":           "EUC-TW",
3599         "gbk":              "GBK",
3600         "iso8859-1":        "latin1",
3601         "iso8859-2":        "latin2",
3602         "iso8859-3":        "latin3",
3603         "iso8859-4":        "latin4",
3604         "iso8859-5":        "iso88595",
3605         "iso8859-6":        "8859-6",
3606         "iso8859-7":        "iso-8859-7",
3607         "iso8859-8":        "8859-8",
3608         "iso8859-9":        "latin5",
3609         "iso8859-13":       "l7xenc",
3610         "iso8859-15":       "latin9",
3611         "iso8859-16":       "latin10",
3612         "jis":              "JIS",
3613         "jis-platex":       "jis",
3614         "shift-jis":        "SJIS",
3615         "shift-jis-platex": "sjis",
3616         "utf8-cjk":         "UTF8",
3617         "utf8-platex":      "sjis"
3618     }
3619     i = find_token(document.header, "\\inputencoding" , 0)
3620     if i == -1:
3621         return
3622     val = get_value(document.header, "\\inputencoding", i)
3623     if val in LyX2LaTeX_enc_dict.keys():
3624         document.header[i] = "\\inputencoding %s" % LyX2LaTeX_enc_dict[val]
3625     elif val not in known_enc_tuple:
3626         document.warning("Ignoring unknown input encoding: `%s'" % val)
3627
3628
3629 def revert_IEEEtran_3(document):
3630   '''
3631   Reverts Flex Insets to TeX-code
3632   '''
3633   if document.textclass == "IEEEtran":
3634     h = 0
3635     i = 0
3636     j = 0
3637     while True:
3638       if h != -1:
3639         h = find_token(document.body, "\\begin_inset Flex Author Mark", h)
3640       if h != -1:
3641         endh = find_end_of_inset(document.body, h)
3642         document.body[endh - 2 : endh + 1] = put_cmd_in_ert("}")
3643         document.body[h : h + 4] = put_cmd_in_ert("\\IEEEauthorrefmark{")
3644         h = h + 5
3645       if i != -1:
3646         i = find_token(document.body, "\\begin_inset Flex Author Name", i)
3647       if i != -1:
3648         endi = find_end_of_inset(document.body, i)
3649         document.body[endi - 2 : endi + 1] = put_cmd_in_ert("}")
3650         document.body[i : i + 4] = put_cmd_in_ert("\\IEEEauthorblockN{")
3651         i = i + 5
3652       if j != -1:
3653         j = find_token(document.body, "\\begin_inset Flex Author Affiliation", j)
3654       if j != -1:
3655         endj = find_end_of_inset(document.body, j)
3656         document.body[endj - 2 : endj + 1] = put_cmd_in_ert("}")
3657         document.body[j : j + 4] = put_cmd_in_ert("\\IEEEauthorblockA{")
3658         j = j + 5
3659       if i == -1 and j == -1 and h == -1:
3660         return
3661
3662
3663 def revert_kurier_fonts(document):
3664   " Revert kurier font definition to LaTeX "
3665   
3666   i = find_token(document.header, "\\font_math", 0)
3667   if i != -1:
3668     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3669       val = get_value(document.header, "\\font_math", i)
3670       if val == "kurier-math":
3671         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
3672           "\\usepackage[math]{kurier}\n" \
3673           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
3674         document.header[i] = "\\font_math auto"
3675   
3676   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3677     kurier_fonts = ["kurier", "kurierc", "kurierl", "kurierlc"]
3678     k = find_token(document.header, "\\font_sans kurier", 0)
3679     if k != -1:
3680       sf = get_value(document.header, "\\font_sans", k)
3681       if sf in kurier_fonts:
3682         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
3683         document.header[k] = "\\font_sans default"
3684
3685 def revert_iwona_fonts(document):
3686   " Revert iwona font definition to LaTeX "
3687   
3688   i = find_token(document.header, "\\font_math", 0)
3689   if i != -1:
3690     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3691       val = get_value(document.header, "\\font_math", i)
3692       if val == "iwona-math":
3693         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
3694           "\\usepackage[math]{iwona}\n" \
3695           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
3696         document.header[i] = "\\font_math auto"
3697   
3698   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3699     iwona_fonts = ["iwona", "iwonac", "iwonal", "iwonalc"]
3700     k = find_token(document.header, "\\font_sans iwona", 0)
3701     if k != -1:
3702       sf = get_value(document.header, "\\font_sans", k)
3703       if sf in iwona_fonts:
3704         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
3705         document.header[k] = "\\font_sans default"
3706
3707
3708 def revert_new_libertines(document):
3709     " Revert new libertine font definition to LaTeX "
3710   
3711     if find_token(document.header, "\\use_non_tex_fonts true", 0) != -1:
3712         return
3713
3714     i = find_token(document.header, "\\font_typewriter libertine-mono", 0)
3715     if i != -1:
3716         preamble = "\\usepackage"
3717         sc = find_token(document.header, "\\font_tt_scale", 0)
3718         if sc != -1:
3719             scval = get_value(document.header, "\\font_tt_scale", sc)
3720             if scval != "100":
3721                 preamble += "[scale=%f]" % (float(scval) / 100)
3722                 document.header[sc] = "\\font_tt_scale 100"
3723         preamble += "{libertineMono-type1}"
3724         add_to_preamble(document, [preamble])
3725         document.header[i] = "\\font_typewriter default"
3726    
3727     k = find_token(document.header, "\\font_sans biolinum", 0)
3728     if k != -1:
3729         preamble = "\\usepackage"
3730         options = ""
3731         j = find_token(document.header, "\\font_osf true", 0)
3732         if j != -1:
3733             options += "osf"
3734         else:
3735             options += "lining"
3736         sc = find_token(document.header, "\\font_sf_scale", 0)
3737         if sc != -1:
3738             scval = get_value(document.header, "\\font_sf_scale", sc)
3739             if scval != "100":
3740                 options += ",scale=%f" % (float(scval) / 100)
3741                 document.header[sc] = "\\font_sf_scale 100"
3742         if options != "":
3743             preamble += "[" + options +"]"
3744         preamble += "{biolinum-type1}"
3745         add_to_preamble(document, [preamble])
3746         document.header[k] = "\\font_sans default"
3747
3748
3749 def convert_lyxframes(document):
3750     " Converts old beamer frames to new style "
3751     
3752     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3753     if document.textclass not in beamer_classes:
3754         return
3755    
3756     framebeg = ["BeginFrame", "BeginPlainFrame"]
3757     frameend = ["Frame", "PlainFrame", "EndFrame", "BeginFrame", "BeginPlainFrame", "AgainFrame",
3758                 "Section", "Section*", "Subsection", "Subsection*", "Subsubsection", "Subsubsection*"]
3759     for lay in framebeg:
3760         i = 0
3761         while True:
3762             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
3763             if i == -1:
3764                 break
3765             parent = get_containing_layout(document.body, i)
3766             if parent == False or parent[1] != i:
3767                 document.warning("Wrong parent layout!")
3768                 i += 1
3769                 continue
3770             frametype = parent[0]
3771             j = parent[2]
3772             parbeg = parent[3]
3773             if i != -1:
3774                 # Step I: Convert ERT arguments
3775                 # FIXME: This currently only works if the arguments are in one single ERT
3776                 ertend = i
3777                 if document.body[parbeg] == "\\begin_inset ERT":
3778                     ertend = find_end_of_inset(document.body, parbeg)
3779                     if ertend == -1:
3780                         document.warning("Malformed LyX document: missing ERT \\end_inset")
3781                         continue
3782                     ertcont = parbeg + 5
3783                     if document.body[ertcont].startswith("[<"):
3784                         # This is a default overlay specification
3785                         # strip off the [<
3786                         document.body[ertcont] = document.body[ertcont][2:]
3787                         if document.body[ertcont].endswith(">]"):
3788                             # strip off the >]
3789                             document.body[ertcont] = document.body[ertcont][:-2]
3790                         elif document.body[ertcont].endswith("]"):
3791                             # divide the args
3792                             tok = document.body[ertcont].find('>][')
3793                             if tok != -1:
3794                                 subst = [document.body[ertcont][:tok],
3795                                          '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
3796                                          'status collapsed', '', '\\begin_layout Plain Layout',
3797                                          document.body[ertcont][tok + 3:-1]]
3798                                 document.body[ertcont : ertcont + 1] = subst
3799                                 ertend += 11
3800                         # Convert to ArgInset
3801                         document.body[parbeg] = "\\begin_inset Argument 2"
3802                     elif document.body[ertcont].startswith("<"):
3803                         # This is an overlay specification
3804                         # strip off the <
3805                         document.body[ertcont] = document.body[ertcont][1:]
3806                         if document.body[ertcont].endswith(">"):
3807                             # strip off the >
3808                             document.body[ertcont] = document.body[ertcont][:-1]
3809                             # Convert to ArgInset
3810                             document.body[parbeg] = "\\begin_inset Argument 1"
3811                         elif document.body[ertcont].endswith(">]"):
3812                             # divide the args
3813                             tok = document.body[ertcont].find('>[<')
3814                             if tok != -1:
3815                                document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
3816                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3817                                                                'status collapsed', '', '\\begin_layout Plain Layout',
3818                                                                document.body[ertcont][tok + 3:-2]]
3819                             # Convert to ArgInset
3820                             document.body[parbeg] = "\\begin_inset Argument 1"
3821                             ertend += 11
3822                         elif document.body[ertcont].endswith("]"):
3823                             # divide the args
3824                             tok = document.body[ertcont].find('>[<')
3825                             if tok != -1:
3826                                # divide the args
3827                                tokk = document.body[ertcont].find('>][')
3828                                if tokk != -1:
3829                                    document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
3830                                                                    '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3831                                                                    'status collapsed', '', '\\begin_layout Plain Layout',
3832                                                                    document.body[ertcont][tok + 3:tokk],
3833                                                                    '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
3834                                                                    'status collapsed', '', '\\begin_layout Plain Layout',
3835                                                                    document.body[ertcont][tokk + 3:-1]]
3836                                    ertend += 22
3837                             else:
3838                                 tokk = document.body[ertcont].find('>[')
3839                                 if tokk != -1:
3840                                     document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
3841                                                                     '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
3842                                                                     'status collapsed', '', '\\begin_layout Plain Layout',
3843                                                                     document.body[ertcont][tokk + 2:-1]]
3844                                     ertend += 11
3845                             # Convert to ArgInset
3846                             document.body[parbeg] = "\\begin_inset Argument 1"
3847                     elif document.body[ertcont].startswith("["):
3848                         # This is an ERT option
3849                         # strip off the [
3850                         document.body[ertcont] = document.body[ertcont][1:]
3851                         if document.body[ertcont].endswith("]"):
3852                             # strip off the ]
3853                             document.body[ertcont] = document.body[ertcont][:-1]
3854                             # Convert to ArgInset
3855                             document.body[parbeg] = "\\begin_inset Argument 3"
3856                 # End of argument conversion
3857                 # Step II: Now rename the layout and convert the title to an argument
3858                 j = find_end_of_layout(document.body, i)
3859                 document.body[j : j + 1] = ['\\end_layout', '', '\\end_inset', '', '\\end_layout']
3860                 if lay == "BeginFrame":
3861                     document.body[i] = "\\begin_layout Frame"
3862                 else:
3863                     document.body[i] = "\\begin_layout PlainFrame"
3864                 document.body[ertend + 1 : ertend + 1] = ['\\begin_inset Argument 4',
3865                                                 'status open', '', '\\begin_layout Plain Layout']
3866                 # Step III: find real frame end
3867                 j = j + 8
3868                 jj = j
3869                 while True:
3870                     fend = find_token(document.body, "\\begin_layout", jj)
3871                     if fend == -1:
3872                         document.warning("Malformed LyX document: No real frame end!")
3873                         return
3874                     val = get_value(document.body, "\\begin_layout", fend)
3875                     if val not in frameend:
3876                         jj = fend + 1
3877                         continue
3878                     old = document.body[fend]
3879                     if val == frametype:
3880                         document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
3881                     # consider explicit EndFrames between two identical frame types
3882                     elif val == "EndFrame":
3883                         nextlayout = find_token(document.body, "\\begin_layout", fend + 1)
3884                         if nextlayout != -1 and get_value(document.body, "\\begin_layout", nextlayout) == frametype:
3885                             document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
3886                         else:
3887                             document.body[fend : fend] = ['\\end_deeper']
3888                     else:
3889                         document.body[fend : fend] = ['\\end_deeper']
3890                     document.body[j + 1 : j + 1] = ['', '\\begin_deeper']
3891                     break
3892             i = j
3893
3894
3895 def remove_endframes(document):
3896     " Remove deprecated beamer endframes "
3897     
3898     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3899     if document.textclass not in beamer_classes:
3900         return
3901    
3902     i = 0
3903     while True:
3904         i = find_token_exact(document.body, "\\begin_layout EndFrame", i)
3905         if i == -1:
3906             break
3907         j = find_end_of_layout(document.body, i)
3908         if j == -1:
3909             document.warning("Malformed LyX document: Missing \\end_layout to EndFrame")
3910             i += 1
3911             continue
3912         del document.body[i : j + 1]
3913
3914
3915 def revert_powerdot_flexes(document):
3916     " Reverts powerdot flex insets "
3917     
3918     if document.textclass != "powerdot":
3919         return
3920
3921     flexes = {"Onslide" : "\\onslide",
3922               "Onslide*" : "\\onslide*",
3923               "Onslide+" : "\\onslide+"}
3924     rx = re.compile(r'^\\begin_inset Flex (.+)$')
3925
3926     i = 0
3927     while True:
3928         i = find_token(document.body, "\\begin_inset Flex", i)
3929         if i == -1:
3930             return
3931         m = rx.match(document.body[i])
3932         if m:
3933             flextype = m.group(1)
3934             z = find_end_of_inset(document.body, i)
3935             if z == -1:
3936                 document.warning("Can't find end of Flex " + flextype + " inset.")
3937                 i += 1
3938                 continue
3939             if flextype in flexes:
3940                 pre = put_cmd_in_ert(flexes[flextype])
3941                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
3942                 if arg != -1:
3943                     argend = find_end_of_inset(document.body, arg)
3944                     if argend == -1:
3945                         document.warning("Can't find end of Argument!")
3946                         i += 1
3947                         continue
3948                     # Find containing paragraph layout
3949                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3950                     endPlain = find_end_of_layout(document.body, beginPlain)
3951                     argcontent = document.body[beginPlain + 1 : endPlain]
3952                     # Adjust range end
3953                     z = z - len(document.body[arg : argend + 1])
3954                     # Remove arg inset
3955                     del document.body[arg : argend + 1]
3956                     pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
3957                 pre += put_cmd_in_ert("{")
3958                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
3959                 endPlain = find_end_of_layout(document.body, beginPlain)
3960                 # Adjust range end
3961                 z = z - len(document.body[i : beginPlain + 1])
3962                 z += len(pre)
3963                 document.body[i : beginPlain + 1] = pre
3964                 post = put_cmd_in_ert("}")
3965                 document.body[z - 2 : z + 1] = post     
3966         i += 1
3967
3968
3969 def revert_powerdot_pause(document):
3970     " Reverts powerdot pause layout to ERT "
3971     
3972     if document.textclass != "powerdot":
3973         return
3974
3975     i = 0
3976     while True:
3977         i = find_token(document.body, "\\begin_layout Pause", i)
3978         if i == -1:
3979             return
3980         j = find_end_of_layout(document.body, i)
3981         if j == -1:
3982             document.warning("Malformed LyX document: Can't find end of Pause layout")
3983             i += 1
3984             continue
3985         endlay = j
3986         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\pause")
3987         for p in range(i, j):
3988             if p >= endlay:
3989                 break
3990             arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3991             if arg != -1:
3992                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3993                 endPlain = find_end_of_layout(document.body, beginPlain)
3994                 endInset = find_end_of_inset(document.body, p)
3995                 content = document.body[beginPlain + 1 : endPlain]
3996                 # Adjust range end
3997                 endlay = endlay - len(document.body[p : endInset + 1])
3998                 # Remove arg inset
3999                 del document.body[p : endInset + 1]
4000                 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4001                     
4002         document.body[i : i + 1] = subst
4003         i = endlay
4004
4005
4006 def revert_powerdot_itemargs(document):
4007     " Reverts powerdot item arguments to ERT "
4008     
4009     if document.textclass != "powerdot":
4010         return
4011
4012     i = 0
4013     list_layouts = ["Itemize", "ItemizeType1", "Enumerate", "EnumerateType1"]
4014     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4015
4016     while True:
4017         i = find_token(document.body, "\\begin_inset Argument", i)
4018         if i == -1:
4019             return
4020         # Find containing paragraph layout
4021         parent = get_containing_layout(document.body, i)
4022         if parent == False:
4023             document.warning("Malformed LyX document: Can't find parent paragraph layout")
4024             i += 1
4025             continue
4026         parbeg = parent[1]
4027         parend = parent[2]
4028         realparbeg = parent[3]
4029         layoutname = parent[0]
4030         realparend = parend
4031         for p in range(parbeg, parend):
4032             if p >= realparend:
4033                 i = realparend
4034                 break
4035             if layoutname in list_layouts:
4036                 m = rx.match(document.body[p])
4037                 if m:
4038                     argnr = m.group(1)
4039                     if argnr == "item:1":
4040                         j = find_end_of_inset(document.body, i)
4041                         # Find containing paragraph layout
4042                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4043                         endPlain = find_end_of_layout(document.body, beginPlain)
4044                         content = document.body[beginPlain + 1 : endPlain]
4045                         del document.body[i:j+1]
4046                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4047                         document.body[realparbeg : realparbeg] = subst
4048                     elif argnr == "item:2":
4049                         j = find_end_of_inset(document.body, i)
4050                         # Find containing paragraph layout
4051                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4052                         endPlain = find_end_of_layout(document.body, beginPlain)
4053                         content = document.body[beginPlain + 1 : endPlain]
4054                         del document.body[i:j+1]
4055                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
4056                         document.body[realparbeg : realparbeg] = subst
4057         
4058         i = realparend
4059
4060
4061 def revert_powerdot_columns(document):
4062     " Reverts powerdot twocolumn to TeX-code "
4063     if document.textclass != "powerdot":
4064         return
4065
4066     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4067     i = 0
4068     while True:
4069         i = find_token(document.body, "\\begin_layout Twocolumn", i)
4070         if i == -1:
4071             return
4072         j = find_end_of_layout(document.body, i)
4073         if j == -1:
4074             document.warning("Malformed LyX document: Can't find end of Twocolumn layout")
4075             i += 1
4076             continue
4077         endlay = j
4078         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
4079         endlay += len(put_cmd_in_ert("}"))
4080         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\twocolumn")
4081         for p in range(i, j):
4082             if p >= endlay:
4083                 break
4084             m = rx.match(document.body[p])
4085             if m:
4086                 argnr = m.group(1)
4087                 if argnr == "1":
4088                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4089                     endPlain = find_end_of_layout(document.body, beginPlain)
4090                     endInset = find_end_of_inset(document.body, p)
4091                     content = document.body[beginPlain + 1 : endPlain]
4092                     # Adjust range end
4093                     endlay = endlay - len(document.body[p : endInset + 1])
4094                     # Remove arg inset
4095                     del document.body[p : endInset + 1]
4096                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4097                 elif argnr == "2":
4098                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4099                     endPlain = find_end_of_layout(document.body, beginPlain)
4100                     endInset = find_end_of_inset(document.body, p)
4101                     content = document.body[beginPlain + 1 : endPlain]
4102                     # Adjust range end
4103                     endlay = endlay - len(document.body[p : endInset + 1])
4104                     # Remove arg inset
4105                     del document.body[p : endInset + 1]
4106                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
4107                     
4108         subst += put_cmd_in_ert("{")
4109         document.body[i : i + 1] = subst
4110         i = endlay
4111
4112
4113 def revert_mbox_fbox(document):
4114     'Convert revert mbox/fbox boxes to TeX-code'
4115     i = 0
4116     while True:
4117         i = find_token(document.body, "\\begin_inset Box", i)
4118         if i == -1:
4119             return
4120         j = find_token(document.body, "width", i)
4121         if j != i + 7:
4122             document.warning("Malformed LyX document: Can't find box width")
4123             return
4124         width = get_value(document.body, "width", j)
4125         k = find_end_of_inset(document.body, j)
4126         if k == -1:
4127             document.warning("Malformed LyX document: Can't find end of box inset")
4128             i += 1
4129             continue
4130         BeginLayout = find_token(document.body, "\\begin_layout Plain Layout", j)
4131         EndLayout = find_token(document.body, "\\end_layout", BeginLayout)
4132         # replace if width is ""
4133         if (width == '""'):
4134             document.body[EndLayout:k + 1] = put_cmd_in_ert("}")
4135             if document.body[i] == "\\begin_inset Box Frameless":
4136                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\mbox{")
4137             if document.body[i] == "\\begin_inset Box Boxed":
4138                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\fbox{")
4139         i += 1
4140
4141
4142 def revert_starred_caption(document):
4143     " Reverts unnumbered longtable caption insets "
4144     
4145     i = 0
4146     while True:
4147       i = find_token(document.body, "\\begin_inset Caption LongTableNoNumber", i)
4148       if i == -1:
4149           return
4150       # This is not equivalent, but since the caption inset is a full blown
4151       # text inset a true conversion to ERT is too difficult.
4152       document.body[i] = "\\begin_inset Caption Standard"
4153       i += 1
4154
4155
4156 def revert_forced_local_layout(document):
4157     i = 0
4158     while True:
4159         i = find_token(document.header, "\\begin_forced_local_layout", i)
4160         if i == -1:
4161             return
4162         j = find_end_of(document.header, i, "\\begin_forced_local_layout", "\\end_forced_local_layout")
4163         if j == -1:
4164             # this should not happen
4165             break
4166         regexp = re.compile(r'\s*forcelocal', re.IGNORECASE)
4167         k = find_re(document.header, regexp, i, j)
4168         while k != -1:
4169             del document.header[k]
4170             j = j - 1
4171             k = find_re(document.header, regexp, i, j)
4172         k = find_token(document.header, "\\begin_local_layout", 0)
4173         if k == -1:
4174             document.header[i] = "\\begin_local_layout"
4175             document.header[j] = "\\end_local_layout"
4176         else:
4177             l = find_end_of(document.header, k, "\\begin_local_layout", "\\end_local_layout")
4178             if j == -1:
4179                 # this should not happen
4180                 break
4181             lines = document.header[i+1 : j]
4182             if k > i:
4183                 document.header[k+1 : k+1] = lines
4184                 document.header[i   : j  ] = []
4185             else:
4186                 document.header[i   : j  ] = []
4187                 document.header[k+1 : k+1] = lines
4188
4189
4190 def revert_aa1(document):
4191   " Reverts InsetArguments of aa to TeX-code "
4192   if document.textclass == "aa":
4193     i = 0
4194     while True:
4195       if i != -1:
4196         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4197       if i != -1:
4198         revert_Argument_to_TeX_brace(document, i, 0, 1, 4, False, False)
4199         i += 1
4200       if i == -1:
4201         return
4202
4203
4204 def revert_aa2(document):
4205   " Reverts InsetArguments of aa to TeX-code "
4206   if document.textclass == "aa":
4207     i = 0
4208     while True:
4209       if i != -1:
4210         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4211       if i != -1:
4212         document.body[i] = "\\begin_layout Abstract"
4213         i += 1
4214       if i == -1:
4215         return
4216
4217
4218 def revert_tibetan(document):
4219     "Set the document language for Tibetan to English" 
4220
4221     if document.language == "tibetan":
4222         document.language = "english"
4223         i = find_token(document.header, "\\language", 0) 
4224         if i != -1: 
4225             document.header[i] = "\\language english" 
4226     j = 0
4227     while j < len(document.body): 
4228         j = find_token(document.body, "\\lang tibetan", j)
4229         if j != -1:
4230             document.body[j] = document.body[j].replace("\\lang tibetan", "\\lang english")
4231             j += 1
4232         else:
4233             j = len(document.body)
4234
4235
4236 #############
4237 #
4238 # Chunk stuff
4239 #
4240 #############
4241
4242 # the idea here is that we will have a sequence of chunk paragraphs
4243 # we want to convert them to paragraphs in a chunk inset
4244 # the last will be discarded
4245 # the first should look like: <<FROGS>>=
4246 # will will discard the delimiters, and put the contents into the
4247 # optional argument of the inset
4248 def convert_chunks(document):
4249     first_re = re.compile(r'<<(.*)>>=')
4250     k = 0
4251     while True:
4252         # the beginning of this sequence
4253         i = k
4254         # find start of a block of chunks
4255         i = find_token(document.body, "\\begin_layout Chunk", i)
4256         if i == -1:
4257             return
4258         start = i
4259         end = -1
4260         contents = []
4261
4262         while True:
4263             # process the one we just found
4264             j = find_end_of_layout(document.body, i)
4265             if j == -1:
4266                 document.warning("Malformed LyX documents. Can't find end of Chunk layout!")
4267                 break
4268             thischunk = "".join(document.body[i + 1:j])
4269             contents.append(document.body[i + 1:j])
4270             
4271             if thischunk == "@":
4272                 break
4273
4274             # look for the next one
4275             i = j
4276             i = find_token(document.body, "\\begin_layout", i)
4277             if i == -1:
4278                 break
4279
4280             layout = get_value(document.body, "\\begin_layout", i)
4281             #sys.stderr.write(layout+ '\n')
4282             if layout != "Chunk":
4283                 break
4284
4285         if j == -1:
4286             # error, but we can try to continue
4287             k = j + 1
4288             continue
4289
4290         end = j + 1
4291         k = end
4292         
4293         # the last chunk should simply have an "@" in it
4294         
4295         if ''.join(contents[-1]) != "@":
4296             document.warning("Unexpected chunk contents.")
4297             continue
4298
4299         contents.pop()
4300
4301         # the first item should look like: <<FROGS>>=
4302         # we want the inside
4303         optarg = ' '.join(contents[0])
4304         optarg.strip()
4305         match = first_re.search(optarg)
4306         if match:
4307             optarg = match.groups()[0]
4308             contents.pop(0)
4309
4310         newstuff = ['\\begin_layout Standard',
4311                     '\\begin_inset Flex Chunk',
4312                     'status open', '',
4313                     '\\begin_layout Plain Layout', '']
4314
4315         if match:
4316             newstuff.extend(
4317                 ['\\begin_inset Argument 1',
4318                  'status open', '',
4319                  '\\begin_layout Plain Layout',
4320                  optarg,
4321                  '\\end_layout', '',
4322                  '\\end_inset', ''])
4323
4324         didone = False
4325         for c in contents:
4326             if didone:
4327                 newstuff.extend(['', '\\begin_layout Plain Layout', ''])
4328             else:
4329                 didone = True
4330             newstuff.extend(c)
4331             newstuff.append('\\end_layout')
4332
4333         newstuff.extend(['', '\\end_inset', '', '\\end_layout', ''])
4334
4335         document.body[start:end] = newstuff
4336
4337         k += len(newstuff) - (end - start)
4338
4339
4340 def revert_chunks(document):
4341     i = 0
4342     while True:
4343         i = find_token(document.body, "\\begin_inset Flex Chunk", i)
4344         if i == -1:
4345             return
4346
4347         iend = find_end_of_inset(document.body, i)
4348         if iend == -1:
4349             document.warning("Can't find end of Chunk!")
4350             i += 1
4351             continue
4352
4353         # Look for optional argument
4354         have_optarg = False
4355         ostart = find_token(document.body, "\\begin_inset Argument 1", i, iend)
4356         if ostart != -1:
4357             oend = find_end_of_inset(document.body, ostart)
4358             k = find_token(document.body, "\\begin_layout Plain Layout", ostart, oend)
4359             if k == -1:
4360                 document.warning("Malformed LyX document: Can't find argument contents!")
4361             else:
4362                 m = find_end_of_layout(document.body, k)
4363                 optarg = "".join(document.body[k+1:m])
4364                 have_optarg = True
4365
4366             # We now remove the optional argument, so we have something
4367             # uniform on which to work
4368             document.body[ostart : oend + 1] = []
4369             # iend is now invalid
4370             iend = find_end_of_inset(document.body, i)
4371
4372         retval = get_containing_layout(document.body, i)
4373         if not retval:
4374             document.warning("Can't find containing layout for Chunk!")
4375             i = iend
4376             continue
4377         (lname, lstart, lend, pstart)  = retval
4378         # we now want to work through the various paragraphs, and collect their contents
4379         parlist = []
4380         k = i
4381         while True:
4382             k = find_token(document.body, "\\begin_layout Plain Layout", k, lend)
4383             if k == -1:
4384                 break
4385             j = find_end_of_layout(document.body, k)
4386             if j == -1:
4387                 document.warning("Can't find end of layout inside chunk!")
4388                 break
4389             parlist.append(document.body[k+1:j])
4390             k = j
4391         # we now need to wrap all of these paragraphs in chunks
4392         newlines = []
4393         if have_optarg:
4394             newlines.extend(["\\begin_layout Chunk", "", "<<" + optarg + ">>=", "\\end_layout", ""])
4395         for stuff in parlist:
4396             newlines.extend(["\\begin_layout Chunk"] + stuff + ["\\end_layout", ""])
4397         newlines.extend(["\\begin_layout Chunk", "", "@", "\\end_layout", ""])
4398         # replace old content with new content
4399         document.body[lstart : lend + 1] = newlines
4400         i = lstart + len(newlines)
4401         
4402
4403 ##
4404 # Conversion hub
4405 #
4406
4407 supported_versions = ["2.1.0","2.1"]
4408 convert = [
4409            [414, []],
4410            [415, [convert_undertilde]],
4411            [416, []],
4412            [417, [convert_japanese_encodings]],
4413            [418, []],
4414            [419, []],
4415            [420, [convert_biblio_style]],
4416            [421, [convert_longtable_captions]],
4417            [422, [convert_use_packages]],
4418            [423, [convert_use_mathtools]],
4419            [424, [convert_cite_engine_type]],
4420            [425, []],
4421            [426, []],
4422            [427, []],
4423            [428, [convert_cell_rotation]],
4424            [429, [convert_table_rotation]],
4425            [430, [convert_listoflistings]],
4426            [431, [convert_use_amssymb]],
4427            [432, []],
4428            [433, [convert_armenian]],
4429            [434, []],
4430            [435, []],
4431            [436, []],
4432            [437, []],
4433            [438, []],
4434            [439, []],
4435            [440, []],
4436            [441, [convert_mdnomath]],
4437            [442, []],
4438            [443, []],
4439            [444, []],
4440            [445, []],
4441            [446, [convert_latexargs]],
4442            [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV, convert_Initials, convert_ModernCV]],
4443            [448, [convert_literate]],
4444            [449, []],
4445            [450, []],
4446            [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]],
4447            [452, [convert_beamerblocks]],
4448            [453, [convert_use_stmaryrd]],
4449            [454, [convert_overprint]],
4450            [455, []],
4451            [456, [convert_epigraph]],
4452            [457, [convert_use_stackrel]],
4453            [458, [convert_captioninsets, convert_captionlayouts]],
4454            [459, []],
4455            [460, []],
4456            [461, []],
4457            [462, []],
4458            [463, [convert_encodings]],
4459            [464, [convert_use_cancel]],
4460            [465, [convert_lyxframes, remove_endframes]],
4461            [466, []],
4462            [467, []],
4463            [468, []],
4464            [469, []],
4465            [470, []],
4466            [471, [convert_cite_engine_type_default]],
4467            [472, []],
4468            [473, []],
4469            [474, [convert_chunks]],
4470           ]
4471
4472 revert =  [
4473            [473, [revert_chunks]],
4474            [472, [revert_tibetan]],
4475            [471, [revert_aa1,revert_aa2]],
4476            [470, [revert_cite_engine_type_default]],
4477            [469, [revert_forced_local_layout]],
4478            [468, [revert_starred_caption]],
4479            [467, [revert_mbox_fbox]],
4480            [466, [revert_iwona_fonts]],
4481            [465, [revert_powerdot_flexes, revert_powerdot_pause, revert_powerdot_itemargs, revert_powerdot_columns]],
4482            [464, []],
4483            [463, [revert_use_cancel]],
4484            [462, [revert_encodings]],
4485            [461, [revert_new_libertines]],
4486            [460, [revert_kurier_fonts]],
4487            [459, [revert_IEEEtran_3]],
4488            [458, [revert_fragileframe, revert_newframes]],
4489            [457, [revert_captioninsets, revert_captionlayouts]],
4490            [456, [revert_use_stackrel]],
4491            [455, [revert_epigraph]],
4492            [454, [revert_frametitle]],
4493            [453, [revert_overprint]],
4494            [452, [revert_use_stmaryrd]],
4495            [451, [revert_beamerblocks]],
4496            [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
4497            [449, [revert_garamondx, revert_garamondx_newtxmath]],
4498            [448, [revert_itemargs]],
4499            [447, [revert_literate]],
4500            [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]],
4501            [445, [revert_latexargs]],
4502            [444, [revert_uop]],
4503            [443, [revert_biolinum]],
4504            [442, []],
4505            [441, [revert_newtxmath]],
4506            [440, [revert_mdnomath]],
4507            [439, [revert_mathfonts]],
4508            [438, [revert_minionpro]],
4509            [437, [revert_ipadeco, revert_ipachar]],
4510            [436, [revert_texgyre]],
4511            [435, [revert_mathdesign]],
4512            [434, [revert_txtt]],
4513            [433, [revert_libertine]],
4514            [432, [revert_armenian]],
4515            [431, [revert_languages, revert_ancientgreek]],
4516            [430, [revert_use_amssymb]],
4517            [429, [revert_listoflistings]],
4518            [428, [revert_table_rotation]],
4519            [427, [revert_cell_rotation]],
4520            [426, [revert_tipa]],
4521            [425, [revert_verbatim]],
4522            [424, [revert_cancel]],
4523            [423, [revert_cite_engine_type]],
4524            [422, [revert_use_mathtools]],
4525            [421, [revert_use_packages]],
4526            [420, [revert_longtable_captions]],
4527            [419, [revert_biblio_style]],
4528            [418, [revert_australian]],
4529            [417, [revert_justification]],
4530            [416, [revert_japanese_encodings]],
4531            [415, [revert_negative_space, revert_math_spaces]],
4532            [414, [revert_undertilde]],
4533            [413, [revert_visible_space]]
4534           ]
4535
4536
4537 if __name__ == "__main__":
4538     pass