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