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