]> git.lyx.org Git - features.git/blob - lib/lyx2lyx/lyx_2_1.py
Move helper functions where they belong.
[features.git] / lib / lyx2lyx / lyx_2_1.py
1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # -*- coding: utf-8 -*-
4 # Copyright (C) 2011 The LyX team
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
20 """ Convert files to the file format generated by LyX 2.1"""
21
22 import re, string
23 import unicodedata
24 import sys, os
25
26 # Uncomment only what you need to import, please.
27
28 from parser_tools import count_pars_in_inset, del_token, find_token, find_token_exact, \
29     find_token_backwards, find_end_of, find_end_of_inset, find_end_of_layout, \
30     find_end_of_sequence, find_re, get_option_value, get_containing_layout, \
31     get_value, get_quoted_value, set_option_value
32
33 #from parser_tools import find_token, find_end_of, find_tokens, \
34   #find_end_of_inset, find_end_of_layout, \
35   #is_in_inset, del_token, check_token
36
37 from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, get_ert
38
39 #from lyx2lyx_tools import insert_to_preamble, \
40 #  lyx2latex, latex_length, revert_flex_inset, \
41 #  revert_font_attrs, hex2ratio, str2bool
42
43 ####################################################################
44 # Private helper functions
45
46 #def remove_option(lines, m, option):
47     #''' removes option from line m. returns whether we did anything '''
48     #l = lines[m].find(option)
49     #if l == -1:
50         #return False
51     #val = lines[m][l:].split('"')[1]
52     #lines[m] = lines[m][:l - 1] + lines[m][l+len(option + '="' + val + '"'):]
53     #return True
54
55
56 def revert_Argument_to_TeX_brace(document, line, endline, n, nmax, environment, opt):
57     '''
58     Reverts an InsetArgument to TeX-code
59     usage:
60     revert_Argument_to_TeX_brace(document, LineOfBegin, LineOfEnd, StartArgument, EndArgument, isEnvironment, isOpt)
61     LineOfBegin is the line  of the \begin_layout or \begin_inset statement
62     LineOfEnd is the line  of the \end_layout or \end_inset statement, if "0" is given, the end of the file is used instead
63     StartArgument is the number of the first argument that needs to be converted
64     EndArgument is the number of the last argument that needs to be converted or the last defined one
65     isEnvironment must be true, if the layout is for a LaTeX environment
66     isOpt must be true, if the argument is an optional one
67     '''
68     lineArg = 0
69     wasOpt = False
70     while lineArg != -1 and n < nmax + 1:
71       lineArg = find_token(document.body, "\\begin_inset Argument " + str(n), line)
72       if lineArg > endline and endline != 0:
73         return wasOpt
74       if lineArg != -1:
75         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
76         # we have to assure that no other inset is in the Argument
77         beginInset = find_token(document.body, "\\begin_inset", beginPlain)
78         endInset = find_token(document.body, "\\end_inset", beginPlain)
79         k = beginPlain + 1
80         l = k
81         while beginInset < endInset and beginInset != -1:
82           beginInset = find_token(document.body, "\\begin_inset", k)
83           endInset = find_token(document.body, "\\end_inset", l)
84           k = beginInset + 1
85           l = endInset + 1
86         if environment == False:
87           if opt == False:
88             document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}{")
89             del(document.body[lineArg : beginPlain + 1])
90             wasOpt = False
91           else:
92             document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("]")
93             document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("[")
94             wasOpt = True
95         else:
96           document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
97           document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("{")
98           wasOpt = False
99         n = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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       if begin != -1:
1606         begin = find_token(document.body, "\\begin_inset Flex Paragraph Start", begin)
1607       if begin != -1:
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       if begin == -1:
1613         return
1614
1615
1616 def convert_IEEEtran(document):
1617   '''
1618   Converts ERT of
1619   Page headings
1620   Biography
1621   Biography without photo
1622   to InsetArgument
1623   '''
1624   if document.textclass == "IEEEtran":
1625     i = 0
1626     j = 0
1627     k = 0
1628     while True:
1629       if i != -1:
1630         i = find_token(document.body, "\\begin_layout Page headings", i)
1631       if i != -1:
1632         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1633         i = i + 1
1634       if j != -1:
1635         j = find_token(document.body, "\\begin_layout Biography without photo", j)
1636       if j != -1:
1637         convert_TeX_brace_to_Argument(document, j, 1, 1, False, True)
1638         j = j + 1
1639       if k != -1:
1640         # assure that we don't handle Biography Biography without photo
1641         k = find_token(document.body, "\\begin_layout Biography", k)
1642         kA = find_token(document.body, "\\begin_layout Biography without photo", k - 1)
1643       if k == kA and k != -1:
1644         k = k + 1
1645         continue
1646       if k != -1:
1647         # the argument we want to convert is the second one
1648         convert_TeX_brace_to_Argument(document, k, 2, 2, False, True)
1649         k = k + 1
1650       if i == -1 and j == -1 and k == -1:
1651         return
1652
1653
1654 def revert_AASTeX(document):
1655   " Reverts InsetArgument of Altaffilation to TeX-code "
1656   if document.textclass == "aastex":
1657     i = 0
1658     while True:
1659       if i != -1:
1660         i = find_token(document.body, "\\begin_layout Altaffilation", i)
1661       if i != -1:
1662         revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1663         i = i + 1
1664       if i == -1:
1665         return
1666
1667
1668 def convert_AASTeX(document):
1669   " Converts ERT of Altaffilation to InsetArgument "
1670   if document.textclass == "aastex":
1671     i = 0
1672     while True:
1673       if i != -1:
1674         i = find_token(document.body, "\\begin_layout Altaffilation", i)
1675       if i != -1:
1676         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1677         i = i + 1
1678       if i == -1:
1679         return
1680
1681
1682 def revert_AGUTeX(document):
1683   " Reverts InsetArgument of Author affiliation to TeX-code "
1684   if document.textclass == "agutex":
1685     i = 0
1686     while True:
1687       if i != -1:
1688         i = find_token(document.body, "\\begin_layout Author affiliation", i)
1689       if i != -1:
1690         revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1691         i = i + 1
1692       if i == -1:
1693         return
1694
1695
1696 def convert_AGUTeX(document):
1697   " Converts ERT of Author affiliation to InsetArgument "
1698   if document.textclass == "agutex":
1699     i = 0
1700     while True:
1701       if i != -1:
1702         i = find_token(document.body, "\\begin_layout Author affiliation", i)
1703       if i != -1:
1704         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1705         i = i + 1
1706       if i == -1:
1707         return
1708
1709
1710 def revert_IJMP(document):
1711   " Reverts InsetArgument of MarkBoth to TeX-code "
1712   if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1713     i = 0
1714     while True:
1715       if i != -1:
1716         i = find_token(document.body, "\\begin_layout MarkBoth", i)
1717       if i != -1:
1718         revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1719         i = i + 1
1720       if i == -1:
1721         return
1722
1723
1724 def convert_IJMP(document):
1725   " Converts ERT of MarkBoth to InsetArgument "
1726   if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1727     i = 0
1728     while True:
1729       if i != -1:
1730         i = find_token(document.body, "\\begin_layout MarkBoth", i)
1731       if i != -1:
1732         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1733         i = i + 1
1734       if i == -1:
1735         return
1736
1737
1738 def revert_SIGPLAN(document):
1739   " Reverts InsetArguments of SIGPLAN to TeX-code "
1740   if document.textclass == "sigplanconf":
1741     i = 0
1742     j = 0
1743     while True:
1744       if i != -1:
1745         i = find_token(document.body, "\\begin_layout Conference", i)
1746       if i != -1:
1747         revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1748         i = i + 1
1749       if j != -1:
1750         j = find_token(document.body, "\\begin_layout Author", j)
1751       if j != -1:
1752         revert_Argument_to_TeX_brace(document, j, 0, 1, 2, False, False)
1753         j = j + 1
1754       if i == -1 and j == -1:
1755         return
1756
1757
1758 def convert_SIGPLAN(document):
1759   " Converts ERT of SIGPLAN to InsetArgument "
1760   if document.textclass == "sigplanconf":
1761     i = 0
1762     j = 0
1763     while True:
1764       if i != -1:
1765         i = find_token(document.body, "\\begin_layout Conference", i)
1766       if i != -1:
1767         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1768         i = i + 1
1769       if j != -1:
1770         j = find_token(document.body, "\\begin_layout Author", j)
1771       if j != -1:
1772         convert_TeX_brace_to_Argument(document, j, 1, 2, False, False)
1773         j = j + 1
1774       if i == -1 and j == -1:
1775         return
1776
1777
1778 def revert_SIGGRAPH(document):
1779   " Reverts InsetArgument of Flex CRcat to TeX-code "
1780   if document.textclass == "acmsiggraph":
1781     i = 0
1782     while True:
1783       if i != -1:
1784         i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1785       if i != -1:
1786         revert_Argument_to_TeX_brace(document, i, 0, 1, 3, False, False)
1787         i = i + 1
1788       if i == -1:
1789         return
1790
1791
1792 def convert_SIGGRAPH(document):
1793   " Converts ERT of Flex CRcat to InsetArgument "
1794   if document.textclass == "acmsiggraph":
1795     i = 0
1796     while True:
1797       if i != -1:
1798         i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1799       if i != -1:
1800         convert_TeX_brace_to_Argument(document, i, 1, 3, True, False)
1801         i = i + 1
1802       if i == -1:
1803         return
1804
1805
1806 def revert_EuropeCV(document):
1807   " Reverts InsetArguments of europeCV to TeX-code "
1808   if document.textclass == "europecv":
1809     i = 0
1810     j = 0
1811     k = 0
1812     m = 0
1813     while True:
1814       if i != -1:
1815         i = find_token(document.body, "\\begin_layout Item", i)
1816       if i != -1:
1817         revert_Argument_to_TeX_brace(document, i, 0, 2, 2, False, False)
1818         i = i + 1
1819       if j != -1:
1820         j = find_token(document.body, "\\begin_layout BulletedItem", j)
1821       if j != -1:
1822         revert_Argument_to_TeX_brace(document, j, 0, 2, 2, False, False)
1823         j = j + 1
1824       if k != -1:
1825         k = find_token(document.body, "\\begin_layout Language", k)
1826       if k != -1:
1827         revert_Argument_to_TeX_brace(document, k, 0, 2, 6, False, False)
1828         k = k + 1
1829       if m != -1:
1830         m = find_token(document.body, "\\begin_layout LastLanguage", m)
1831       if m != -1:
1832         revert_Argument_to_TeX_brace(document, m, 0, 2, 6, False, False)
1833         m = m + 1
1834       if i == -1 and j == -1 and k == -1 and m == -1:
1835         return
1836
1837
1838 def convert_EuropeCV(document):
1839   " Converts ERT of europeCV to InsetArgument "
1840   if document.textclass == "europecv":
1841     i = 0
1842     j = 0
1843     k = 0
1844     m = 0
1845     while True:
1846       if i != -1:
1847         i = find_token(document.body, "\\begin_layout Item", i)
1848       if i != -1:
1849         convert_TeX_brace_to_Argument(document, i, 2, 2, False, False)
1850         i = i + 1
1851       if j != -1:
1852         j = find_token(document.body, "\\begin_layout BulletedItem", j)
1853       if j != -1:
1854         convert_TeX_brace_to_Argument(document, j, 2, 2, False, False)
1855         j = j + 1
1856       if k != -1:
1857         k = find_token(document.body, "\\begin_layout Language", k)
1858       if k != -1:
1859         convert_TeX_brace_to_Argument(document, k, 2, 6, False, False)
1860         k = k + 1
1861       if m != -1:
1862         m = find_token(document.body, "\\begin_layout LastLanguage", m)
1863       if m != -1:
1864         convert_TeX_brace_to_Argument(document, m, 2, 6, False, False)
1865         m = m + 1
1866       if i == -1 and j == -1 and k == -1 and m == -1:
1867         return
1868
1869
1870 def revert_ModernCV(document):
1871   " Reverts InsetArguments of modernCV to TeX-code "
1872   if document.textclass == "moderncv":
1873     j = 0
1874     k = 0
1875     m = 0
1876     o = 0
1877     p = 0
1878     while True:
1879       if j != -1:
1880         j = find_token(document.body, "\\begin_layout Entry", j)
1881       if j != -1:
1882         revert_Argument_to_TeX_brace(document, j, 0, 1, 5, False, False)
1883         j = j + 1
1884       if k != -1:
1885         k = find_token(document.body, "\\begin_layout Item", k)
1886       if k != -1:
1887         revert_Argument_to_TeX_brace(document, k, 0, 1, 1, False, False)
1888         k = k + 1
1889       if m != -1:
1890         m = find_token(document.body, "\\begin_layout ItemWithComment", m)
1891       if m != -1:
1892         revert_Argument_to_TeX_brace(document, m, 0, 1, 2, False, False)
1893         document.body[m] = document.body[m].replace("\\begin_layout ItemWithComment", "\\begin_layout Language")
1894         m = m + 1
1895       if o != -1:
1896         o = find_token(document.body, "\\begin_layout DoubleItem", o)
1897       if o != -1:
1898         revert_Argument_to_TeX_brace(document, o, 0, 1, 3, False, False)
1899         document.body[o] = document.body[o].replace("\\begin_layout DoubleItem", "\\begin_layout Computer")
1900         o = o + 1
1901       if p != -1:
1902         p = find_token(document.body, "\\begin_layout Social", p)
1903       if p != -1:
1904         revert_Argument_to_TeX_brace(document, p, 0, 1, 1, False, True)
1905         p = p + 1
1906       if j == -1 and k == -1 and m == -1 and o == -1 and p == -1:
1907         return
1908
1909
1910 def revert_ModernCV_2(document):
1911   " Reverts the Flex:Column inset of modernCV to TeX-code "
1912   if document.textclass == "moderncv":
1913     flex = 0
1914     flexEnd = -1
1915     while True:
1916       if flex != -1:
1917         flex = find_token(document.body, "\\begin_inset Flex Column", flex)
1918       if flex != -1:
1919         flexEnd = find_end_of_inset(document.body, flex)
1920         wasOpt = revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, False, True)
1921         revert_Argument_to_TeX_brace(document, flex, 0, 2, 2, False, False)
1922         flexEnd = find_end_of_inset(document.body, flex)
1923         if wasOpt == True:
1924           document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\cvcolumn")
1925         else:
1926           document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\cvcolumn{")
1927         document.body[flexEnd + 4 : flexEnd + 7] = put_cmd_in_ert("}")
1928         flex = flex + 1
1929       if flex == -1:
1930         return flexEnd
1931
1932
1933 def revert_ModernCV_3(document):
1934   " Reverts the Column style of modernCV to TeX-code "
1935   if document.textclass == "moderncv":
1936     # revert the layouts
1937     revert_ModernCV(document)
1938     p = 0
1939     # get the position of the end of the last column inset
1940     LastFlexEnd = revert_ModernCV_2(document)
1941     while True:
1942       if p != -1:
1943         p = find_token(document.body, "\\begin_layout Columns", p)
1944       if p != -1:
1945         pEnd = find_end_of_layout(document.body, p)
1946         document.body[p] = document.body[p].replace("\\begin_layout Columns", "\\begin_layout Standard")
1947         if LastFlexEnd != -1:
1948           document.body[p + 1 : p + 1] = put_cmd_in_ert("\\begin{cvcolumns}")
1949           document.body[LastFlexEnd + 24 : LastFlexEnd + 24] = put_cmd_in_ert("\\end{cvcolumns}")
1950         p = p + 1
1951       if p == -1:
1952         return
1953
1954
1955 def revert_ModernCV_4(document):
1956   " Reverts the style Social to TeX-code "
1957   if document.textclass == "moderncv":
1958     # revert the layouts
1959     revert_ModernCV(document)
1960     p = 0
1961     while True:
1962       if p != -1:
1963         p = find_token(document.body, "\\begin_layout Social", p)
1964       if p != -1:
1965         pEnd = find_end_of_layout(document.body, p)
1966         document.body[p] = document.body[p].replace("\\begin_layout Social", "\\begin_layout Standard")
1967         document.body[p + 1 : p + 1] = put_cmd_in_ert("\\social")
1968         hasOpt = find_token(document.body, "[", p + 9)
1969         if hasOpt < p + 18:
1970             document.body[p + 30 : p + 30] = put_cmd_in_ert("{")
1971             document.body[p + 41 : p + 41] = put_cmd_in_ert("}")
1972         else:
1973             document.body[p + 11 : p + 11] = put_cmd_in_ert("{")
1974             document.body[p + 21 : p + 21] = put_cmd_in_ert("}")
1975         p = p + 1
1976       if p == -1:
1977         return
1978
1979
1980 def convert_ModernCV(document):
1981   " Converts ERT of modernCV to InsetArgument "
1982   if document.textclass == "moderncv":
1983     i = 0
1984     j = 0
1985     k = 0
1986     m = 0
1987     o = 0
1988     while True:
1989       if i != -1:
1990         i = find_token(document.body, "\\begin_layout DoubleItem", i)
1991       if i != -1:
1992         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1993         document.body[o] = document.body[o].replace("\\begin_layout DoubleItem", "\\begin_layout DoubleListItem")
1994         i = i + 1
1995       if j != -1:
1996         j = find_token(document.body, "\\begin_layout Entry", j)
1997       if j != -1:
1998         convert_TeX_brace_to_Argument(document, j, 1, 5, False, False)
1999         j = j + 1
2000       if k != -1:
2001         k = find_token(document.body, "\\begin_layout Item", k)
2002       if k != -1:
2003         convert_TeX_brace_to_Argument(document, k, 1, 1, False, False)
2004         k = k + 1
2005       if m != -1:
2006         m = find_token(document.body, "\\begin_layout Language", m)
2007       if m != -1:
2008         convert_TeX_brace_to_Argument(document, m, 1, 2, False, False)
2009         m = m + 1
2010       if i == -1 and j == -1 and k == -1 and m == -1:
2011         return
2012
2013
2014 def revert_Initials(document):
2015   " Reverts InsetArgument of Initial to TeX-code "
2016   i = 0
2017   while True:
2018     i = find_token(document.body, "\\begin_layout Initial", i)
2019     if i == -1:
2020       return
2021     # first arg (optional) and second arg (first mandatory) are supported in LyX 2.0.x
2022     revert_Argument_to_TeX_brace(document, i, 0, 3, 3, False, False)
2023     i = i + 1
2024
2025
2026 def convert_Initials(document):
2027   " Converts ERT of Initial to InsetArgument "
2028   i = 0
2029   while True:
2030     i = find_token(document.body, "\\begin_layout Initial", i)
2031     if i == -1:
2032       return
2033     document.warning(str(i))
2034     convert_TeX_brace_to_Argument(document, i, 3, 3, False, False)
2035     i = i + 1
2036
2037
2038 def revert_literate(document):
2039     " Revert Literate document to old format "
2040     if del_token(document.header, "noweb", 0):
2041       document.textclass = "literate-" + document.textclass
2042       i = 0
2043       while True:
2044         i = find_token(document.body, "\\begin_layout Chunk", i)
2045         if i == -1:
2046           break
2047         document.body[i] = "\\begin_layout Scrap"
2048         i = i + 1
2049
2050
2051 def convert_literate(document):
2052     " Convert Literate document to new format"
2053     i = find_token(document.header, "\\textclass", 0)    
2054     if (i != -1) and "literate-" in document.header[i]:
2055       document.textclass = document.header[i].replace("\\textclass literate-", "")
2056       j = find_token(document.header, "\\begin_modules", 0)
2057       if (j != -1):
2058         document.header.insert(j + 1, "noweb")
2059       else:
2060         document.header.insert(i + 1, "\\end_modules")
2061         document.header.insert(i + 1, "noweb")
2062         document.header.insert(i + 1, "\\begin_modules")
2063       i = 0
2064       while True:
2065         i = find_token(document.body, "\\begin_layout Scrap", i)
2066         if i == -1:
2067           break
2068         document.body[i] = "\\begin_layout Chunk"
2069         i = i + 1
2070
2071
2072 def revert_itemargs(document):
2073     " Reverts \\item arguments to TeX-code "
2074     i = 0
2075     while True:
2076         i = find_token(document.body, "\\begin_inset Argument item:", i)
2077         if i == -1:
2078             return
2079         j = find_end_of_inset(document.body, i)
2080         # Find containing paragraph layout
2081         parent = get_containing_layout(document.body, i)
2082         if parent == False:
2083             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2084             i = i + 1
2085             continue
2086         parbeg = parent[3]
2087         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2088         endPlain = find_end_of_layout(document.body, beginPlain)
2089         content = document.body[beginPlain + 1 : endPlain]
2090         del document.body[i:j+1]
2091         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2092         document.body[parbeg : parbeg] = subst
2093         i = i + 1
2094
2095
2096 def revert_garamondx_newtxmath(document):
2097     " Revert native garamond newtxmath definition to LaTeX " 
2098
2099     i = find_token(document.header, "\\font_math", 0)
2100     if i == -1:
2101        return
2102     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
2103         val = get_value(document.header, "\\font_math", i)
2104         if val == "garamondx-ntxm":
2105             add_to_preamble(document, "\\usepackage[garamondx]{newtxmath}")
2106             document.header[i] = "\\font_math auto"
2107
2108
2109 def revert_garamondx(document):
2110     " Revert native garamond font definition to LaTeX " 
2111
2112     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
2113         i = find_token(document.header, "\\font_roman garamondx", 0)
2114         if i != -1:
2115             osf = False
2116             j = find_token(document.header, "\\font_osf true", 0)
2117             if j != -1:
2118                 osf = True
2119             preamble = "\\usepackage"
2120             if osf:
2121                 preamble += "[osfI]"
2122             preamble += "{garamondx}"
2123             add_to_preamble(document, [preamble])
2124             document.header[i] = "\\font_roman default"
2125
2126
2127 def convert_beamerargs(document):
2128     " Converts beamer arguments to new layout "
2129     
2130     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2131     if document.textclass not in beamer_classes:
2132         return
2133
2134     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2135     list_layouts = ["Itemize", "Enumerate", "Description"]
2136     rx = re.compile(r'^\\begin_inset Argument (\d+)$')
2137
2138     i = 0
2139     while True:
2140         i = find_token(document.body, "\\begin_inset Argument", i)
2141         if i == -1:
2142             return
2143         # Find containing paragraph layout
2144         parent = get_containing_layout(document.body, i)
2145         if parent == False:
2146             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2147             i = i + 1
2148             continue
2149         parbeg = parent[1]
2150         parend = parent[2]
2151         layoutname = parent[0]
2152         for p in range(parbeg, parend):
2153             if layoutname in shifted_layouts:
2154                 m = rx.match(document.body[p])
2155                 if m:
2156                     argnr = int(m.group(1))
2157                     argnr += 1
2158                     document.body[p] = "\\begin_inset Argument %d" % argnr
2159             if layoutname == "AgainFrame":
2160                 m = rx.match(document.body[p])
2161                 if m:
2162                     document.body[p] = "\\begin_inset Argument 3"
2163                     if document.body[p + 4] == "\\begin_inset ERT":
2164                         if document.body[p + 9].startswith("<"):
2165                             # This is an overlay specification
2166                             # strip off the <
2167                             document.body[p + 9] = document.body[p + 9][1:]
2168                             if document.body[p + 9].endswith(">"):
2169                                 # strip off the >
2170                                 document.body[p + 9] = document.body[p + 9][:-1]
2171                                 # Shift this one
2172                                 document.body[p] = "\\begin_inset Argument 2"
2173             if layoutname in list_layouts:
2174                 m = rx.match(document.body[p])
2175                 if m:
2176                     if m.group(1) == "1":
2177                         if document.body[p + 4] == "\\begin_inset ERT":
2178                             if document.body[p + 9].startswith("<"):
2179                                 # This is an overlay specification
2180                                 # strip off the <
2181                                 document.body[p + 9] = document.body[p + 9][1:]
2182                                 if document.body[p + 9].endswith(">"):
2183                                     # strip off the >
2184                                     document.body[p + 9] = document.body[p + 9][:-1]
2185                         elif layoutname != "Itemize":
2186                             # Shift this one
2187                             document.body[p] = "\\begin_inset Argument 2"
2188         i = i + 1
2189
2190
2191 def convert_againframe_args(document):
2192     " Converts beamer AgainFrame to new layout "
2193
2194     # FIXME: This currently only works if the arguments are in one single ERT
2195     
2196     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2197     if document.textclass not in beamer_classes:
2198         return
2199    
2200     i = 0
2201     while True:
2202         i = find_token(document.body, "\\begin_layout AgainFrame", i)
2203         if i == -1:
2204             break
2205         parent = get_containing_layout(document.body, i)
2206         if parent[1] != i:
2207             document.warning("Wrong parent layout!")
2208         j = parent[2]
2209         parbeg = parent[3]
2210         if i != -1:
2211             if document.body[parbeg] == "\\begin_inset ERT":
2212                 ertcont = parbeg + 5
2213                 if document.body[ertcont].startswith("[<"):
2214                     # This is a default overlay specification
2215                     # strip off the [<
2216                     document.body[ertcont] = document.body[ertcont][2:]
2217                     if document.body[ertcont].endswith(">]"):
2218                         # strip off the >]
2219                         document.body[ertcont] = document.body[ertcont][:-2]
2220                     elif document.body[ertcont].endswith("]"):
2221                         # divide the args
2222                         tok = document.body[ertcont].find('>][')
2223                         if tok != -1:
2224                             subst = [document.body[ertcont][:tok],
2225                                      '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2226                                      'status collapsed', '', '\\begin_layout Plain Layout',
2227                                      document.body[ertcont][tok + 3:-1]]
2228                             document.body[ertcont : ertcont + 1] = subst
2229                      # Convert to ArgInset
2230                     document.body[parbeg] = "\\begin_inset Argument 2"
2231                     i = j
2232                     continue
2233                 elif document.body[ertcont].startswith("<"):
2234                     # This is an overlay specification
2235                     # strip off the <
2236                     document.body[ertcont] = document.body[ertcont][1:]
2237                     if document.body[ertcont].endswith(">"):
2238                         # strip off the >
2239                         document.body[ertcont] = document.body[ertcont][:-1]
2240                         # Convert to ArgInset
2241                         document.body[parbeg] = "\\begin_inset Argument 1"
2242                     elif document.body[ertcont].endswith(">]"):
2243                         # divide the args
2244                         tok = document.body[ertcont].find('>[<')
2245                         if tok != -1:
2246                            document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2247                                                            '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2248                                                            'status collapsed', '', '\\begin_layout Plain Layout',
2249                                                            document.body[ertcont][tok + 3:-2]]
2250                         # Convert to ArgInset
2251                         document.body[parbeg] = "\\begin_inset Argument 1"
2252                     elif document.body[ertcont].endswith("]"):
2253                         # divide the args
2254                         tok = document.body[ertcont].find('>[<')
2255                         if tok != -1:
2256                            # divide the args
2257                            tokk = document.body[ertcont].find('>][')
2258                            if tokk != -1:
2259                                document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2260                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2261                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2262                                                                document.body[ertcont][tok + 3:tokk],
2263                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2264                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2265                                                                document.body[ertcont][tokk + 3:-1]]
2266                         else:
2267                             tokk = document.body[ertcont].find('>[')
2268                             if tokk != -1:
2269                                 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
2270                                                                 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2271                                                                 'status collapsed', '', '\\begin_layout Plain Layout',
2272                                                                 document.body[ertcont][tokk + 2:-1]]
2273                         # Convert to ArgInset
2274                         document.body[parbeg] = "\\begin_inset Argument 1"
2275                     i = j
2276                     continue
2277                 elif document.body[ertcont].startswith("["):
2278                     # This is an ERT option
2279                     # strip off the [
2280                     document.body[ertcont] = document.body[ertcont][1:]
2281                     if document.body[ertcont].endswith("]"):
2282                         # strip off the ]
2283                         document.body[ertcont] = document.body[ertcont][:-1]
2284                         # Convert to ArgInset
2285                         document.body[parbeg] = "\\begin_inset Argument 3"
2286                     i = j
2287                     continue
2288         i = j
2289
2290
2291 def convert_corollary_args(document):
2292     " Converts beamer corrolary-style ERT arguments native InsetArgs "
2293     
2294     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2295     if document.textclass not in beamer_classes:
2296         return
2297    
2298     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2299     for lay in corollary_layouts:
2300         i = 0
2301         while True:
2302             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2303             if i == -1:
2304                 break
2305             parent = get_containing_layout(document.body, i)
2306             if parent[1] != i:
2307                 document.warning("Wrong parent layout!")
2308             j = parent[2]
2309             parbeg = parent[3]
2310             if i != -1:
2311                 if document.body[parbeg] == "\\begin_inset ERT":
2312                     ertcont = parbeg + 5
2313                     if document.body[ertcont].startswith("<"):
2314                         # This is an overlay specification
2315                         # strip off the <
2316                         document.body[ertcont] = document.body[ertcont][1:]
2317                         if document.body[ertcont].endswith(">"):
2318                             # strip off the >
2319                             document.body[ertcont] = document.body[ertcont][:-1]
2320                         elif document.body[ertcont].endswith("]"):
2321                             # divide the args
2322                             tok = document.body[ertcont].find('>[')
2323                             if tok != -1:
2324                                 subst = [document.body[ertcont][:tok],
2325                                          '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2326                                          'status collapsed', '', '\\begin_layout Plain Layout',
2327                                          document.body[ertcont][tok + 2:-1]]
2328                                 document.body[ertcont : ertcont + 1] = subst
2329                         # Convert to ArgInset
2330                         document.body[parbeg] = "\\begin_inset Argument 1"
2331                         i = j
2332                         continue
2333                     elif document.body[ertcont].startswith("["):
2334                         # This is an ERT option
2335                         # strip off the [
2336                         document.body[ertcont] = document.body[ertcont][1:]
2337                         if document.body[ertcont].endswith("]"):
2338                             # strip off the ]
2339                             document.body[ertcont] = document.body[ertcont][:-1]
2340                         # Convert to ArgInset
2341                         document.body[parbeg] = "\\begin_inset Argument 2"
2342                     i = j
2343                     continue
2344             i = j
2345
2346
2347
2348 def convert_quote_args(document):
2349     " Converts beamer quote style ERT args to native InsetArgs "
2350     
2351     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2352     if document.textclass not in beamer_classes:
2353         return
2354    
2355     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2356     for lay in quote_layouts:
2357         i = 0
2358         while True:
2359             i = find_token(document.body, "\\begin_layout " + lay, i)
2360             if i == -1:
2361                 break
2362             parent = get_containing_layout(document.body, i)
2363             if parent[1] != i:
2364                 document.warning("Wrong parent layout!")
2365             j = parent[2]
2366             parbeg = parent[3]
2367             if i != -1:
2368                 if document.body[parbeg] == "\\begin_inset ERT":
2369                     if document.body[i + 6].startswith("<"):
2370                         # This is an overlay specification
2371                         # strip off the <
2372                         document.body[i + 6] = document.body[i + 6][1:]
2373                         if document.body[i + 6].endswith(">"):
2374                             # strip off the >
2375                             document.body[i + 6] = document.body[i + 6][:-1]
2376                             # Convert to ArgInset
2377                             document.body[i + 1] = "\\begin_inset Argument 1"
2378             i = j
2379
2380
2381 def revert_beamerargs(document):
2382     " Reverts beamer arguments to old layout "
2383     
2384     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2385     if document.textclass not in beamer_classes:
2386         return
2387
2388     i = 0
2389     list_layouts = ["Itemize", "Enumerate", "Description"]
2390     headings = ["Part", "Section", "Section*", "Subsection", "Subsection*",
2391                 "Subsubsection", "Subsubsection*", "FrameSubtitle", "NoteItem"]
2392     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2393     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2394     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2395
2396     while True:
2397         i = find_token(document.body, "\\begin_inset Argument", i)
2398         if i == -1:
2399             return
2400         # Find containing paragraph layout
2401         parent = get_containing_layout(document.body, i)
2402         if parent == False:
2403             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2404             i = i + 1
2405             continue
2406         parbeg = parent[1]
2407         parend = parent[2]
2408         realparbeg = parent[3]
2409         layoutname = parent[0]
2410         realparend = parend
2411         for p in range(parbeg, parend):
2412             if p >= realparend:
2413                 i = realparend
2414                 break
2415             if layoutname in headings:
2416                 m = rx.match(document.body[p])
2417                 if m:
2418                     argnr = m.group(1)
2419                     if argnr == "1":
2420                         # Find containing paragraph layout
2421                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2422                         endPlain = find_end_of_layout(document.body, beginPlain)
2423                         endInset = find_end_of_inset(document.body, p)
2424                         argcontent = document.body[beginPlain + 1 : endPlain]
2425                         # Adjust range end
2426                         realparend = realparend - len(document.body[p : endInset + 1])
2427                         # Remove arg inset
2428                         del document.body[p : endInset + 1]
2429                         if layoutname == "FrameSubtitle":
2430                             pre = put_cmd_in_ert("\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2431                         elif layoutname == "NoteItem":
2432                             pre = put_cmd_in_ert("\\note<") + argcontent + put_cmd_in_ert(">[item]")
2433                         elif layoutname.endswith('*'):
2434                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower()[:-1] + "<") + argcontent + put_cmd_in_ert(">*")
2435                         else:
2436                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2437                         secarg = find_token(document.body, "\\begin_inset Argument 2", parbeg, parend)
2438                         if secarg != -1:
2439                             # Find containing paragraph layout
2440                             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", secarg)
2441                             endPlain = find_end_of_layout(document.body, beginPlain)
2442                             endInset = find_end_of_inset(document.body, secarg)
2443                             argcontent = document.body[beginPlain + 1 : endPlain]
2444                             # Adjust range end
2445                             realparend = realparend - len(document.body[secarg : endInset + 1])
2446                             del document.body[secarg : endInset + 1]
2447                             pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2448                         pre += put_cmd_in_ert("{")
2449                         document.body[parbeg] = "\\begin_layout Standard"
2450                         document.body[realparbeg : realparbeg] = pre
2451                         pe = find_end_of_layout(document.body, parbeg)
2452                         post = put_cmd_in_ert("}")
2453                         document.body[pe : pe] = post
2454                         realparend += len(pre) + len(post)
2455             if layoutname == "AgainFrame":
2456                 m = rx.match(document.body[p])
2457                 if m:
2458                     argnr = m.group(1)
2459                     if argnr == "3":
2460                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2461                         endPlain = find_end_of_layout(document.body, beginPlain)
2462                         endInset = find_end_of_inset(document.body, p)
2463                         content = document.body[beginPlain + 1 : endPlain]
2464                         # Adjust range end
2465                         realparend = realparend - len(document.body[p : endInset + 1])
2466                         # Remove arg inset
2467                         del document.body[p : endInset + 1]
2468                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2469                         document.body[realparbeg : realparbeg] = subst
2470             if layoutname == "Overprint":
2471                 m = rx.match(document.body[p])
2472                 if m:
2473                     argnr = m.group(1)
2474                     if argnr == "1":
2475                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2476                         endPlain = find_end_of_layout(document.body, beginPlain)
2477                         endInset = find_end_of_inset(document.body, p)
2478                         content = document.body[beginPlain + 1 : endPlain]
2479                         # Adjust range end
2480                         realparend = realparend - len(document.body[p : endInset + 1])
2481                         # Remove arg inset
2482                         del document.body[p : endInset + 1]
2483                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2484                         document.body[realparbeg : realparbeg] = subst
2485             if layoutname == "OverlayArea":
2486                 m = rx.match(document.body[p])
2487                 if m:
2488                     argnr = m.group(1)
2489                     if argnr == "2":
2490                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2491                         endPlain = find_end_of_layout(document.body, beginPlain)
2492                         endInset = find_end_of_inset(document.body, p)
2493                         content = document.body[beginPlain + 1 : endPlain]
2494                         # Adjust range end
2495                         realparend = realparend - len(document.body[p : endInset + 1])
2496                         # Remove arg inset
2497                         del document.body[p : endInset + 1]
2498                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2499                         document.body[realparbeg : realparbeg] = subst
2500             if layoutname in list_layouts:
2501                 m = rx.match(document.body[p])
2502                 if m:
2503                     argnr = m.group(1)
2504                     if argnr == "1":
2505                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2506                         endPlain = find_end_of_layout(document.body, beginPlain)
2507                         endInset = find_end_of_inset(document.body, p)
2508                         content = document.body[beginPlain + 1 : endPlain]
2509                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2510                         realparend = realparend + len(subst) - len(content)
2511                         document.body[beginPlain + 1 : endPlain] = subst
2512                     elif argnr == "item:1":
2513                         j = find_end_of_inset(document.body, i)
2514                         # Find containing paragraph layout
2515                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2516                         endPlain = find_end_of_layout(document.body, beginPlain)
2517                         content = document.body[beginPlain + 1 : endPlain]
2518                         del document.body[i:j+1]
2519                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2520                         document.body[realparbeg : realparbeg] = subst
2521                     elif argnr == "item:2":
2522                         j = find_end_of_inset(document.body, i)
2523                         # Find containing paragraph layout
2524                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2525                         endPlain = find_end_of_layout(document.body, beginPlain)
2526                         content = document.body[beginPlain + 1 : endPlain]
2527                         del document.body[i:j+1]
2528                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2529                         document.body[realparbeg : realparbeg] = subst
2530             if layoutname in quote_layouts:
2531                 m = rx.match(document.body[p])
2532                 if m:
2533                     argnr = m.group(1)
2534                     if argnr == "1":
2535                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2536                         endPlain = find_end_of_layout(document.body, beginPlain)
2537                         endInset = find_end_of_inset(document.body, p)
2538                         content = document.body[beginPlain + 1 : endPlain]
2539                         # Adjust range end
2540                         realparend = realparend - len(document.body[p : endInset + 1])
2541                         # Remove arg inset
2542                         del document.body[p : endInset + 1]
2543                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2544                         document.body[realparbeg : realparbeg] = subst
2545             if layoutname in corollary_layouts:
2546                 m = rx.match(document.body[p])
2547                 if m:
2548                     argnr = m.group(1)
2549                     if argnr == "2":
2550                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2551                         endPlain = find_end_of_layout(document.body, beginPlain)
2552                         endInset = find_end_of_inset(document.body, p)
2553                         content = document.body[beginPlain + 1 : endPlain]
2554                         # Adjust range end
2555                         realparend = realparend - len(document.body[p : endInset + 1])
2556                         # Remove arg inset
2557                         del document.body[p : endInset + 1]
2558                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2559                         document.body[realparbeg : realparbeg] = subst
2560         
2561         i = realparend
2562
2563
2564 def revert_beamerargs2(document):
2565     " Reverts beamer arguments to old layout, step 2 "
2566     
2567     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2568     if document.textclass not in beamer_classes:
2569         return
2570
2571     i = 0
2572     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2573     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2574     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2575
2576     while True:
2577         i = find_token(document.body, "\\begin_inset Argument", i)
2578         if i == -1:
2579             return
2580         # Find containing paragraph layout
2581         parent = get_containing_layout(document.body, i)
2582         if parent == False:
2583             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2584             i = i + 1
2585             continue
2586         parbeg = parent[1]
2587         parend = parent[2]
2588         realparbeg = parent[3]
2589         layoutname = parent[0]
2590         realparend = parend
2591         for p in range(parbeg, parend):
2592             if p >= realparend:
2593                 i = realparend
2594                 break
2595             if layoutname in shifted_layouts:
2596                 m = rx.match(document.body[p])
2597                 if m:
2598                     argnr = m.group(1)
2599                     if argnr == "2":
2600                         document.body[p] = "\\begin_inset Argument 1"       
2601             if layoutname in corollary_layouts:
2602                 m = rx.match(document.body[p])
2603                 if m:
2604                     argnr = m.group(1)
2605                     if argnr == "1":
2606                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2607                         endPlain = find_end_of_layout(document.body, beginPlain)
2608                         endInset = find_end_of_inset(document.body, p)
2609                         content = document.body[beginPlain + 1 : endPlain]
2610                         # Adjust range end
2611                         realparend = realparend - len(document.body[p : endInset + 1])
2612                         # Remove arg inset
2613                         del document.body[p : endInset + 1]
2614                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2615                         document.body[realparbeg : realparbeg] = subst
2616             if layoutname == "OverlayArea":
2617                 m = rx.match(document.body[p])
2618                 if m:
2619                     argnr = m.group(1)
2620                     if argnr == "1":
2621                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2622                         endPlain = find_end_of_layout(document.body, beginPlain)
2623                         endInset = find_end_of_inset(document.body, p)
2624                         content = document.body[beginPlain + 1 : endPlain]
2625                         # Adjust range end
2626                         realparend = realparend - len(document.body[p : endInset + 1])
2627                         # Remove arg inset
2628                         del document.body[p : endInset + 1]
2629                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2630                         document.body[realparbeg : realparbeg] = subst
2631             if layoutname == "AgainFrame":
2632                 m = rx.match(document.body[p])
2633                 if m:
2634                     argnr = m.group(1)
2635                     if argnr == "2":
2636                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2637                         endPlain = find_end_of_layout(document.body, beginPlain)
2638                         endInset = find_end_of_inset(document.body, p)
2639                         content = document.body[beginPlain + 1 : endPlain]
2640                         # Adjust range end
2641                         realparend = realparend - len(document.body[p : endInset + 1])
2642                         # Remove arg inset
2643                         del document.body[p : endInset + 1]
2644                         subst = put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
2645                         document.body[realparbeg : realparbeg] = subst
2646         i = realparend
2647
2648
2649 def revert_beamerargs3(document):
2650     " Reverts beamer arguments to old layout, step 3 "
2651     
2652     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2653     if document.textclass not in beamer_classes:
2654         return
2655
2656     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2657     i = 0
2658     while True:
2659         i = find_token(document.body, "\\begin_inset Argument", i)
2660         if i == -1:
2661             return
2662         # Find containing paragraph layout
2663         parent = get_containing_layout(document.body, i)
2664         if parent == False:
2665             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2666             i = i + 1
2667             continue
2668         parbeg = parent[1]
2669         parend = parent[2]
2670         realparbeg = parent[3]
2671         layoutname = parent[0]
2672         realparend = parend
2673         for p in range(parbeg, parend):
2674             if p >= realparend:
2675                 i = realparend
2676                 break
2677             if layoutname == "AgainFrame":
2678                 m = rx.match(document.body[p])
2679                 if m:
2680                     argnr = m.group(1)
2681                     if argnr == "1":
2682                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2683                         endPlain = find_end_of_layout(document.body, beginPlain)
2684                         endInset = find_end_of_inset(document.body, p)
2685                         content = document.body[beginPlain + 1 : endPlain]
2686                         # Adjust range end
2687                         realparend = realparend - len(document.body[p : endInset + 1])
2688                         # Remove arg inset
2689                         del document.body[p : endInset + 1]
2690                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2691                         document.body[realparbeg : realparbeg] = subst
2692         i = realparend
2693
2694
2695 def revert_beamerflex(document):
2696     " Reverts beamer Flex insets "
2697     
2698     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2699     if document.textclass not in beamer_classes:
2700         return
2701
2702     new_flexes = {"Bold" : "\\textbf", "Emphasize" : "\\emph", "Only" : "\\only",
2703                   "Uncover" : "\\uncover", "Visible" : "\\visible",
2704                   "Invisible" : "\\invisible", "Alternative" : "\\alt",
2705                   "Beamer_Note" : "\\note"}
2706     old_flexes = {"Alert" : "\\alert", "Structure" : "\\structure"}
2707     rx = re.compile(r'^\\begin_inset Flex (.+)$')
2708
2709     i = 0
2710     while True:
2711         i = find_token(document.body, "\\begin_inset Flex", i)
2712         if i == -1:
2713             return
2714         m = rx.match(document.body[i])
2715         if m:
2716             flextype = m.group(1)
2717             z = find_end_of_inset(document.body, i)
2718             if z == -1:
2719                 document.warning("Can't find end of Flex " + flextype + " inset.")
2720                 i += 1
2721                 continue
2722             if flextype in new_flexes:
2723                 pre = put_cmd_in_ert(new_flexes[flextype])
2724                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2725                 if arg != -1:
2726                     argend = find_end_of_inset(document.body, arg)
2727                     if argend == -1:
2728                         document.warning("Can't find end of Argument!")
2729                         i += 1
2730                         continue
2731                     # Find containing paragraph layout
2732                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2733                     endPlain = find_end_of_layout(document.body, beginPlain)
2734                     argcontent = document.body[beginPlain + 1 : endPlain]
2735                     # Adjust range end
2736                     z = z - len(document.body[arg : argend + 1])
2737                     # Remove arg inset
2738                     del document.body[arg : argend + 1]
2739                     pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2740                 arg = find_token(document.body, "\\begin_inset Argument 2", i, z)
2741                 if arg != -1:
2742                     argend = find_end_of_inset(document.body, arg)
2743                     if argend == -1:
2744                         document.warning("Can't find end of Argument!")
2745                         i += 1
2746                         continue
2747                     # Find containing paragraph layout
2748                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2749                     endPlain = find_end_of_layout(document.body, beginPlain)
2750                     argcontent = document.body[beginPlain + 1 : endPlain]
2751                     # Adjust range end
2752                     z = z - len(document.body[arg : argend + 1])
2753                     # Remove arg inset
2754                     del document.body[arg : argend + 1]
2755                     if flextype == "Alternative":
2756                         pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
2757                     else:
2758                         pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2759                 pre += put_cmd_in_ert("{")
2760                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2761                 endPlain = find_end_of_layout(document.body, beginPlain)
2762                 # Adjust range end
2763                 z = z - len(document.body[i : beginPlain + 1])
2764                 z += len(pre)
2765                 document.body[i : beginPlain + 1] = pre
2766                 post = put_cmd_in_ert("}")
2767                 document.body[z - 2 : z + 1] = post
2768             elif flextype in old_flexes:
2769                 pre = put_cmd_in_ert(old_flexes[flextype])
2770                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2771                 if arg == -1:
2772                     i += 1
2773                     continue
2774                 argend = find_end_of_inset(document.body, arg)
2775                 if argend == -1:
2776                     document.warning("Can't find end of Argument!")
2777                     i += 1
2778                     continue
2779                 # Find containing paragraph layout
2780                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2781                 endPlain = find_end_of_layout(document.body, beginPlain)
2782                 argcontent = document.body[beginPlain + 1 : endPlain]
2783                 # Adjust range end
2784                 z = z - len(document.body[arg : argend + 1])
2785                 # Remove arg inset
2786                 del document.body[arg : argend + 1]
2787                 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2788                 pre += put_cmd_in_ert("{")
2789                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2790                 endPlain = find_end_of_layout(document.body, beginPlain)
2791                 # Adjust range end
2792                 z = z - len(document.body[i : beginPlain + 1])
2793                 z += len(pre)
2794                 document.body[i : beginPlain + 1] = pre
2795                 post = put_cmd_in_ert("}")
2796                 document.body[z - 2 : z + 1] = post
2797         
2798         i += 1
2799
2800
2801 def revert_beamerblocks(document):
2802     " Reverts beamer block arguments to ERT "
2803     
2804     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2805     if document.textclass not in beamer_classes:
2806         return
2807
2808     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2809
2810     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2811     i = 0
2812     while True:
2813         i = find_token(document.body, "\\begin_inset Argument", i)
2814         if i == -1:
2815             return
2816         # Find containing paragraph layout
2817         parent = get_containing_layout(document.body, i)
2818         if parent == False:
2819             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2820             i = i + 1
2821             continue
2822         parbeg = parent[1]
2823         parend = parent[2]
2824         realparbeg = parent[3]
2825         layoutname = parent[0]
2826         realparend = parend
2827         for p in range(parbeg, parend):
2828             if p >= realparend:
2829                 i = realparend
2830                 break
2831             if layoutname in blocks:
2832                 m = rx.match(document.body[p])
2833                 if m:
2834                     argnr = m.group(1)
2835                     if argnr == "1":
2836                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2837                         endPlain = find_end_of_layout(document.body, beginPlain)
2838                         endInset = find_end_of_inset(document.body, p)
2839                         content = document.body[beginPlain + 1 : endPlain]
2840                         # Adjust range end
2841                         realparend = realparend - len(document.body[p : endInset + 1])
2842                         # Remove arg inset
2843                         del document.body[p : endInset + 1]
2844                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2845                         document.body[realparbeg : realparbeg] = subst
2846                     elif argnr == "2":
2847                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2848                         endPlain = find_end_of_layout(document.body, beginPlain)
2849                         endInset = find_end_of_inset(document.body, p)
2850                         content = document.body[beginPlain + 1 : endPlain]
2851                         # Adjust range end
2852                         realparend = realparend - len(document.body[p : endInset + 1])
2853                         # Remove arg inset
2854                         del document.body[p : endInset + 1]
2855                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2856                         document.body[realparbeg : realparbeg] = subst
2857         i = realparend
2858
2859
2860
2861 def convert_beamerblocks(document):
2862     " Converts beamer block ERT args to native InsetArgs "
2863     
2864     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2865     if document.textclass not in beamer_classes:
2866         return
2867    
2868     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2869     for lay in blocks:
2870         i = 0
2871         while True:
2872             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2873             if i == -1:
2874                 break
2875             parent = get_containing_layout(document.body, i)
2876             if parent == False or parent[1] != i:
2877                 document.warning("Wrong parent layout!")
2878                 i += 1
2879                 continue
2880             j = parent[2]
2881             parbeg = parent[3]
2882             if i != -1:
2883                 if document.body[parbeg] == "\\begin_inset ERT":
2884                     ertcont = parbeg + 5
2885                     while True:
2886                         if document.body[ertcont].startswith("<"):
2887                             # This is an overlay specification
2888                             # strip off the <
2889                             document.body[ertcont] = document.body[ertcont][1:]
2890                             if document.body[ertcont].endswith(">"):
2891                                 # strip off the >
2892                                 document.body[ertcont] = document.body[ertcont][:-1]
2893                                 # Convert to ArgInset
2894                                 document.body[parbeg] = "\\begin_inset Argument 1"
2895                             elif document.body[ertcont].endswith("}"):
2896                                 # divide the args
2897                                 tok = document.body[ertcont].find('>{')
2898                                 if tok != -1:
2899                                     document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2900                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2901                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
2902                                                                             document.body[ertcont][tok + 2:-1]]
2903                             # Convert to ArgInset
2904                             document.body[parbeg] = "\\begin_inset Argument 1"
2905                         elif document.body[ertcont].startswith("{"):
2906                             # This is the block title
2907                             if document.body[ertcont].endswith("}"):
2908                                 # strip off the braces
2909                                 document.body[ertcont] = document.body[ertcont][1:-1]
2910                                 # Convert to ArgInset
2911                                 document.body[parbeg] = "\\begin_inset Argument 2"
2912                             elif count_pars_in_inset(document.body, ertcont) > 1:
2913                                 # Multipar ERT. Skip this.
2914                                 break
2915                             else:
2916                                 convert_TeX_brace_to_Argument(document, i, 2, 2, False, True)
2917                         else:
2918                             break
2919                         j = find_end_of_layout(document.body, i)
2920                         if j == -1:
2921                             document.warning("end of layout not found!")
2922                         k = find_token(document.body, "\\begin_inset Argument", i, j)
2923                         if k == -1:
2924                             document.warning("InsetArgument not found!")
2925                             break
2926                         l = find_end_of_inset(document.body, k)
2927                         m = find_token(document.body, "\\begin_inset ERT", l, j)
2928                         if m == -1:
2929                             break
2930                         ertcont = m + 5
2931                         parbeg = m
2932             i = j
2933
2934
2935 def convert_overprint(document):
2936     " Convert old beamer overprint layouts to ERT "
2937     
2938     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2939     if document.textclass not in beamer_classes:
2940         return
2941
2942     i = 0
2943     while True:
2944         i = find_token(document.body, "\\begin_layout Overprint", i)
2945         if i == -1:
2946             return
2947         # Find end of sequence
2948         j = find_end_of_sequence(document.body, i)
2949         if j == -1:
2950             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
2951             i = i + 1
2952             continue
2953         endseq = j
2954         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
2955         esubst = list()
2956         if document.body[j] == "\\end_deeper":
2957             esubst = ["", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2958         else:
2959             esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2960         endseq = endseq + len(esubst) - len(document.body[j : j])
2961         document.body[j : j] = esubst
2962         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2963         if argbeg != -1:
2964             argend = find_end_of_layout(document.body, argbeg)
2965             if argend == -1:
2966                 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
2967                 i = i + 1
2968                 continue
2969             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2970             endPlain = find_end_of_layout(document.body, beginPlain)
2971             content = document.body[beginPlain + 1 : endPlain]
2972             # Adjust range end
2973             endseq = endseq - len(document.body[argbeg : argend + 1])
2974             # Remove arg inset
2975             del document.body[argbeg : argend + 1]
2976             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2977             
2978         endseq = endseq - len(document.body[i : i])
2979         document.body[i : i] = subst + ["\\end_layout"]
2980         endseq += len(subst)
2981         
2982         for p in range(i, endseq):
2983             if document.body[p] == "\\begin_layout Overprint":
2984                 document.body[p] = "\\begin_layout Standard"
2985
2986         i = endseq
2987
2988
2989 def revert_overprint(document):
2990     " Revert old beamer overprint layouts to ERT "
2991     
2992     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2993     if document.textclass not in beamer_classes:
2994         return
2995
2996     i = 0
2997     while True:
2998         i = find_token(document.body, "\\begin_layout Overprint", i)
2999         if i == -1:
3000             return
3001         # Find end of sequence
3002         j = find_end_of_sequence(document.body, i)
3003         if j == -1:
3004             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3005             i = i + 1
3006             continue
3007         endseq = j
3008         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3009         esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}")
3010         endseq = endseq + len(esubst) - len(document.body[j : j])
3011         if document.body[j] == "\\end_deeper":
3012             document.body[j : j] = ["\\end_deeper", ""] + esubst
3013         else:
3014             document.body[j : j] = esubst
3015         r = i
3016         while r < j:
3017             if document.body[r] == "\\begin_deeper":
3018                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3019                 if s != -1:
3020                     document.body[r] = ""
3021                     document.body[s] = ""
3022                     r = s
3023                     continue
3024             r = r + 1
3025         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3026         if argbeg != -1:
3027             argend = find_end_of_inset(document.body, argbeg)
3028             if argend == -1:
3029                 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3030                 i = i + 1
3031                 continue
3032             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3033             endPlain = find_end_of_layout(document.body, beginPlain)
3034             content = document.body[beginPlain + 1 : endPlain]
3035             # Adjust range end
3036             endseq = endseq - len(document.body[argbeg : argend])
3037             # Remove arg inset
3038             del document.body[argbeg : argend + 1]
3039             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3040             
3041         endseq = endseq - len(document.body[i : i])
3042         document.body[i : i] = subst + ["\\end_layout"]
3043         endseq += len(subst)
3044      
3045         p = i
3046         while True:
3047             if p >= endseq:
3048                 break
3049             if document.body[p] == "\\begin_layout Overprint":
3050                 q = find_end_of_layout(document.body, p)
3051                 if q == -1:
3052                     document.warning("Malformed LyX document. Cannot find end of Overprint layout!")
3053                     p += 1
3054                     continue
3055                 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\onslide")
3056                 argbeg = find_token(document.body, "\\begin_inset Argument item:1", p, q)
3057                 if argbeg != -1:
3058                     argend = find_end_of_inset(document.body, argbeg)
3059                     if argend == -1:
3060                         document.warning("Malformed LyX document. Cannot find end of Overprint item argument!")
3061                         p += 1
3062                         continue
3063                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3064                     endPlain = find_end_of_layout(document.body, beginPlain)
3065                     content = document.body[beginPlain + 1 : endPlain]
3066                     # Adjust range end
3067                     endseq = endseq - len(document.body[argbeg : argend + 1])
3068                     # Remove arg inset
3069                     del document.body[argbeg : argend + 1]
3070                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3071                 endseq = endseq - len(document.body[p : p + 1]) + len(subst)
3072                 document.body[p : p + 1] = subst
3073             p = p + 1
3074
3075         i = endseq
3076
3077
3078 def revert_frametitle(document):
3079     " Reverts beamer frametitle layout to ERT "
3080     
3081     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3082     if document.textclass not in beamer_classes:
3083         return
3084
3085     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3086     i = 0
3087     while True:
3088         i = find_token(document.body, "\\begin_layout FrameTitle", i)
3089         if i == -1:
3090             return
3091         j = find_end_of_layout(document.body, i)
3092         if j == -1:
3093             document.warning("Malformed LyX document: Can't find end of FrameTitle layout")
3094             i = i + 1
3095             continue
3096         endlay = j
3097         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
3098         endlay += len(put_cmd_in_ert("}"))
3099         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\frametitle")
3100         for p in range(i, j):
3101             if p >= endlay:
3102                 break
3103             m = rx.match(document.body[p])
3104             if m:
3105                 argnr = m.group(1)
3106                 if argnr == "1":
3107                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3108                     endPlain = find_end_of_layout(document.body, beginPlain)
3109                     endInset = find_end_of_inset(document.body, p)
3110                     content = document.body[beginPlain + 1 : endPlain]
3111                     # Adjust range end
3112                     endlay = endlay - len(document.body[p : endInset + 1])
3113                     # Remove arg inset
3114                     del document.body[p : endInset + 1]
3115                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3116                 elif argnr == "2":
3117                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3118                     endPlain = find_end_of_layout(document.body, beginPlain)
3119                     endInset = find_end_of_inset(document.body, p)
3120                     content = document.body[beginPlain + 1 : endPlain]
3121                     # Adjust range end
3122                     endlay = endlay - len(document.body[p : endInset + 1])
3123                     # Remove arg inset
3124                     del document.body[p : endInset + 1]
3125                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3126                     
3127         subst += put_cmd_in_ert("{")
3128         document.body[i : i + 1] = subst
3129         i = endlay
3130
3131
3132 def convert_epigraph(document):
3133     " Converts memoir epigraph to new syntax "
3134     
3135     if document.textclass != "memoir":
3136         return
3137
3138     i = 0
3139     while True:
3140         i = find_token(document.body, "\\begin_layout Epigraph", i)
3141         if i == -1:
3142             return
3143         j = find_end_of_layout(document.body, i)
3144         if j == -1:
3145             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3146             i = i + 1
3147             continue
3148         endlay = j
3149         subst = list()
3150         ert = find_token(document.body, "\\begin_inset ERT", i, j)
3151         if ert != -1:
3152             endInset = find_end_of_inset(document.body, ert)
3153             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", ert)
3154             endPlain = find_end_of_layout(document.body, beginPlain)
3155             ertcont = beginPlain + 2
3156             if document.body[ertcont] == "}{":
3157                 # strip off the <
3158                 # Convert to ArgInset
3159                 endlay = endlay - 2 * len(document.body[j])
3160                 begsubst = ['\\begin_inset Argument post:1', 'status collapsed', '',
3161                             '\\begin_layout Plain Layout']
3162                 endsubst = ['\\end_layout', '', '\\end_inset', '', document.body[j]]
3163                 document.body[j : j + 1] = endsubst
3164                 document.body[endInset + 1 : endInset + 1] = begsubst
3165                 # Adjust range end
3166                 endlay += len(begsubst) + len(endsubst)
3167                 endlay = endlay - len(document.body[ert : endInset + 1])
3168                 del document.body[ert : endInset + 1]
3169                     
3170         i = endlay
3171
3172
3173 def revert_epigraph(document):
3174     " Reverts memoir epigraph argument to ERT "
3175     
3176     if document.textclass != "memoir":
3177         return
3178
3179     i = 0
3180     while True:
3181         i = find_token(document.body, "\\begin_layout Epigraph", i)
3182         if i == -1:
3183             return
3184         j = find_end_of_layout(document.body, i)
3185         if j == -1:
3186             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3187             i = i + 1
3188             continue
3189         endlay = j
3190         subst = list()
3191         p = find_token(document.body, "\\begin_layout Argument post:1", i, j)
3192         if p != -1:
3193             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3194             endPlain = find_end_of_layout(document.body, beginPlain)
3195             endInset = find_end_of_inset(document.body, p)
3196             content = document.body[beginPlain + 1 : endPlain]
3197             # Adjust range end
3198             endlay = endlay - len(document.body[p : endInset + 1])
3199             # Remove arg inset
3200             del document.body[p : endInset + 1]
3201             subst += put_cmd_in_ert("}{") + content
3202         else:
3203             subst += put_cmd_in_ert("}{")
3204                     
3205         document.body[j : j] = subst + document.body[j : j]
3206         i = endlay
3207
3208
3209 def convert_captioninsets(document):
3210     " Converts caption insets to new syntax "
3211     
3212     i = 0
3213     while True:
3214       i = find_token(document.body, "\\begin_inset Caption", i)
3215       if i == -1:
3216           return
3217       document.body[i] = "\\begin_inset Caption Standard"
3218       i = i + 1
3219
3220
3221 def revert_captioninsets(document):
3222     " Reverts caption insets to old syntax "
3223     
3224     i = 0
3225     while True:
3226       i = find_token(document.body, "\\begin_inset Caption Standard", i)
3227       if i == -1:
3228           return
3229       document.body[i] = "\\begin_inset Caption"
3230       i = i + 1
3231
3232
3233 def convert_captionlayouts(document):
3234     " Convert caption layouts to caption insets. "
3235
3236     caption_dict = {
3237         "Captionabove":  "Above",
3238         "Captionbelow":  "Below",
3239         "FigCaption"  :  "FigCaption",
3240         "Table_Caption" :  "Table",
3241         "CenteredCaption" : "Centered",
3242         "Bicaption" : "Bicaption",
3243         }
3244
3245     i = 0
3246     while True:
3247         i = find_token(document.body, "\\begin_layout", i)
3248         if i == -1:
3249             return
3250         val = get_value(document.body, "\\begin_layout", i)
3251         if val in caption_dict.keys():
3252             j = find_end_of_layout(document.body, i)
3253             if j == -1:
3254                 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3255                 return
3256
3257             document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""]
3258             document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout,
3259                                     "\\begin_inset Caption %s" % caption_dict[val], "",
3260                                     "\\begin_layout %s" % document.default_layout]
3261         i = i + 1
3262
3263
3264 def revert_captionlayouts(document):
3265     " Revert caption insets to caption layouts. "
3266     
3267     caption_dict = {
3268         "Above" : "Captionabove",
3269         "Below" : "Captionbelow",
3270         "FigCaption"  :  "FigCaption",
3271         "Table" : "Table_Caption",
3272         "Centered" : "CenteredCaption",
3273         "Bicaption" : "Bicaption",
3274         }
3275     
3276     i = 0
3277     rx = re.compile(r'^\\begin_inset Caption (\S+)$')
3278     while True:
3279         i = find_token(document.body, "\\begin_inset Caption", i)
3280         if i == -1:
3281             return
3282
3283         m = rx.match(document.body[i])
3284         val = ""
3285         if m:
3286             val = m.group(1)
3287         if val not in caption_dict.keys():
3288             i = i + 1
3289             continue
3290         
3291         # We either need to delete the previous \begin_layout line, or we
3292         # need to end the previous layout if this inset is not in the first
3293         # position of the paragraph.
3294         layout_before = find_token_backwards(document.body, "\\begin_layout", i)
3295         if layout_before == -1:
3296             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3297             return
3298         layout_line = document.body[layout_before]
3299         del_layout_before = True
3300         l = layout_before + 1
3301         while l < i:
3302             if document.body[l] != "":
3303                 del_layout_before = False
3304                 break
3305             l = l + 1
3306         if del_layout_before:
3307             del document.body[layout_before:i]
3308             i = layout_before
3309         else:
3310             document.body[i:i] = ["\\end_layout", ""]
3311             i = i + 2
3312
3313         # Find start of layout in the inset and end of inset
3314         j = find_token(document.body, "\\begin_layout", i)
3315         if j == -1:
3316             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3317             return
3318         k = find_end_of_inset(document.body, i)
3319         if k == -1:
3320             document.warning("Malformed LyX document: Missing `\\end_inset'.")
3321             return
3322
3323         # We either need to delete the following \end_layout line, or we need
3324         # to restart the old layout if this inset is not at the paragraph end.
3325         layout_after = find_token(document.body, "\\end_layout", k)
3326         if layout_after == -1:
3327             document.warning("Malformed LyX document: Missing `\\end_layout'.")
3328             return
3329         del_layout_after = True
3330         l = k + 1
3331         while l < layout_after:
3332             if document.body[l] != "":
3333                 del_layout_after = False
3334                 break
3335             l = l + 1
3336         if del_layout_after:
3337             del document.body[k+1:layout_after+1]
3338         else:
3339             document.body[k+1:k+1] = [layout_line, ""]
3340
3341         # delete \begin_layout and \end_inset and replace \begin_inset with
3342         # "\begin_layout XXX". This works because we can only have one
3343         # paragraph in the caption inset: The old \end_layout will be recycled.
3344         del document.body[k]
3345         if document.body[k] == "":
3346             del document.body[k]
3347         del document.body[j]
3348         if document.body[j] == "":
3349             del document.body[j]
3350         document.body[i] = "\\begin_layout %s" % caption_dict[val]
3351         if document.body[i+1] == "":
3352             del document.body[i+1]
3353         i = i + 1
3354
3355
3356 def revert_fragileframe(document):
3357     " Reverts beamer FragileFrame layout to ERT "
3358     
3359     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3360     if document.textclass not in beamer_classes:
3361         return
3362
3363     i = 0
3364     while True:
3365         i = find_token(document.body, "\\begin_layout FragileFrame", i)
3366         if i == -1:
3367             return
3368         # Find end of sequence
3369         j = find_end_of_sequence(document.body, i)
3370         if j == -1:
3371             document.warning("Malformed LyX document. Cannot find end of FragileFrame sequence!")
3372             i = i + 1
3373             continue
3374         endseq = j
3375         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{frame}")
3376         esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}")
3377         endseq = endseq + len(esubst) - len(document.body[j : j])
3378         if document.body[j] == "\\end_deeper":
3379             document.body[j : j] = ["\\end_deeper", ""] + esubst
3380         else:
3381             document.body[j : j] = esubst
3382         for q in range(i, j):
3383             if document.body[q] == "\\begin_layout FragileFrame":
3384                 document.body[q] = "\\begin_layout %s" % document.default_layout
3385         r = i
3386         while r < j:
3387             if document.body[r] == "\\begin_deeper":
3388                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3389                 if s != -1:
3390                     document.body[r] = ""
3391                     document.body[s] = ""
3392                     r = s
3393                     continue
3394             r = r + 1
3395         for p in range(1, 5):
3396             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, j)
3397             if arg != -1:
3398                 if p == 1:
3399                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3400                     endPlain = find_end_of_layout(document.body, beginPlain)
3401                     endInset = find_end_of_inset(document.body, arg)
3402                     content = document.body[beginPlain + 1 : endPlain]
3403                     # Adjust range end
3404                     j = j - len(document.body[arg : endInset + 1])
3405                     # Remove arg inset
3406                     del document.body[arg : endInset + 1]
3407                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3408                 elif p == 2:
3409                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3410                     endPlain = find_end_of_layout(document.body, beginPlain)
3411                     endInset = find_end_of_inset(document.body, arg)
3412                     content = document.body[beginPlain + 1 : endPlain]
3413                     # Adjust range end
3414                     j = j - len(document.body[arg : endInset + 1])
3415                     # Remove arg inset
3416                     del document.body[arg : endInset + 1]
3417                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3418                 elif p == 3:
3419                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3420                     endPlain = find_end_of_layout(document.body, beginPlain)
3421                     endInset = find_end_of_inset(document.body, arg)
3422                     content = document.body[beginPlain + 1 : endPlain]
3423                     # Adjust range end
3424                     j = j - len(document.body[arg : endInset + 1])
3425                     # Remove arg inset
3426                     del document.body[arg : endInset + 1]
3427                     subst += put_cmd_in_ert("[fragile,") + content + put_cmd_in_ert("]")
3428                 elif p == 4:
3429                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3430                     endPlain = find_end_of_layout(document.body, beginPlain)
3431                     endInset = find_end_of_inset(document.body, arg)
3432                     content = document.body[beginPlain + 1 : endPlain]
3433                     # Adjust range end
3434                     j = j - len(document.body[arg : endInset + 1])
3435                     # Remove arg inset
3436                     del document.body[arg : endInset + 1]
3437                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3438             elif p == 3:
3439                 subst += put_cmd_in_ert("[fragile]")
3440                     
3441         document.body[i : i + 1] = subst
3442         i = j
3443
3444
3445 def revert_newframes(document):
3446     " Reverts beamer Frame and PlainFrame layouts to old forms "
3447     
3448     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3449     if document.textclass not in beamer_classes:
3450         return
3451
3452     frame_dict = {
3453         "Frame" : "BeginFrame",
3454         "PlainFrame" : "BeginPlainFrame",
3455         }
3456
3457     rx = re.compile(r'^\\begin_layout (\S+)$')
3458     i = 0
3459     while True:
3460         i = find_token(document.body, "\\begin_layout", i)
3461         if i == -1:
3462             return
3463
3464         m = rx.match(document.body[i])
3465         val = ""
3466         if m:
3467             val = m.group(1)
3468         if val not in frame_dict.keys():
3469             i = i + 1
3470             continue
3471         # Find end of sequence
3472         j = find_end_of_sequence(document.body, i)
3473         if j == -1:
3474             document.warning("Malformed LyX document. Cannot find end of Frame sequence!")
3475             i = i + 1
3476             continue
3477         endseq = j
3478         subst = ["\\begin_layout %s" % frame_dict[val]]
3479         esubst = ["\\end_layout", "", "\\begin_layout EndFrame", "", "\\end_layout"]
3480         endseq = endseq + len(esubst) - len(document.body[j : j])
3481         if document.body[j] == "\\end_deeper":
3482             document.body[j : j] = ["\\end_deeper", ""] + esubst
3483         else:
3484             document.body[j : j] = esubst
3485         for q in range(i, j):
3486             if document.body[q] == "\\begin_layout %s" % val:
3487                 document.body[q] = "\\begin_layout %s" % document.default_layout
3488         r = i
3489         while r < j:
3490             if document.body[r] == "\\begin_deeper":
3491                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3492                 if s != -1:
3493                     document.body[r] = ""
3494                     document.body[s] = ""
3495                     r = s
3496                     continue
3497             r = r + 1
3498         l = find_end_of_layout(document.body, i)
3499         for p in range(1, 5):
3500             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, l)
3501             if arg != -1:
3502                 if p == 1:
3503                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3504                     endPlain = find_end_of_layout(document.body, beginPlain)
3505                     endInset = find_end_of_inset(document.body, arg)
3506                     content = document.body[beginPlain + 1 : endPlain]
3507                     # Adjust range end
3508                     l = l - len(document.body[arg : endInset + 1])
3509                     # Remove arg inset
3510                     del document.body[arg : endInset + 1]
3511                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3512                 elif p == 2:
3513                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3514                     endPlain = find_end_of_layout(document.body, beginPlain)
3515                     endInset = find_end_of_inset(document.body, arg)
3516                     content = document.body[beginPlain + 1 : endPlain]
3517                     # Adjust range end
3518                     l = l - len(document.body[arg : endInset + 1])
3519                     # Remove arg inset
3520                     del document.body[arg : endInset + 1]
3521                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3522                 elif p == 3:
3523                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3524                     endPlain = find_end_of_layout(document.body, beginPlain)
3525                     endInset = find_end_of_inset(document.body, arg)
3526                     content = document.body[beginPlain + 1 : endPlain]
3527                     # Adjust range end
3528                     l = l - len(document.body[arg : endInset + 1])
3529                     # Remove arg inset
3530                     del document.body[arg : endInset + 1]
3531                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3532                 elif p == 4:
3533                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3534                     endPlain = find_end_of_layout(document.body, beginPlain)
3535                     endInset = find_end_of_inset(document.body, arg)
3536                     content = document.body[beginPlain + 1 : endPlain]
3537                     # Adjust range end
3538                     l = l - len(document.body[arg : endInset + 1])
3539                     # Remove arg inset
3540                     del document.body[arg : endInset + 1]
3541                     subst += content
3542                     
3543         document.body[i : i + 1] = subst
3544         i = j
3545
3546 # known encodings that do not change their names (same LyX and LaTeX names)
3547 known_enc_tuple = ("auto", "default", "ansinew", "applemac", "armscii8", "ascii",
3548     "cp437", "cp437de", "cp850", "cp852", "cp855", "cp858", "cp862", "cp865", "cp866",
3549     "cp1250", "cp1251", "cp1252", "cp1255", "cp1256", "cp1257", "koi8-r", "koi8-u",
3550     "pt154", "pt254", "tis620-0", "utf8", "utf8x", "utf8-plain")
3551
3552 def convert_encodings(document):
3553     "Use the LyX names of the encodings instead of the LaTeX names."
3554     LaTeX2LyX_enc_dict = {
3555         "8859-6":     "iso8859-6",
3556         "8859-8":     "iso8859-8",
3557         "Bg5":        "big5",
3558         "euc":        "euc-jp-platex",
3559         "EUC-JP":     "euc-jp",
3560         "EUC-TW":     "euc-tw",
3561         "GB":         "euc-cn",
3562         "GBK":        "gbk",
3563         "iso88595":   "iso8859-5",
3564         "iso-8859-7": "iso8859-7",
3565         "JIS":        "jis",
3566         "jis":        "jis-platex",
3567         "KS":         "euc-kr",
3568         "l7xenc":     "iso8859-13",
3569         "latin1":     "iso8859-1",
3570         "latin2":     "iso8859-2",
3571         "latin3":     "iso8859-3",
3572         "latin4":     "iso8859-4",
3573         "latin5":     "iso8859-9",
3574         "latin9":     "iso8859-15",
3575         "latin10":    "iso8859-16",
3576         "SJIS":       "shift-jis",
3577         "sjis":       "shift-jis-platex",
3578         "UTF8":       "utf8-cjk"
3579     }
3580     i = find_token(document.header, "\\inputencoding" , 0)
3581     if i == -1:
3582         return
3583     val = get_value(document.header, "\\inputencoding", i)
3584     if val in LaTeX2LyX_enc_dict.keys():
3585         document.header[i] = "\\inputencoding %s" % LaTeX2LyX_enc_dict[val]
3586     elif val not in known_enc_tuple:
3587         document.warning("Ignoring unknown input encoding: `%s'" % val)
3588
3589
3590 def revert_encodings(document):
3591     """Revert to using the LaTeX names of the encodings instead of the LyX names.
3592     Also revert utf8-platex to sjis, the language default when using Japanese.
3593     """
3594     LyX2LaTeX_enc_dict = {
3595         "big5":             "Bg5",
3596         "euc-cn":           "GB",
3597         "euc-kr":           "KS",
3598         "euc-jp":           "EUC-JP",
3599         "euc-jp-platex":    "euc",
3600         "euc-tw":           "EUC-TW",
3601         "gbk":              "GBK",
3602         "iso8859-1":        "latin1",
3603         "iso8859-2":        "latin2",
3604         "iso8859-3":        "latin3",
3605         "iso8859-4":        "latin4",
3606         "iso8859-5":        "iso88595",
3607         "iso8859-6":        "8859-6",
3608         "iso8859-7":        "iso-8859-7",
3609         "iso8859-8":        "8859-8",
3610         "iso8859-9":        "latin5",
3611         "iso8859-13":       "l7xenc",
3612         "iso8859-15":       "latin9",
3613         "iso8859-16":       "latin10",
3614         "jis":              "JIS",
3615         "jis-platex":       "jis",
3616         "shift-jis":        "SJIS",
3617         "shift-jis-platex": "sjis",
3618         "utf8-cjk":         "UTF8",
3619         "utf8-platex":      "sjis"
3620     }
3621     i = find_token(document.header, "\\inputencoding" , 0)
3622     if i == -1:
3623         return
3624     val = get_value(document.header, "\\inputencoding", i)
3625     if val in LyX2LaTeX_enc_dict.keys():
3626         document.header[i] = "\\inputencoding %s" % LyX2LaTeX_enc_dict[val]
3627     elif val not in known_enc_tuple:
3628         document.warning("Ignoring unknown input encoding: `%s'" % val)
3629
3630
3631 def revert_IEEEtran_3(document):
3632   '''
3633   Reverts Flex Insets to TeX-code
3634   '''
3635   if document.textclass == "IEEEtran":
3636     h = 0
3637     i = 0
3638     j = 0
3639     while True:
3640       if h != -1:
3641         h = find_token(document.body, "\\begin_inset Flex Author Mark", h)
3642       if h != -1:
3643         endh = find_end_of_inset(document.body, h)
3644         document.body[endh - 2 : endh + 1] = put_cmd_in_ert("}")
3645         document.body[h : h + 4] = put_cmd_in_ert("\\IEEEauthorrefmark{")
3646         h = h + 5
3647       if i != -1:
3648         i = find_token(document.body, "\\begin_inset Flex Author Name", i)
3649       if i != -1:
3650         endi = find_end_of_inset(document.body, i)
3651         document.body[endi - 2 : endi + 1] = put_cmd_in_ert("}")
3652         document.body[i : i + 4] = put_cmd_in_ert("\\IEEEauthorblockN{")
3653         i = i + 5
3654       if j != -1:
3655         j = find_token(document.body, "\\begin_inset Flex Author Affiliation", j)
3656       if j != -1:
3657         endj = find_end_of_inset(document.body, j)
3658         document.body[endj - 2 : endj + 1] = put_cmd_in_ert("}")
3659         document.body[j : j + 4] = put_cmd_in_ert("\\IEEEauthorblockA{")
3660         j = j + 5
3661       if i == -1 and j == -1 and h == -1:
3662         return
3663
3664
3665 def revert_kurier_fonts(document):
3666   " Revert kurier font definition to LaTeX "
3667   
3668   i = find_token(document.header, "\\font_math", 0)
3669   if i != -1:
3670     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3671       val = get_value(document.header, "\\font_math", i)
3672       if val == "kurier-math":
3673         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
3674           "\\usepackage[math]{kurier}\n" \
3675           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
3676         document.header[i] = "\\font_math auto"
3677   
3678   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3679     kurier_fonts = ["kurier", "kurierc", "kurierl", "kurierlc"]
3680     k = find_token(document.header, "\\font_sans kurier", 0)
3681     if k != -1:
3682       sf = get_value(document.header, "\\font_sans", k)
3683       if sf in kurier_fonts:
3684         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
3685         document.header[k] = "\\font_sans default"
3686
3687 def revert_iwona_fonts(document):
3688   " Revert iwona font definition to LaTeX "
3689   
3690   i = find_token(document.header, "\\font_math", 0)
3691   if i != -1:
3692     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3693       val = get_value(document.header, "\\font_math", i)
3694       if val == "iwona-math":
3695         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
3696           "\\usepackage[math]{iwona}\n" \
3697           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
3698         document.header[i] = "\\font_math auto"
3699   
3700   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
3701     iwona_fonts = ["iwona", "iwonac", "iwonal", "iwonalc"]
3702     k = find_token(document.header, "\\font_sans iwona", 0)
3703     if k != -1:
3704       sf = get_value(document.header, "\\font_sans", k)
3705       if sf in iwona_fonts:
3706         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
3707         document.header[k] = "\\font_sans default"
3708
3709
3710 def revert_new_libertines(document):
3711     " Revert new libertine font definition to LaTeX "
3712   
3713     if find_token(document.header, "\\use_non_tex_fonts true", 0) != -1:
3714         return
3715
3716     i = find_token(document.header, "\\font_typewriter libertine-mono", 0)
3717     if i != -1:
3718         preamble = "\\usepackage"
3719         sc = find_token(document.header, "\\font_tt_scale", 0)
3720         if sc != -1:
3721             scval = get_value(document.header, "\\font_tt_scale", sc)
3722             if scval != "100":
3723                 preamble += "[scale=%f]" % (float(scval) / 100)
3724                 document.header[sc] = "\\font_tt_scale 100"
3725         preamble += "{libertineMono-type1}"
3726         add_to_preamble(document, [preamble])
3727         document.header[i] = "\\font_typewriter default"
3728    
3729     k = find_token(document.header, "\\font_sans biolinum", 0)
3730     if k != -1:
3731         preamble = "\\usepackage"
3732         options = ""
3733         j = find_token(document.header, "\\font_osf true", 0)
3734         if j != -1:
3735             options += "osf"
3736         else:
3737             options += "lining"
3738         sc = find_token(document.header, "\\font_sf_scale", 0)
3739         if sc != -1:
3740             scval = get_value(document.header, "\\font_sf_scale", sc)
3741             if scval != "100":
3742                 options += ",scale=%f" % (float(scval) / 100)
3743                 document.header[sc] = "\\font_sf_scale 100"
3744         if options != "":
3745             preamble += "[" + options +"]"
3746         preamble += "{biolinum-type1}"
3747         add_to_preamble(document, [preamble])
3748         document.header[k] = "\\font_sans default"
3749
3750
3751 def convert_lyxframes(document):
3752     " Converts old beamer frames to new style "
3753     
3754     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3755     if document.textclass not in beamer_classes:
3756         return
3757    
3758     framebeg = ["BeginFrame", "BeginPlainFrame"]
3759     frameend = ["Frame", "PlainFrame", "EndFrame", "BeginFrame", "BeginPlainFrame", "AgainFrame",
3760                 "Section", "Section*", "Subsection", "Subsection*", "Subsubsection", "Subsubsection*"]
3761     for lay in framebeg:
3762         i = 0
3763         while True:
3764             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
3765             if i == -1:
3766                 break
3767             parent = get_containing_layout(document.body, i)
3768             if parent == False or parent[1] != i:
3769                 document.warning("Wrong parent layout!")
3770                 i += 1
3771                 continue
3772             frametype = parent[0]
3773             j = parent[2]
3774             parbeg = parent[3]
3775             if i != -1:
3776                 # Step I: Convert ERT arguments
3777                 # FIXME: This currently only works if the arguments are in one single ERT
3778                 ertend = i
3779                 if document.body[parbeg] == "\\begin_inset ERT":
3780                     ertend = find_end_of_inset(document.body, parbeg)
3781                     if ertend == -1:
3782                         document.warning("Malformed LyX document: missing ERT \\end_inset")
3783                         continue
3784                     ertcont = parbeg + 5
3785                     if document.body[ertcont].startswith("[<"):
3786                         # This is a default overlay specification
3787                         # strip off the [<
3788                         document.body[ertcont] = document.body[ertcont][2:]
3789                         if document.body[ertcont].endswith(">]"):
3790                             # strip off the >]
3791                             document.body[ertcont] = document.body[ertcont][:-2]
3792                         elif document.body[ertcont].endswith("]"):
3793                             # divide the args
3794                             tok = document.body[ertcont].find('>][')
3795                             if tok != -1:
3796                                 subst = [document.body[ertcont][:tok],
3797                                          '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
3798                                          'status collapsed', '', '\\begin_layout Plain Layout',
3799                                          document.body[ertcont][tok + 3:-1]]
3800                                 document.body[ertcont : ertcont + 1] = subst
3801                                 ertend += 11
3802                         # Convert to ArgInset
3803                         document.body[parbeg] = "\\begin_inset Argument 2"
3804                     elif document.body[ertcont].startswith("<"):
3805                         # This is an overlay specification
3806                         # strip off the <
3807                         document.body[ertcont] = document.body[ertcont][1:]
3808                         if document.body[ertcont].endswith(">"):
3809                             # strip off the >
3810                             document.body[ertcont] = document.body[ertcont][:-1]
3811                             # Convert to ArgInset
3812                             document.body[parbeg] = "\\begin_inset Argument 1"
3813                         elif document.body[ertcont].endswith(">]"):
3814                             # divide the args
3815                             tok = document.body[ertcont].find('>[<')
3816                             if tok != -1:
3817                                document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
3818                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3819                                                                'status collapsed', '', '\\begin_layout Plain Layout',
3820                                                                document.body[ertcont][tok + 3:-2]]
3821                             # Convert to ArgInset
3822                             document.body[parbeg] = "\\begin_inset Argument 1"
3823                             ertend += 11
3824                         elif document.body[ertcont].endswith("]"):
3825                             # divide the args
3826                             tok = document.body[ertcont].find('>[<')
3827                             if tok != -1:
3828                                # divide the args
3829                                tokk = document.body[ertcont].find('>][')
3830                                if tokk != -1:
3831                                    document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
3832                                                                    '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3833                                                                    'status collapsed', '', '\\begin_layout Plain Layout',
3834                                                                    document.body[ertcont][tok + 3:tokk],
3835                                                                    '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
3836                                                                    'status collapsed', '', '\\begin_layout Plain Layout',
3837                                                                    document.body[ertcont][tokk + 3:-1]]
3838                                    ertend += 22
3839                             else:
3840                                 tokk = document.body[ertcont].find('>[')
3841                                 if tokk != -1:
3842                                     document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
3843                                                                     '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
3844                                                                     'status collapsed', '', '\\begin_layout Plain Layout',
3845                                                                     document.body[ertcont][tokk + 2:-1]]
3846                                     ertend += 11
3847                             # Convert to ArgInset
3848                             document.body[parbeg] = "\\begin_inset Argument 1"
3849                     elif document.body[ertcont].startswith("["):
3850                         # This is an ERT option
3851                         # strip off the [
3852                         document.body[ertcont] = document.body[ertcont][1:]
3853                         if document.body[ertcont].endswith("]"):
3854                             # strip off the ]
3855                             document.body[ertcont] = document.body[ertcont][:-1]
3856                             # Convert to ArgInset
3857                             document.body[parbeg] = "\\begin_inset Argument 3"
3858                 # End of argument conversion
3859                 # Step II: Now rename the layout and convert the title to an argument
3860                 j = find_end_of_layout(document.body, i)
3861                 document.body[j : j + 1] = ['\\end_layout', '', '\\end_inset', '', '\\end_layout']
3862                 if lay == "BeginFrame":
3863                     document.body[i] = "\\begin_layout Frame"
3864                 else:
3865                     document.body[i] = "\\begin_layout PlainFrame"
3866                 document.body[ertend + 1 : ertend + 1] = ['\\begin_inset Argument 4',
3867                                                 'status open', '', '\\begin_layout Plain Layout']
3868                 # Step III: find real frame end
3869                 j = j + 8
3870                 jj = j
3871                 while True:
3872                     fend = find_token(document.body, "\\begin_layout", jj)
3873                     if fend == -1:
3874                         document.warning("Malformed LyX document: No real frame end!")
3875                         return
3876                     val = get_value(document.body, "\\begin_layout", fend)
3877                     if val not in frameend:
3878                         jj = fend + 1
3879                         continue
3880                     old = document.body[fend]
3881                     if val == frametype:
3882                         document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
3883                     else:
3884                         document.body[fend : fend] = ['\\end_deeper']
3885                     document.body[j + 1 : j + 1] = ['', '\\begin_deeper']
3886                     break
3887             i = j
3888
3889
3890 def remove_endframes(document):
3891     " Remove deprecated beamer endframes "
3892     
3893     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3894     if document.textclass not in beamer_classes:
3895         return
3896    
3897     i = 0
3898     while True:
3899         i = find_token_exact(document.body, "\\begin_layout EndFrame", i)
3900         if i == -1:
3901             break
3902         j = find_end_of_layout(document.body, i)
3903         if j == -1:
3904             document.warning("Malformed LyX document: Missing \\end_layout to EndFrame")
3905             i = i + 1
3906             continue
3907         del document.body[i : j + 1]
3908
3909
3910 def revert_powerdot_flexes(document):
3911     " Reverts powerdot flex insets "
3912     
3913     if document.textclass != "powerdot":
3914         return
3915
3916     flexes = {"Onslide" : "\\onslide",
3917               "Onslide*" : "\\onslide*",
3918               "Onslide+" : "\\onslide+"}
3919     rx = re.compile(r'^\\begin_inset Flex (.+)$')
3920
3921     i = 0
3922     while True:
3923         i = find_token(document.body, "\\begin_inset Flex", i)
3924         if i == -1:
3925             return
3926         m = rx.match(document.body[i])
3927         if m:
3928             flextype = m.group(1)
3929             z = find_end_of_inset(document.body, i)
3930             if z == -1:
3931                 document.warning("Can't find end of Flex " + flextype + " inset.")
3932                 i += 1
3933                 continue
3934             if flextype in flexes:
3935                 pre = put_cmd_in_ert(flexes[flextype])
3936                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
3937                 if arg != -1:
3938                     argend = find_end_of_inset(document.body, arg)
3939                     if argend == -1:
3940                         document.warning("Can't find end of Argument!")
3941                         i += 1
3942                         continue
3943                     # Find containing paragraph layout
3944                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3945                     endPlain = find_end_of_layout(document.body, beginPlain)
3946                     argcontent = document.body[beginPlain + 1 : endPlain]
3947                     # Adjust range end
3948                     z = z - len(document.body[arg : argend + 1])
3949                     # Remove arg inset
3950                     del document.body[arg : argend + 1]
3951                     pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
3952                 pre += put_cmd_in_ert("{")
3953                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
3954                 endPlain = find_end_of_layout(document.body, beginPlain)
3955                 # Adjust range end
3956                 z = z - len(document.body[i : beginPlain + 1])
3957                 z += len(pre)
3958                 document.body[i : beginPlain + 1] = pre
3959                 post = put_cmd_in_ert("}")
3960                 document.body[z - 2 : z + 1] = post     
3961         i += 1
3962
3963
3964 def revert_powerdot_pause(document):
3965     " Reverts powerdot pause layout to ERT "
3966     
3967     if document.textclass != "powerdot":
3968         return
3969
3970     i = 0
3971     while True:
3972         i = find_token(document.body, "\\begin_layout Pause", i)
3973         if i == -1:
3974             return
3975         j = find_end_of_layout(document.body, i)
3976         if j == -1:
3977             document.warning("Malformed LyX document: Can't find end of Pause layout")
3978             i = i + 1
3979             continue
3980         endlay = j
3981         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\pause")
3982         for p in range(i, j):
3983             if p >= endlay:
3984                 break
3985             arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3986             if arg != -1:
3987                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3988                 endPlain = find_end_of_layout(document.body, beginPlain)
3989                 endInset = find_end_of_inset(document.body, p)
3990                 content = document.body[beginPlain + 1 : endPlain]
3991                 # Adjust range end
3992                 endlay = endlay - len(document.body[p : endInset + 1])
3993                 # Remove arg inset
3994                 del document.body[p : endInset + 1]
3995                 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3996                     
3997         document.body[i : i + 1] = subst
3998         i = endlay
3999
4000
4001 def revert_powerdot_itemargs(document):
4002     " Reverts powerdot item arguments to ERT "
4003     
4004     if document.textclass != "powerdot":
4005         return
4006
4007     i = 0
4008     list_layouts = ["Itemize", "ItemizeType1", "Enumerate", "EnumerateType1"]
4009     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4010
4011     while True:
4012         i = find_token(document.body, "\\begin_inset Argument", i)
4013         if i == -1:
4014             return
4015         # Find containing paragraph layout
4016         parent = get_containing_layout(document.body, i)
4017         if parent == False:
4018             document.warning("Malformed LyX document: Can't find parent paragraph layout")
4019             i = i + 1
4020             continue
4021         parbeg = parent[1]
4022         parend = parent[2]
4023         realparbeg = parent[3]
4024         layoutname = parent[0]
4025         realparend = parend
4026         for p in range(parbeg, parend):
4027             if p >= realparend:
4028                 i = realparend
4029                 break
4030             if layoutname in list_layouts:
4031                 m = rx.match(document.body[p])
4032                 if m:
4033                     argnr = m.group(1)
4034                     if argnr == "item:1":
4035                         j = find_end_of_inset(document.body, i)
4036                         # Find containing paragraph layout
4037                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4038                         endPlain = find_end_of_layout(document.body, beginPlain)
4039                         content = document.body[beginPlain + 1 : endPlain]
4040                         del document.body[i:j+1]
4041                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4042                         document.body[realparbeg : realparbeg] = subst
4043                     elif argnr == "item:2":
4044                         j = find_end_of_inset(document.body, i)
4045                         # Find containing paragraph layout
4046                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4047                         endPlain = find_end_of_layout(document.body, beginPlain)
4048                         content = document.body[beginPlain + 1 : endPlain]
4049                         del document.body[i:j+1]
4050                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
4051                         document.body[realparbeg : realparbeg] = subst
4052         
4053         i = realparend
4054
4055
4056 def revert_powerdot_columns(document):
4057     " Reverts powerdot twocolumn to TeX-code "
4058     if document.textclass != "powerdot":
4059         return
4060
4061     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4062     i = 0
4063     while True:
4064         i = find_token(document.body, "\\begin_layout Twocolumn", i)
4065         if i == -1:
4066             return
4067         j = find_end_of_layout(document.body, i)
4068         if j == -1:
4069             document.warning("Malformed LyX document: Can't find end of Twocolumn layout")
4070             i = i + 1
4071             continue
4072         endlay = j
4073         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
4074         endlay += len(put_cmd_in_ert("}"))
4075         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\twocolumn")
4076         for p in range(i, j):
4077             if p >= endlay:
4078                 break
4079             m = rx.match(document.body[p])
4080             if m:
4081                 argnr = m.group(1)
4082                 if argnr == "1":
4083                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4084                     endPlain = find_end_of_layout(document.body, beginPlain)
4085                     endInset = find_end_of_inset(document.body, p)
4086                     content = document.body[beginPlain + 1 : endPlain]
4087                     # Adjust range end
4088                     endlay = endlay - len(document.body[p : endInset + 1])
4089                     # Remove arg inset
4090                     del document.body[p : endInset + 1]
4091                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4092                 elif argnr == "2":
4093                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4094                     endPlain = find_end_of_layout(document.body, beginPlain)
4095                     endInset = find_end_of_inset(document.body, p)
4096                     content = document.body[beginPlain + 1 : endPlain]
4097                     # Adjust range end
4098                     endlay = endlay - len(document.body[p : endInset + 1])
4099                     # Remove arg inset
4100                     del document.body[p : endInset + 1]
4101                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
4102                     
4103         subst += put_cmd_in_ert("{")
4104         document.body[i : i + 1] = subst
4105         i = endlay
4106
4107
4108 def revert_mbox_fbox(document):
4109     'Convert revert mbox/fbox boxes to TeX-code'
4110     i = 0
4111     while True:
4112         i = find_token(document.body, "\\begin_inset Box", i)
4113         if i == -1:
4114             return
4115         j = find_token(document.body, "width", i)
4116         if j != i + 7:
4117             document.warning("Malformed LyX document: Can't find box width")
4118             return
4119         width = get_value(document.body, "width", j)
4120         k = find_end_of_inset(document.body, j)
4121         if k == -1:
4122             document.warning("Malformed LyX document: Can't find end of box inset")
4123             i += 1
4124             continue
4125         BeginLayout = find_token(document.body, "\\begin_layout Plain Layout", j)
4126         EndLayout = find_token(document.body, "\\end_layout", BeginLayout)
4127         # replace if width is ""
4128         if (width == '""'):
4129             document.body[EndLayout:k + 1] = put_cmd_in_ert("}")
4130             if document.body[i] == "\\begin_inset Box Frameless":
4131                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\mbox{")
4132             if document.body[i] == "\\begin_inset Box Boxed":
4133                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\fbox{")
4134         i = i + 1
4135
4136
4137 def revert_starred_caption(document):
4138     " Reverts unnumbered longtable caption insets "
4139     
4140     i = 0
4141     while True:
4142       i = find_token(document.body, "\\begin_inset Caption LongTableNoNumber", i)
4143       if i == -1:
4144           return
4145       # This is not equivalent, but since the caption inset is a full blown
4146       # text inset a true conversion to ERT is too difficult.
4147       document.body[i] = "\\begin_inset Caption Standard"
4148       i = i + 1
4149
4150
4151 def revert_forced_local_layout(document):
4152     i = 0
4153     while True:
4154         i = find_token(document.header, "\\begin_forced_local_layout", i)
4155         if i == -1:
4156             return
4157         j = find_end_of(document.header, i, "\\begin_forced_local_layout", "\\end_forced_local_layout")
4158         if j == -1:
4159             # this should not happen
4160             break
4161         regexp = re.compile(r'\s*forcelocal', re.IGNORECASE)
4162         k = find_re(document.header, regexp, i, j)
4163         while k != -1:
4164             del document.header[k]
4165             j = j - 1
4166             k = find_re(document.header, regexp, i, j)
4167         k = find_token(document.header, "\\begin_local_layout", 0)
4168         if k == -1:
4169             document.header[i] = "\\begin_local_layout"
4170             document.header[j] = "\\end_local_layout"
4171         else:
4172             l = find_end_of(document.header, k, "\\begin_local_layout", "\\end_local_layout")
4173             if j == -1:
4174                 # this should not happen
4175                 break
4176             lines = document.header[i+1 : j]
4177             if k > i:
4178                 document.header[k+1 : k+1] = lines
4179                 document.header[i   : j  ] = []
4180             else:
4181                 document.header[i   : j  ] = []
4182                 document.header[k+1 : k+1] = lines
4183
4184
4185 def revert_aa1(document):
4186   " Reverts InsetArguments of aa to TeX-code "
4187   if document.textclass == "aa":
4188     i = 0
4189     while True:
4190       if i != -1:
4191         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4192       if i != -1:
4193         revert_Argument_to_TeX_brace(document, i, 0, 1, 4, False, False)
4194         i = i + 1
4195       if i == -1:
4196         return
4197
4198
4199 def revert_aa2(document):
4200   " Reverts InsetArguments of aa to TeX-code "
4201   if document.textclass == "aa":
4202     i = 0
4203     while True:
4204       if i != -1:
4205         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4206       if i != -1:
4207         document.body[i] = "\\begin_layout Abstract"
4208         i = i + 1
4209       if i == -1:
4210         return
4211
4212
4213 def revert_tibetan(document):
4214     "Set the document language for Tibetan to English" 
4215
4216     if document.language == "tibetan":
4217         document.language = "english"
4218         i = find_token(document.header, "\\language", 0) 
4219         if i != -1: 
4220             document.header[i] = "\\language english" 
4221     j = 0
4222     while j < len(document.body): 
4223         j = find_token(document.body, "\\lang tibetan", j)
4224         if j != -1:
4225             document.body[j] = document.body[j].replace("\\lang tibetan", "\\lang english")
4226             j += 1
4227         else:
4228             j = len(document.body)
4229
4230
4231 #############
4232 #
4233 # Chunk stuff
4234 #
4235 #############
4236
4237 # the idea here is that we will have a sequence of chunk paragraphs
4238 # we want to convert them to paragraphs in a chunk inset
4239 # the last will be discarded
4240 # the first should look like: <<FROGS>>=
4241 # will will discard the delimiters, and put the contents into the
4242 # optional argument of the inset
4243 def convert_chunks(document):
4244     first_re = re.compile(r'<<(.*)>>=')
4245     k = 0
4246     while True:
4247         # the beginning of this sequence
4248         i = k
4249         # find start of a block of chunks
4250         i = find_token(document.body, "\\begin_layout Chunk", i)
4251         if i == -1:
4252             return
4253         start = i
4254         end = -1
4255         contents = []
4256
4257         while True:
4258             # process the one we just found
4259             j = find_end_of_layout(document.body, i)
4260             if j == -1:
4261                 document.warning("Malformed LyX documents. Can't find end of Chunk layout!")
4262                 break
4263             thischunk = "".join(document.body[i + 1:j])
4264             contents.append(document.body[i + 1:j])
4265             
4266             if thischunk == "@":
4267                 break
4268
4269             # look for the next one
4270             #i = j
4271             i = find_token(document.body, "\\begin_layout", i)
4272             if i == -1:
4273                 break
4274
4275             layout = get_value(document.body, "\\begin_layout", i)
4276             #sys.stderr.write(layout+ '\n')
4277             if layout != "Chunk":
4278                 break
4279
4280         if j == -1:
4281             # error, but we can try to continue
4282             k = j + 1
4283             continue
4284
4285         end = j + 1
4286         k = end
4287         
4288         # the last chunk should simply have an "@" in it
4289         
4290         if ''.join(contents[-1]) != "@":
4291             document.warning("Unexpected chunk contents.")
4292             continue
4293
4294         contents.pop()
4295
4296         # the first item should look like: <<FROGS>>=
4297         # we want the inside
4298         optarg = ' '.join(contents[0])
4299         optarg.strip()
4300         match = first_re.search(optarg)
4301         if match:
4302             optarg = match.groups()[0]
4303             contents.pop(0)
4304
4305         newstuff = ['\\begin_layout Standard',
4306                     '\\begin_inset Flex Chunk',
4307                     'status open', '',
4308                     '\\begin_layout Plain Layout', '']
4309
4310         if match:
4311             newstuff.extend(
4312                 ['\\begin_inset Argument 1',
4313                  'status open', '',
4314                  '\\begin_layout Plain Layout',
4315                  optarg,
4316                  '\\end_layout', '',
4317                  '\\end_inset', ''])
4318
4319         didone = False
4320         for c in contents:
4321             if didone:
4322                 newstuff.extend(['', '\\begin_layout Plain Layout', ''])
4323             else:
4324                 didone = True
4325             newstuff.extend(c)
4326             newstuff.append('\\end_layout')
4327
4328         newstuff.extend(['', '\\end_inset', '', '\\end_layout', ''])
4329
4330         document.body[start:end] = newstuff
4331
4332         k += len(newstuff) - (end - start)
4333
4334
4335 def revert_chunks(document):
4336     i = 0
4337     while True:
4338         i = find_token(document.body, "\\begin_inset Flex Chunk", i)
4339         if i == -1:
4340             return
4341
4342         iend = find_end_of_inset(document.body, i)
4343         if iend == -1:
4344             document.warning("Can't find end of Chunk!")
4345             i += 1
4346             continue
4347
4348         # Look for optional argument
4349         have_optarg = False
4350         ostart = find_token(document.body, "\\begin_inset Argument 1", i, iend)
4351         if ostart != -1:
4352             oend = find_end_of_inset(document.body, ostart)
4353             k = find_token(document.body, "\\begin_layout Plain Layout", ostart, oend)
4354             if k == -1:
4355                 document.warning("Malformed LyX document: Can't find argument contents!")
4356             else:
4357                 m = find_end_of_layout(document.body, k)
4358                 optarg = "".join(document.body[k+1:m])
4359                 have_optarg = True
4360
4361             # We now remove the optional argument, so we have something
4362             # uniform on which to work
4363             document.body[ostart : oend + 1] = []
4364             # iend is now invalid
4365             iend = find_end_of_inset(document.body, i)
4366
4367         retval = get_containing_layout(document.body, i)
4368         if not retval:
4369             document.warning("Can't find containing layout for Chunk!")
4370             i = iend
4371             continue
4372         (lname, lstart, lend, pstart)  = retval
4373         # we now want to work through the various paragraphs, and collect their contents
4374         parlist = []
4375         k = i
4376         while True:
4377             k = find_token(document.body, "\\begin_layout Plain Layout", k, lend)
4378             if k == -1:
4379                 break
4380             j = find_end_of_layout(document.body, k)
4381             if j == -1:
4382                 document.warning("Can't find end of layout inside chunk!")
4383                 break
4384             parlist.append(document.body[k+1:j])
4385             k = j
4386         # we now need to wrap all of these paragraphs in chunks
4387         newlines = []
4388         if have_optarg:
4389             newlines.extend(["\\begin_layout Chunk", "", "<<" + optarg + ">>=", "\\end_layout", ""])
4390         for stuff in parlist:
4391             newlines.extend(["\\begin_layout Chunk"] + stuff + ["\\end_layout", ""])
4392         newlines.extend(["\\begin_layout Chunk", "", "@", "\\end_layout", ""])
4393         # replace old content with new content
4394         document.body[lstart : lend + 1] = newlines
4395         i = lstart + len(newlines)
4396         
4397
4398 ##
4399 # Conversion hub
4400 #
4401
4402 supported_versions = ["2.1.0","2.1"]
4403 convert = [
4404            [414, []],
4405            [415, [convert_undertilde]],
4406            [416, []],
4407            [417, [convert_japanese_encodings]],
4408            [418, []],
4409            [419, []],
4410            [420, [convert_biblio_style]],
4411            [421, [convert_longtable_captions]],
4412            [422, [convert_use_packages]],
4413            [423, [convert_use_mathtools]],
4414            [424, [convert_cite_engine_type]],
4415            [425, []],
4416            [426, []],
4417            [427, []],
4418            [428, [convert_cell_rotation]],
4419            [429, [convert_table_rotation]],
4420            [430, [convert_listoflistings]],
4421            [431, [convert_use_amssymb]],
4422            [432, []],
4423            [433, [convert_armenian]],
4424            [434, []],
4425            [435, []],
4426            [436, []],
4427            [437, []],
4428            [438, []],
4429            [439, []],
4430            [440, []],
4431            [441, [convert_mdnomath]],
4432            [442, []],
4433            [443, []],
4434            [444, []],
4435            [445, []],
4436            [446, [convert_latexargs]],
4437            [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV, convert_Initials, convert_ModernCV]],
4438            [448, [convert_literate]],
4439            [449, []],
4440            [450, []],
4441            [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]],
4442            [452, [convert_beamerblocks]],
4443            [453, [convert_use_stmaryrd]],
4444            [454, [convert_overprint]],
4445            [455, []],
4446            [456, [convert_epigraph]],
4447            [457, [convert_use_stackrel]],
4448            [458, [convert_captioninsets, convert_captionlayouts]],
4449            [459, []],
4450            [460, []],
4451            [461, []],
4452            [462, []],
4453            [463, [convert_encodings]],
4454            [464, [convert_use_cancel]],
4455            [465, [convert_lyxframes, remove_endframes]],
4456            [466, []],
4457            [467, []],
4458            [468, []],
4459            [469, []],
4460            [470, []],
4461            [471, [convert_cite_engine_type_default]],
4462            [472, []],
4463            [473, []],
4464            [474, [convert_chunks]],
4465           ]
4466
4467 revert =  [
4468            [473, [revert_chunks]],
4469            [472, [revert_tibetan]],
4470            [471, [revert_aa1,revert_aa2]],
4471            [470, [revert_cite_engine_type_default]],
4472            [469, [revert_forced_local_layout]],
4473            [468, [revert_starred_caption]],
4474            [467, [revert_mbox_fbox]],
4475            [466, [revert_iwona_fonts]],
4476            [465, [revert_powerdot_flexes, revert_powerdot_pause, revert_powerdot_itemargs, revert_powerdot_columns]],
4477            [464, []],
4478            [463, [revert_use_cancel]],
4479            [462, [revert_encodings]],
4480            [461, [revert_new_libertines]],
4481            [460, [revert_kurier_fonts]],
4482            [459, [revert_IEEEtran_3]],
4483            [458, [revert_fragileframe, revert_newframes]],
4484            [457, [revert_captioninsets, revert_captionlayouts]],
4485            [456, [revert_use_stackrel]],
4486            [455, [revert_epigraph]],
4487            [454, [revert_frametitle]],
4488            [453, [revert_overprint]],
4489            [452, [revert_use_stmaryrd]],
4490            [451, [revert_beamerblocks]],
4491            [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
4492            [449, [revert_garamondx, revert_garamondx_newtxmath]],
4493            [448, [revert_itemargs]],
4494            [447, [revert_literate]],
4495            [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]],
4496            [445, [revert_latexargs]],
4497            [444, [revert_uop]],
4498            [443, [revert_biolinum]],
4499            [442, []],
4500            [441, [revert_newtxmath]],
4501            [440, [revert_mdnomath]],
4502            [439, [revert_mathfonts]],
4503            [438, [revert_minionpro]],
4504            [437, [revert_ipadeco, revert_ipachar]],
4505            [436, [revert_texgyre]],
4506            [435, [revert_mathdesign]],
4507            [434, [revert_txtt]],
4508            [433, [revert_libertine]],
4509            [432, [revert_armenian]],
4510            [431, [revert_languages, revert_ancientgreek]],
4511            [430, [revert_use_amssymb]],
4512            [429, [revert_listoflistings]],
4513            [428, [revert_table_rotation]],
4514            [427, [revert_cell_rotation]],
4515            [426, [revert_tipa]],
4516            [425, [revert_verbatim]],
4517            [424, [revert_cancel]],
4518            [423, [revert_cite_engine_type]],
4519            [422, [revert_use_mathtools]],
4520            [421, [revert_use_packages]],
4521            [420, [revert_longtable_captions]],
4522            [419, [revert_biblio_style]],
4523            [418, [revert_australian]],
4524            [417, [revert_justification]],
4525            [416, [revert_japanese_encodings]],
4526            [415, [revert_negative_space, revert_math_spaces]],
4527            [414, [revert_undertilde]],
4528            [413, [revert_visible_space]]
4529           ]
4530
4531
4532 if __name__ == "__main__":
4533     pass