]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_1.py
Fix problem with Initial layout conversion reported by Scott on
[lyx.git] / lib / lyx2lyx / lyx_2_1.py
1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # -*- coding: utf-8 -*-
4 # Copyright (C) 2011 The LyX team
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
20 """ Convert files to the file format generated by LyX 2.1"""
21
22 import re, string
23 import unicodedata
24 import sys, os
25
26 # Uncomment only what you need to import, please.
27
28 from parser_tools import count_pars_in_inset, del_token, find_token, find_token_exact, \
29     find_token_backwards, find_end_of, find_end_of_inset, find_end_of_layout, \
30     find_end_of_sequence, find_re, get_option_value, get_containing_layout, \
31     get_value, get_quoted_value, set_option_value
32
33 #from parser_tools import find_token, find_end_of, find_tokens, \
34   #find_end_of_inset, find_end_of_layout, \
35   #is_in_inset, del_token, check_token
36
37 from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, get_ert
38
39 #from lyx2lyx_tools import insert_to_preamble, \
40 #  lyx2latex, latex_length, revert_flex_inset, \
41 #  revert_font_attrs, hex2ratio, str2bool
42
43 ####################################################################
44 # Private helper functions
45
46 #def remove_option(lines, m, option):
47     #''' removes option from line m. returns whether we did anything '''
48     #l = lines[m].find(option)
49     #if l == -1:
50         #return False
51     #val = lines[m][l:].split('"')[1]
52     #lines[m] = lines[m][:l - 1] + lines[m][l+len(option + '="' + val + '"'):]
53     #return True
54
55
56 ###############################################################################
57 ###
58 ### Conversion and reversion routines
59 ###
60 ###############################################################################
61
62 def revert_visible_space(document):
63     "Revert InsetSpace visible into its ERT counterpart"
64     i = 0
65     while True:
66       i = find_token(document.body, "\\begin_inset space \\textvisiblespace{}", i)
67       if i == -1:
68         return
69       end = find_end_of_inset(document.body, i)
70       subst = put_cmd_in_ert("\\textvisiblespace{}")
71       document.body[i:end + 1] = subst
72
73
74 def convert_undertilde(document):
75     " Load undertilde automatically "
76     i = find_token(document.header, "\\use_mathdots" , 0)
77     if i == -1:
78         i = find_token(document.header, "\\use_mhchem" , 0)
79     if i == -1:
80         i = find_token(document.header, "\\use_esint" , 0)
81     if i == -1:
82         document.warning("Malformed LyX document: Can't find \\use_mathdots.")
83         return;
84     j = find_token(document.preamble, "\\usepackage{undertilde}", 0)
85     if j == -1:
86         document.header.insert(i + 1, "\\use_undertilde 0")
87     else:
88         document.header.insert(i + 1, "\\use_undertilde 2")
89         del document.preamble[j]
90
91
92 def revert_undertilde(document):
93     " Load undertilde if used in the document "
94     undertilde = find_token(document.header, "\\use_undertilde" , 0)
95     if undertilde == -1:
96       document.warning("No \\use_undertilde line. Assuming auto.")
97     else:
98       val = get_value(document.header, "\\use_undertilde", undertilde)
99       del document.header[undertilde]
100       try:
101         usetilde = int(val)
102       except:
103         document.warning("Invalid \\use_undertilde value: " + val + ". Assuming auto.")
104         # probably usedots has not been changed, but be safe.
105         usetilde = 1
106
107       if usetilde == 0:
108         # do not load case
109         return
110       if usetilde == 2:
111         # force load case
112         add_to_preamble(document, ["\\usepackage{undertilde}"])
113         return
114
115     # so we are in the auto case. we want to load undertilde if \utilde is used.
116     i = 0
117     while True:
118       i = find_token(document.body, '\\begin_inset Formula', i)
119       if i == -1:
120         return
121       j = find_end_of_inset(document.body, i)
122       if j == -1:
123         document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
124         i += 1
125         continue
126       code = "\n".join(document.body[i:j])
127       if code.find("\\utilde") != -1:
128         add_to_preamble(document, ["\\@ifundefined{utilde}{\\usepackage{undertilde}}"])
129         return
130       i = j
131
132
133 def revert_negative_space(document):
134     "Revert InsetSpace negmedspace and negthickspace into its TeX-code counterpart"
135     i = 0
136     j = 0
137     reverted = False
138     while True:
139       i = find_token(document.body, "\\begin_inset space \\negmedspace{}", i)
140       if i == -1:
141         j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
142         if j == -1:
143           # load amsmath in the preamble if not already loaded if we are at the end of checking
144           if reverted == True:
145             i = find_token(document.header, "\\use_amsmath 2", 0)
146             if i == -1:
147               add_to_preamble(document, ["\\@ifundefined{negthickspace}{\\usepackage{amsmath}}"])
148           return
149       if i == -1:
150         return
151       end = find_end_of_inset(document.body, i)
152       subst = put_cmd_in_ert("\\negmedspace{}")
153       document.body[i:end + 1] = subst
154       j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
155       if j == -1:
156         return
157       end = find_end_of_inset(document.body, j)
158       subst = put_cmd_in_ert("\\negthickspace{}")
159       document.body[j:end + 1] = subst
160       reverted = True
161
162
163 def revert_math_spaces(document):
164     "Revert formulas with protected custom space and protected hfills to TeX-code"
165     i = 0
166     while True:
167       i = find_token(document.body, "\\begin_inset Formula", i)
168       if i == -1:
169         return
170       j = document.body[i].find("\\hspace*")
171       if j != -1:
172         end = find_end_of_inset(document.body, i)
173         subst = put_cmd_in_ert(document.body[i][21:])
174         document.body[i:end + 1] = subst
175       i = i + 1
176
177
178 def convert_japanese_encodings(document):
179     " Rename the japanese encodings to names understood by platex "
180     jap_enc_dict = {
181         "EUC-JP-pLaTeX": "euc",
182         "JIS-pLaTeX":    "jis",
183         "SJIS-pLaTeX":   "sjis"
184     }
185     i = find_token(document.header, "\\inputencoding" , 0)
186     if i == -1:
187         return
188     val = get_value(document.header, "\\inputencoding", i)
189     if val in jap_enc_dict.keys():
190         document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
191
192
193 def revert_japanese_encodings(document):
194     " Revert the japanese encodings name changes "
195     jap_enc_dict = {
196         "euc":  "EUC-JP-pLaTeX",
197         "jis":  "JIS-pLaTeX",
198         "sjis": "SJIS-pLaTeX"
199     }
200     i = find_token(document.header, "\\inputencoding" , 0)
201     if i == -1:
202         return
203     val = get_value(document.header, "\\inputencoding", i)
204     if val in jap_enc_dict.keys():
205         document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
206
207
208 def revert_justification(document):
209     " Revert the \\justification buffer param"
210     if not del_token(document.header, '\\justification', 0):
211         document.warning("Malformed LyX document: Missing \\justification.")
212
213
214 def revert_australian(document):
215     "Set English language variants Australian and Newzealand to English" 
216
217     if document.language == "australian" or document.language == "newzealand": 
218         document.language = "english"
219         i = find_token(document.header, "\\language", 0) 
220         if i != -1: 
221             document.header[i] = "\\language english" 
222     j = 0 
223     while True: 
224         j = find_token(document.body, "\\lang australian", j) 
225         if j == -1:
226             j = find_token(document.body, "\\lang newzealand", 0)
227             if j == -1:
228                 return
229             else:
230                 document.body[j] = document.body[j].replace("\\lang newzealand", "\\lang english")
231         else:
232             document.body[j] = document.body[j].replace("\\lang australian", "\\lang english") 
233         j += 1
234
235
236 def convert_biblio_style(document):
237     "Add a sensible default for \\biblio_style based on the citation engine."
238     i = find_token(document.header, "\\cite_engine", 0)
239     if i != -1:
240         engine = get_value(document.header, "\\cite_engine", i).split("_")[0]
241         style = {"basic": "plain", "natbib": "plainnat", "jurabib": "jurabib"}
242         document.header.insert(i + 1, "\\biblio_style " + style[engine])
243
244
245 def revert_biblio_style(document):
246     "BibTeX insets with default option use the style defined by \\biblio_style."
247     i = find_token(document.header, "\\biblio_style" , 0)
248     if i == -1:
249         document.warning("No \\biblio_style line. Nothing to do.")
250         return
251
252     default_style = get_value(document.header, "\\biblio_style", i)
253     del document.header[i]
254
255     # We are looking for bibtex insets having the default option
256     i = 0
257     while True:
258         i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
259         if i == -1:
260             return
261         j = find_end_of_inset(document.body, i)
262         if j == -1:
263             document.warning("Malformed LyX document: Can't find end of bibtex inset at line " + str(i))
264             i += 1
265             return
266         k = find_token(document.body, "options", i, j)
267         if k != -1:
268             options = get_quoted_value(document.body, "options", k)
269             if "default" in options.split(","):
270                 document.body[k] = 'options "%s"' \
271                     % options.replace("default", default_style)
272         i = j
273
274
275 def handle_longtable_captions(document, forward):
276     begin_table = 0
277     while True:
278         begin_table = find_token(document.body, '<lyxtabular version=', begin_table)
279         if begin_table == -1:
280             break
281         end_table = find_end_of(document.body, begin_table, '<lyxtabular', '</lyxtabular>')
282         if end_table == -1:
283             document.warning("Malformed LyX document: Could not find end of table.")
284             begin_table += 1
285             continue
286         fline = find_token(document.body, "<features", begin_table, end_table)
287         if fline == -1:
288             document.warning("Can't find features for inset at line " + str(begin_table))
289             begin_table += 1
290             continue
291         p = document.body[fline].find("islongtable")
292         if p == -1:
293             # no longtable
294             begin_table += 1
295             continue
296         numrows = get_option_value(document.body[begin_table], "rows")
297         try:
298             numrows = int(numrows)
299         except:
300             document.warning(document.body[begin_table])
301             document.warning("Unable to determine rows!")
302             begin_table = end_table
303             continue
304         begin_row = begin_table
305         for row in range(numrows):
306             begin_row = find_token(document.body, '<row', begin_row, end_table)
307             if begin_row == -1:
308                 document.warning("Can't find row " + str(row + 1))
309                 break
310             end_row = find_end_of(document.body, begin_row, '<row', '</row>')
311             if end_row == -1:
312                 document.warning("Can't find end of row " + str(row + 1))
313                 break
314             if forward:
315                 if (get_option_value(document.body[begin_row], 'caption') == 'true' and
316                     get_option_value(document.body[begin_row], 'endfirsthead') != 'true' and
317                     get_option_value(document.body[begin_row], 'endhead') != 'true' and
318                     get_option_value(document.body[begin_row], 'endfoot') != 'true' and
319                     get_option_value(document.body[begin_row], 'endlastfoot') != 'true'):
320                     document.body[begin_row] = set_option_value(document.body[begin_row], 'caption', 'true", endfirsthead="true')
321             elif get_option_value(document.body[begin_row], 'caption') == 'true':
322                 if get_option_value(document.body[begin_row], 'endfirsthead') == 'true':
323                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endfirsthead', 'false')
324                 if get_option_value(document.body[begin_row], 'endhead') == 'true':
325                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endhead', 'false')
326                 if get_option_value(document.body[begin_row], 'endfoot') == 'true':
327                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endfoot', 'false')
328                 if get_option_value(document.body[begin_row], 'endlastfoot') == 'true':
329                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endlastfoot', 'false')
330             begin_row = end_row
331         # since there could be a tabular inside this one, we 
332         # cannot jump to end.
333         begin_table += 1
334
335
336 def convert_longtable_captions(document):
337     "Add a firsthead flag to caption rows"
338     handle_longtable_captions(document, True)
339
340
341 def revert_longtable_captions(document):
342     "remove head/foot flag from caption rows"
343     handle_longtable_captions(document, False)
344
345
346 def convert_use_packages(document):
347     "use_xxx yyy => use_package xxx yyy"
348     packages = ["amsmath", "esint", "mathdots", "mhchem", "undertilde"]
349     for p in packages:
350         i = find_token(document.header, "\\use_%s" % p, 0)
351         if i != -1:
352             value = get_value(document.header, "\\use_%s" % p, i)
353             document.header[i] = "\\use_package %s %s" % (p, value)
354
355
356 def revert_use_packages(document):
357     "use_package xxx yyy => use_xxx yyy"
358     packages = ["amsmath", "esint", "mathdots", "mhchem", "undertilde"]
359     # the order is arbitrary for the use_package version, and not all packages need to be given.
360     # Ensure a complete list and correct order (important for older LyX versions and especially lyx2lyx)
361     j = 0
362     for p in packages:
363         regexp = re.compile(r'(\\use_package\s+%s)' % p)
364         i = find_re(document.header, regexp, j)
365         if i != -1:
366             value = get_value(document.header, "\\use_package %s" % p, i).split()[1]
367             del document.header[i]
368             j = i
369             document.header.insert(j, "\\use_%s %s"  % (p, value))
370         j = j + 1
371
372
373 def convert_use_package(document, pkg):
374     i = find_token(document.header, "\\use_package", 0)
375     if i == -1:
376         document.warning("Malformed LyX document: Can't find \\use_package.")
377         return;
378     j = find_token(document.preamble, "\\usepackage{" + pkg + "}", 0)
379     if j == -1:
380         document.header.insert(i + 1, "\\use_package " + pkg + " 0")
381     else:
382         document.header.insert(i + 1, "\\use_package " + pkg + " 2")
383         del document.preamble[j]
384
385
386 def revert_use_package(document, pkg, commands, oldauto):
387     # oldauto defines how the version we are reverting to behaves:
388     # if it is true, the old version uses the package automatically.
389     # if it is false, the old version never uses the package.
390     regexp = re.compile(r'(\\use_package\s+%s)' % pkg)
391     i = find_re(document.header, regexp, 0)
392     value = "1" # default is auto
393     if i != -1:
394         value = get_value(document.header, "\\use_package" , i).split()[1]
395         del document.header[i]
396     if value == "2": # on
397         add_to_preamble(document, ["\\usepackage{" + pkg + "}"])
398     elif value == "1" and not oldauto: # auto
399         i = 0
400         while True:
401             i = find_token(document.body, '\\begin_inset Formula', i)
402             if i == -1:
403                 return
404             j = find_end_of_inset(document.body, i)
405             if j == -1:
406                 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
407                 i += 1
408                 continue
409             code = "\n".join(document.body[i:j])
410             for c in commands:
411                 if code.find("\\%s" % c) != -1:
412                     add_to_preamble(document, ["\\usepackage{" + pkg + "}"])
413                     return
414             i = j
415
416
417 def convert_use_mathtools(document):
418     "insert use_package mathtools"
419     convert_use_package(document, "mathtools")
420
421
422 def revert_use_mathtools(document):
423     "remove use_package mathtools"
424     commands = ["mathclap", "mathllap", "mathrlap", \
425                 "lgathered", "rgathered", "vcentcolon", "dblcolon", \
426                 "coloneqq", "Coloneqq", "coloneq", "Coloneq", "eqqcolon", \
427                 "Eqqcolon", "eqcolon", "Eqcolon", "colonapprox", \
428                 "Colonapprox", "colonsim", "Colonsim"]
429     revert_use_package(document, "mathtools", commands, False)
430
431
432 def convert_use_stmaryrd(document):
433     "insert use_package stmaryrd"
434     convert_use_package(document, "stmaryrd")
435
436
437 def revert_use_stmaryrd(document):
438     "remove use_package stmaryrd"
439     # commands provided by stmaryrd.sty but LyX uses other packages:
440     # boxdot lightning, bigtriangledown, bigtriangleup
441     commands = ["shortleftarrow", "shortrightarrow", "shortuparrow", \
442                     "shortdownarrow", "Yup", "Ydown", "Yleft", "Yright", \
443                     "varcurlyvee", "varcurlywedge", "minuso", "baro", \
444                     "sslash", "bbslash", "moo", "varotimes", "varoast", \
445                     "varobar", "varodot", "varoslash", "varobslash", \
446                     "varocircle", "varoplus", "varominus", "boxast", \
447                     "boxbar", "boxslash", "boxbslash", "boxcircle", \
448                     "boxbox", "boxempty", "merge", "vartimes", \
449                     "fatsemi", "sswarrow", "ssearrow", "curlywedgeuparrow", \
450                     "curlywedgedownarrow", "fatslash", "fatbslash", "lbag", \
451                     "rbag", "varbigcirc", "leftrightarroweq", \
452                     "curlyveedownarrow", "curlyveeuparrow", "nnwarrow", \
453                     "nnearrow", "leftslice", "rightslice", "varolessthan", \
454                     "varogreaterthan", "varovee", "varowedge", "talloblong", \
455                     "interleave", "obar", "obslash", "olessthan", \
456                     "ogreaterthan", "ovee", "owedge", "oblong", "inplus", \
457                     "niplus", "nplus", "subsetplus", "supsetplus", \
458                     "subsetpluseq", "supsetpluseq", "Lbag", "Rbag", \
459                     "llbracket", "rrbracket", "llparenthesis", \
460                     "rrparenthesis", "binampersand", "bindnasrepma", \
461                     "trianglelefteqslant", "trianglerighteqslant", \
462                     "ntrianglelefteqslant", "ntrianglerighteqslant", \
463                     "llfloor", "rrfloor", "llceil", "rrceil", "arrownot", \
464                     "Arrownot", "Mapstochar", "mapsfromchar", "Mapsfromchar", \
465                     "leftrightarrowtriangle", "leftarrowtriangle", \
466                     "rightarrowtriangle", \
467                     "bigcurlyvee", "bigcurlywedge", "bigsqcap", "bigbox", \
468                     "bigparallel", "biginterleave", "bignplus", \
469                     "varcopyright", "longarrownot", "Longarrownot", \
470                     "Mapsto", "mapsfrom", "Mapsfrom" "Longmapsto", \
471                     "longmapsfrom", "Longmapsfrom"]
472     revert_use_package(document, "stmaryrd", commands, False)
473
474
475
476 def convert_use_stackrel(document):
477     "insert use_package stackrel"
478     convert_use_package(document, "stackrel")
479
480
481 def revert_use_stackrel(document):
482     "remove use_package stackrel"
483     commands = ["stackrel"]
484     revert_use_package(document, "stackrel", commands, False)
485
486
487 def convert_cite_engine_type(document):
488     "Determine the \\cite_engine_type from the citation engine."
489     i = find_token(document.header, "\\cite_engine", 0)
490     if i == -1:
491         return
492     engine = get_value(document.header, "\\cite_engine", i)
493     if "_" in engine:
494         engine, type = engine.split("_")
495     else:
496         type = {"basic": "numerical", "jurabib": "authoryear"}[engine]
497     document.header[i] = "\\cite_engine " + engine
498     document.header.insert(i + 1, "\\cite_engine_type " + type)
499
500
501 def revert_cite_engine_type(document):
502     "Natbib had the type appended with an underscore."
503     engine_type = "numerical"
504     i = find_token(document.header, "\\cite_engine_type" , 0)
505     if i == -1:
506         document.warning("No \\cite_engine_type line. Assuming numerical.")
507     else:
508         engine_type = get_value(document.header, "\\cite_engine_type", i)
509         del document.header[i]
510
511     # We are looking for the natbib citation engine
512     i = find_token(document.header, "\\cite_engine natbib", 0)
513     if i == -1:
514         return
515     document.header[i] = "\\cite_engine natbib_" + engine_type
516
517
518 def convert_cite_engine_type_default(document):
519     "Convert \\cite_engine_type to default for the basic citation engine."
520     i = find_token(document.header, "\\cite_engine basic", 0)
521     if i == -1:
522         return
523     i = find_token(document.header, "\\cite_engine_type" , 0)
524     if i == -1:
525         return
526     document.header[i] = "\\cite_engine_type default"
527
528
529 def revert_cite_engine_type_default(document):
530     """Revert \\cite_engine_type default.
531
532     Revert to numerical for the basic cite engine, otherwise to authoryear."""
533     engine_type = "authoryear"
534     i = find_token(document.header, "\\cite_engine_type default" , 0)
535     if i == -1:
536         return
537     j = find_token(document.header, "\\cite_engine basic", 0)
538     if j != -1:
539         engine_type = "numerical"
540     document.header[i] = "\\cite_engine_type " + engine_type
541
542
543 # this is the same, as revert_use_cancel() except for the default
544 def revert_cancel(document):
545     "add cancel to the preamble if necessary"
546     commands = ["cancelto", "cancel", "bcancel", "xcancel"]
547     revert_use_package(document, "cancel", commands, False)
548
549
550 def revert_verbatim(document):
551     " Revert verbatim einvironments completely to TeX-code. "
552     i = 0
553     consecutive = False
554     subst_end = ['\end_layout', '', '\\begin_layout Plain Layout',
555                  '\end_layout', '',
556                  '\\begin_layout Plain Layout', '', '',
557                  '\\backslash', '',
558                  'end{verbatim}',
559                  '\\end_layout', '', '\\end_inset',
560                  '', '', '\\end_layout']
561     subst_begin = ['\\begin_layout Standard', '\\noindent',
562                    '\\begin_inset ERT', 'status collapsed', '',
563                    '\\begin_layout Plain Layout', '', '', '\\backslash',
564                    'begin{verbatim}',
565                    '\\end_layout', '', '\\begin_layout Plain Layout', '']
566     while 1:
567         i = find_token(document.body, "\\begin_layout Verbatim", i)
568         if i == -1:
569             return
570         j = find_end_of_layout(document.body, i)
571         if j == -1:
572             document.warning("Malformed LyX document: Can't find end of Verbatim layout")
573             i += 1
574             continue
575         # delete all line breaks insets (there are no other insets)
576         l = i
577         while 1:
578             n = find_token(document.body, "\\begin_inset Newline newline", l)
579             if n == -1:
580                 n = find_token(document.body, "\\begin_inset Newline linebreak", l)
581                 if n == -1:
582                     break
583             m = find_end_of_inset(document.body, n)
584             del(document.body[m:m+1])
585             document.body[n:n+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
586             l += 1
587             j += 1
588         # consecutive verbatim environments need to be connected
589         k = find_token(document.body, "\\begin_layout Verbatim", j)
590         if k == j + 2 and consecutive == False:
591             consecutive = True
592             document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
593             document.body[i:i+1] = subst_begin
594             continue
595         if k == j + 2 and consecutive == True:
596             document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
597             del(document.body[i:i+1])
598             continue
599         if k != j + 2 and consecutive == True:
600             document.body[j:j+1] = subst_end
601             # the next paragraph must not be indented
602             document.body[j+19:j+19] = ['\\noindent']
603             del(document.body[i:i+1])
604             consecutive = False
605             continue
606         else:
607             document.body[j:j+1] = subst_end
608             # the next paragraph must not be indented
609             document.body[j+19:j+19] = ['\\noindent']
610             document.body[i:i+1] = subst_begin
611
612
613 def revert_tipa(document):
614     " Revert native TIPA insets to mathed or ERT. "
615     i = 0
616     while 1:
617         i = find_token(document.body, "\\begin_inset IPA", i)
618         if i == -1:
619             return
620         j = find_end_of_inset(document.body, i)
621         if j == -1:
622             document.warning("Malformed LyX document: Can't find end of IPA inset")
623             i += 1
624             continue
625         Multipar = False
626         n = find_token(document.body, "\\begin_layout", i, j)
627         if n == -1:
628             document.warning("Malformed LyX document: IPA inset has no embedded layout")
629             i += 1
630             continue
631         m = find_end_of_layout(document.body, n)
632         if m == -1:
633             document.warning("Malformed LyX document: Can't find end of embedded layout")
634             i += 1
635             continue
636         content = document.body[n+1:m]
637         p = find_token(document.body, "\\begin_layout", m, j)
638         if p != -1 or len(content) > 1:
639             Multipar = True
640             content = document.body[i+1:j]
641         if Multipar:
642             # IPA insets with multiple pars need to be wrapped by \begin{IPA}...\end{IPA}
643             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}")
644             add_to_preamble(document, ["\\usepackage{tipa,tipx}"])
645         else:
646             # single-par IPA insets can be reverted to mathed
647             document.body[i:j+1] = ["\\begin_inset Formula $\\text{\\textipa{" + content[0] + "}}$", "\\end_inset"]
648         i = j
649
650
651 def revert_cell_rotation(document):
652   "Revert cell rotations to TeX-code"
653
654   load_rotating = False
655   i = 0
656   try:
657     while True:
658       # first, let's find out if we need to do anything
659       i = find_token(document.body, '<cell ', i)
660       if i == -1:
661         return
662       j = document.body[i].find('rotate="')
663       if j != -1:
664         k = document.body[i].find('"', j + 8)
665         value = document.body[i][j + 8 : k]
666         if value == "0":
667           rgx = re.compile(r' rotate="[^"]+?"')
668           # remove rotate option
669           document.body[i] = rgx.sub('', document.body[i])
670         elif value == "90":
671           rgx = re.compile(r' rotate="[^"]+?"')
672           document.body[i] = rgx.sub('rotate="true"', document.body[i])
673         else:
674           rgx = re.compile(r' rotate="[^"]+?"')
675           load_rotating = True
676           # remove rotate option
677           document.body[i] = rgx.sub('', document.body[i])
678           # write ERT
679           document.body[i + 5 : i + 5] = \
680             put_cmd_in_ert("\\end{turn}")
681           document.body[i + 4 : i + 4] = \
682             put_cmd_in_ert("\\begin{turn}{" + value + "}")
683         
684       i += 1
685         
686   finally:
687     if load_rotating:
688       add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
689
690
691 def convert_cell_rotation(document):
692     'Convert cell rotation statements from "true" to "90"'
693
694     i = 0
695     while True:
696       # first, let's find out if we need to do anything
697       i = find_token(document.body, '<cell ', i)
698       if i == -1:
699         return
700       j = document.body[i].find('rotate="true"')
701       if j != -1:
702         rgx = re.compile(r'rotate="[^"]+?"')
703         # convert "true" to "90"
704         document.body[i] = rgx.sub('rotate="90"', document.body[i])
705         
706       i += 1
707
708
709 def revert_table_rotation(document):
710   "Revert table rotations to TeX-code"
711
712   load_rotating = False
713   i = 0
714   try:
715     while True:
716       # first, let's find out if we need to do anything
717       i = find_token(document.body, '<features ', i)
718       if i == -1:
719         return
720       j = document.body[i].find('rotate="')
721       if j != -1:
722         end_table = find_token(document.body, '</lyxtabular>', j)
723         k = document.body[i].find('"', j + 8)
724         value = document.body[i][j + 8 : k]
725         if value == "0":
726           rgx = re.compile(r' rotate="[^"]+?"')
727           # remove rotate option
728           document.body[i] = rgx.sub('', document.body[i])
729         elif value == "90":
730           rgx = re.compile(r'rotate="[^"]+?"')
731           document.body[i] = rgx.sub('rotate="true"', document.body[i])
732         else:
733           rgx = re.compile(r' rotate="[^"]+?"')
734           load_rotating = True
735           # remove rotate option
736           document.body[i] = rgx.sub('', document.body[i])
737           # write ERT
738           document.body[end_table + 3 : end_table + 3] = \
739             put_cmd_in_ert("\\end{turn}")
740           document.body[i - 2 : i - 2] = \
741             put_cmd_in_ert("\\begin{turn}{" + value + "}")
742         
743       i += 1
744         
745   finally:
746     if load_rotating:
747       add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
748
749
750 def convert_table_rotation(document):
751     'Convert table rotation statements from "true" to "90"'
752
753     i = 0
754     while True:
755       # first, let's find out if we need to do anything
756       i = find_token(document.body, '<features ', i)
757       if i == -1:
758         return
759       j = document.body[i].find('rotate="true"')
760       if j != -1:
761         rgx = re.compile(r'rotate="[^"]+?"')
762         # convert "true" to "90"
763         document.body[i] = rgx.sub('rotate="90"', document.body[i])
764         
765       i += 1
766
767
768 def convert_listoflistings(document):
769     'Convert ERT \lstlistoflistings to TOC lstlistoflistings inset'
770     # We can support roundtrip because the command is so simple
771     i = 0
772     while True:
773         i = find_token(document.body, "\\begin_inset ERT", i)
774         if i == -1:
775             return
776         j = find_end_of_inset(document.body, i)
777         if j == -1:
778             document.warning("Malformed LyX document: Can't find end of ERT inset")
779             i += 1
780             continue
781         ert = get_ert(document.body, i)
782         if ert == "\\lstlistoflistings{}":
783             document.body[i:j] = ["\\begin_inset CommandInset toc", "LatexCommand lstlistoflistings", ""]
784             i = i + 4
785         else:
786             i = j + 1
787
788
789 def revert_listoflistings(document):
790     'Convert TOC lstlistoflistings inset to ERT lstlistoflistings'
791     i = 0
792     while True:
793         i = find_token(document.body, "\\begin_inset CommandInset toc", i)
794         if i == -1:
795             return
796         if document.body[i+1] == "LatexCommand lstlistoflistings":
797             j = find_end_of_inset(document.body, i)
798             if j == -1:
799                 document.warning("Malformed LyX document: Can't find end of TOC inset")
800                 i += 1
801                 continue
802             subst = put_cmd_in_ert("\\lstlistoflistings{}")
803             document.body[i:j+1] = subst
804             add_to_preamble(document, ["\\usepackage{listings}"])
805         i = i + 1
806
807
808 def convert_use_amssymb(document):
809     "insert use_package amssymb"
810     regexp = re.compile(r'(\\use_package\s+amsmath)')
811     i = find_re(document.header, regexp, 0)
812     if i == -1:
813         document.warning("Malformed LyX document: Can't find \\use_package amsmath.")
814         return;
815     value = get_value(document.header, "\\use_package" , i).split()[1]
816     useamsmath = 0
817     try:
818         useamsmath = int(value)
819     except:
820         document.warning("Invalid \\use_package amsmath: " + value + ". Assuming auto.")
821         useamsmath = 1
822     j = find_token(document.preamble, "\\usepackage{amssymb}", 0)
823     if j == -1:
824         document.header.insert(i + 1, "\\use_package amssymb %d" % useamsmath)
825     else:
826         document.header.insert(i + 1, "\\use_package amssymb 2")
827         del document.preamble[j]
828
829
830 def revert_use_amssymb(document):
831     "remove use_package amssymb"
832     regexp1 = re.compile(r'(\\use_package\s+amsmath)')
833     regexp2 = re.compile(r'(\\use_package\s+amssymb)')
834     i = find_re(document.header, regexp1, 0)
835     j = find_re(document.header, regexp2, 0)
836     value1 = "1" # default is auto
837     value2 = "1" # default is auto
838     if i != -1:
839         value1 = get_value(document.header, "\\use_package" , i).split()[1]
840     if j != -1:
841         value2 = get_value(document.header, "\\use_package" , j).split()[1]
842         del document.header[j]
843     if value1 != value2 and value2 == "2": # on
844         add_to_preamble(document, ["\\usepackage{amssymb}"])
845
846
847 def convert_use_cancel(document):
848     "insert use_package cancel"
849     convert_use_package(document, "cancel")
850
851
852 def revert_use_cancel(document):
853     "remove use_package cancel"
854     commands = ["cancel", "bcancel", "xcancel", "cancelto"]
855     revert_use_package(document, "cancel", commands, True)
856
857
858 def revert_ancientgreek(document):
859     "Set the document language for ancientgreek to greek" 
860
861     if document.language == "ancientgreek": 
862         document.language = "greek"
863         i = find_token(document.header, "\\language", 0) 
864         if i != -1: 
865             document.header[i] = "\\language greek" 
866     j = 0 
867     while True: 
868         j = find_token(document.body, "\\lang ancientgreek", j) 
869         if j == -1:
870             return
871         else:
872             document.body[j] = document.body[j].replace("\\lang ancientgreek", "\\lang greek") 
873         j += 1
874
875
876 def revert_languages(document):
877     "Set the document language for new supported languages to English" 
878
879     languages = [
880                  "coptic", "divehi", "hindi", "kurmanji", "lao", "marathi", "occitan", "sanskrit",
881                  "syriac", "tamil", "telugu", "urdu"
882                 ]
883     for n in range(len(languages)):
884         if document.language == languages[n]:
885             document.language = "english"
886             i = find_token(document.header, "\\language", 0) 
887             if i != -1: 
888                 document.header[i] = "\\language english" 
889         j = 0
890         while j < len(document.body): 
891             j = find_token(document.body, "\\lang " + languages[n], j)
892             if j != -1:
893                 document.body[j] = document.body[j].replace("\\lang " + languages[n], "\\lang english")
894                 j += 1
895             else:
896                 j = len(document.body)
897
898
899 def convert_armenian(document):
900     "Use polyglossia and thus non-TeX fonts for Armenian" 
901
902     if document.language == "armenian": 
903         i = find_token(document.header, "\\use_non_tex_fonts", 0) 
904         if i != -1: 
905             document.header[i] = "\\use_non_tex_fonts true" 
906
907
908 def revert_armenian(document):
909     "Use ArmTeX and thus TeX fonts for Armenian" 
910
911     if document.language == "armenian": 
912         i = find_token(document.header, "\\use_non_tex_fonts", 0) 
913         if i != -1: 
914             document.header[i] = "\\use_non_tex_fonts false" 
915
916
917 def revert_libertine(document):
918     " Revert native libertine font definition to LaTeX " 
919
920     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
921         i = find_token(document.header, "\\font_roman libertine", 0)
922         if i != -1:
923             osf = False
924             j = find_token(document.header, "\\font_osf true", 0)
925             if j != -1:
926                 osf = True
927             preamble = "\\usepackage"
928             if osf:
929                 document.header[j] = "\\font_osf false"
930                 preamble += "[osf]"
931             else:
932                 preamble += "[lining]"
933             preamble += "{libertine-type1}"
934             add_to_preamble(document, [preamble])
935             document.header[i] = "\\font_roman default"
936
937
938 def revert_txtt(document):
939     " Revert native txtt font definition to LaTeX " 
940
941     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
942         i = find_token(document.header, "\\font_typewriter txtt", 0)
943         if i != -1:
944             preamble = "\\renewcommand{\\ttdefault}{txtt}"
945             add_to_preamble(document, [preamble])
946             document.header[i] = "\\font_typewriter default"
947
948
949 def revert_mathdesign(document):
950     " Revert native mathdesign font definition to LaTeX " 
951
952     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
953         mathdesign_dict = {
954         "mdbch":  "charter",
955         "mdput":  "utopia",
956         "mdugm":  "garamond"
957         }
958         i = find_token(document.header, "\\font_roman", 0)
959         if i == -1:
960             return
961         val = get_value(document.header, "\\font_roman", i)
962         if val in mathdesign_dict.keys():
963             preamble = "\\usepackage[%s" % mathdesign_dict[val]
964             expert = False
965             j = find_token(document.header, "\\font_osf true", 0)
966             if j != -1:
967                 expert = True
968                 document.header[j] = "\\font_osf false"
969             l = find_token(document.header, "\\font_sc true", 0)
970             if l != -1:
971                 expert = True
972                 document.header[l] = "\\font_sc false"
973             if expert:
974                 preamble += ",expert"
975             preamble += "]{mathdesign}"
976             add_to_preamble(document, [preamble])
977             document.header[i] = "\\font_roman default"
978
979
980 def revert_texgyre(document):
981     " Revert native TeXGyre font definition to LaTeX " 
982
983     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
984         texgyre_fonts = ["tgadventor", "tgbonum", "tgchorus", "tgcursor", \
985                          "tgheros", "tgpagella", "tgschola", "tgtermes"]
986         i = find_token(document.header, "\\font_roman", 0)
987         if i != -1:
988             val = get_value(document.header, "\\font_roman", i)
989             if val in texgyre_fonts:
990                 preamble = "\\usepackage{%s}" % val
991                 add_to_preamble(document, [preamble])
992                 document.header[i] = "\\font_roman default"
993         i = find_token(document.header, "\\font_sans", 0)
994         if i != -1:
995             val = get_value(document.header, "\\font_sans", i)
996             if val in texgyre_fonts:
997                 preamble = "\\usepackage{%s}" % val
998                 add_to_preamble(document, [preamble])
999                 document.header[i] = "\\font_sans default"
1000         i = find_token(document.header, "\\font_typewriter", 0)
1001         if i != -1:
1002             val = get_value(document.header, "\\font_typewriter", i)
1003             if val in texgyre_fonts:
1004                 preamble = "\\usepackage{%s}" % val
1005                 add_to_preamble(document, [preamble])
1006                 document.header[i] = "\\font_typewriter default"
1007
1008
1009 def revert_ipadeco(document):
1010     " Revert IPA decorations to ERT "
1011     i = 0
1012     while True:
1013       i = find_token(document.body, "\\begin_inset IPADeco", i)
1014       if i == -1:
1015           return
1016       end = find_end_of_inset(document.body, i)
1017       if end == -1:
1018           document.warning("Can't find end of inset at line " + str(i))
1019           i += 1
1020           continue
1021       line = document.body[i]
1022       rx = re.compile(r'\\begin_inset IPADeco (.*)$')
1023       m = rx.match(line)
1024       decotype = m.group(1)
1025       if decotype != "toptiebar" and decotype != "bottomtiebar":
1026           document.warning("Invalid IPADeco type: " + decotype)
1027           i = end
1028           continue
1029       blay = find_token(document.body, "\\begin_layout Plain Layout", i, end)
1030       if blay == -1:
1031           document.warning("Can't find layout for inset at line " + str(i))
1032           i = end
1033           continue
1034       bend = find_end_of_layout(document.body, blay)
1035       if bend == -1:
1036           document.warning("Malformed LyX document: Could not find end of IPADeco inset's layout.")
1037           i = end
1038           continue
1039       substi = ["\\begin_inset ERT", "status collapsed", "",
1040                 "\\begin_layout Plain Layout", "", "", "\\backslash", 
1041                 decotype + "{", "\\end_layout", "", "\\end_inset"]
1042       substj = ["\\size default", "", "\\begin_inset ERT", "status collapsed", "",
1043                 "\\begin_layout Plain Layout", "", "}", "\\end_layout", "", "\\end_inset"]
1044       # do the later one first so as not to mess up the numbering
1045       document.body[bend:end + 1] = substj
1046       document.body[i:blay + 1] = substi
1047       i = end + len(substi) + len(substj) - (end - bend) - (blay - i) - 2
1048       add_to_preamble(document, "\\usepackage{tipa}")
1049
1050
1051 def revert_ipachar(document):
1052     ' Revert \\IPAChar to ERT '
1053     i = 0
1054     found = False
1055     while i < len(document.body):
1056         m = re.match(r'(.*)\\IPAChar \\(\w+\{\w+\})(.*)', document.body[i])
1057         if m:
1058             found = True
1059             before = m.group(1)
1060             ipachar = m.group(2)
1061             after = m.group(3)
1062             subst = [before,
1063                      '\\begin_inset ERT',
1064                      'status collapsed', '',
1065                      '\\begin_layout Standard',
1066                      '', '', '\\backslash',
1067                      ipachar,
1068                      '\\end_layout', '',
1069                      '\\end_inset', '',
1070                      after]
1071             document.body[i: i+1] = subst
1072             i = i + len(subst)
1073         else:
1074             i = i + 1
1075     if found:
1076         add_to_preamble(document, "\\usepackage{tone}")
1077
1078
1079 def revert_minionpro(document):
1080     " Revert native MinionPro font definition to LaTeX " 
1081
1082     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1083         i = find_token(document.header, "\\font_roman minionpro", 0)
1084         if i != -1:
1085             osf = False
1086             j = find_token(document.header, "\\font_osf true", 0)
1087             if j != -1:
1088                 osf = True
1089             preamble = "\\usepackage"
1090             if osf:
1091                 document.header[j] = "\\font_osf false"
1092             else:
1093                 preamble += "[lf]"
1094             preamble += "{MinionPro}"
1095             add_to_preamble(document, [preamble])
1096             document.header[i] = "\\font_roman default"
1097
1098
1099 def revert_mathfonts(document):
1100     " Revert native math font definitions to LaTeX " 
1101
1102     i = find_token(document.header, "\\font_math", 0)
1103     if i == -1:
1104        return
1105     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1106         val = get_value(document.header, "\\font_math", i)
1107         if val == "eulervm":
1108             add_to_preamble(document, "\\usepackage{eulervm}")
1109         elif val == "default":
1110             mathfont_dict = {
1111             "lmodern":  "\\renewcommand{\\rmdefault}{lmr}",
1112             "minionpro":  "\\usepackage[onlytext,lf]{MinionPro}",
1113             "minionpro-osf":  "\\usepackage[onlytext]{MinionPro}",
1114             "palatino":  "\\renewcommand{\\rmdefault}{ppl}",
1115             "palatino-osf":  "\\renewcommand{\\rmdefault}{pplj}",
1116             "times":  "\\renewcommand{\\rmdefault}{ptm}",
1117             "utopia":  "\\renewcommand{\\rmdefault}{futs}",
1118             "utopia-osf":  "\\renewcommand{\\rmdefault}{futj}",
1119             }
1120             j = find_token(document.header, "\\font_roman", 0)
1121             if j != -1:
1122                 rm = get_value(document.header, "\\font_roman", j)
1123                 k = find_token(document.header, "\\font_osf true", 0)
1124                 if k != -1:
1125                     rm += "-osf"
1126                 if rm in mathfont_dict.keys():
1127                     add_to_preamble(document, mathfont_dict[rm])
1128                     document.header[j] = "\\font_roman default"
1129                     if k != -1:
1130                         document.header[k] = "\\font_osf false"
1131     del document.header[i]
1132
1133
1134 def revert_mdnomath(document):
1135     " Revert mathdesign and fourier without math " 
1136
1137     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1138         mathdesign_dict = {
1139         "md-charter": "mdbch",
1140         "md-utopia": "mdput",
1141         "md-garamond": "mdugm"
1142         }
1143         i = find_token(document.header, "\\font_roman", 0)
1144         if i == -1:
1145             return
1146         val = get_value(document.header, "\\font_roman", i)
1147         if val in mathdesign_dict.keys():
1148             j = find_token(document.header, "\\font_math", 0)
1149             if j == -1:
1150                 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1151             mval = get_value(document.header, "\\font_math", j)
1152             if mval == "default":
1153                 document.header[i] = "\\font_roman default"
1154                 add_to_preamble(document, "\\renewcommand{\\rmdefault}{%s}" % mathdesign_dict[val])
1155             else:
1156                 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1157
1158
1159 def convert_mdnomath(document):
1160     " Change mathdesign font name " 
1161
1162     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1163         mathdesign_dict = {
1164         "mdbch":  "md-charter",
1165         "mdput":  "md-utopia",
1166         "mdugm":  "md-garamond"
1167         }
1168         i = find_token(document.header, "\\font_roman", 0)
1169         if i == -1:
1170             return
1171         val = get_value(document.header, "\\font_roman", i)
1172         if val in mathdesign_dict.keys():
1173              document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1174
1175
1176 def revert_newtxmath(document):
1177     " Revert native newtxmath definitions to LaTeX " 
1178
1179     i = find_token(document.header, "\\font_math", 0)
1180     if i == -1:
1181        return
1182     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1183         val = get_value(document.header, "\\font_math", i)
1184         mathfont_dict = {
1185         "libertine-ntxm":  "\\usepackage[libertine]{newtxmath}",
1186         "minion-ntxm":  "\\usepackage[minion]{newtxmath}",
1187         "newtxmath":  "\\usepackage{newtxmath}",
1188         }
1189         if val in mathfont_dict.keys():
1190             add_to_preamble(document, mathfont_dict[val])
1191             document.header[i] = "\\font_math auto"
1192
1193
1194 def revert_biolinum(document):
1195     " Revert native biolinum font definition to LaTeX " 
1196
1197     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1198         i = find_token(document.header, "\\font_sans biolinum", 0)
1199         if i != -1:
1200             osf = False
1201             j = find_token(document.header, "\\font_osf true", 0)
1202             if j != -1:
1203                 osf = True
1204             preamble = "\\usepackage"
1205             if not osf:
1206                 preamble += "[lf]"
1207             preamble += "{biolinum-type1}"
1208             add_to_preamble(document, [preamble])
1209             document.header[i] = "\\font_sans default"
1210
1211
1212 def revert_uop(document):
1213     " Revert native URW Classico (Optima) font definition to LaTeX "
1214
1215     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1216         i = find_token(document.header, "\\font_sans uop", 0)
1217         if i != -1:
1218                 preamble = "\\renewcommand{\\sfdefault}{uop}"
1219                 add_to_preamble(document, [preamble])
1220                 document.header[i] = "\\font_sans default"
1221
1222
1223 def convert_latexargs(document):
1224     " Convert InsetArgument to new syntax "
1225
1226     if find_token(document.body, "\\begin_inset Argument", 0) == -1:
1227         # nothing to do.
1228         return
1229
1230     # A list of layouts (document classes) with only optional or no arguments.
1231     # These can be safely converted to the new syntax
1232     # (I took the liberty to add some of my personal layouts/modules here; JSP)
1233     safe_layouts = ["aa", "aapaper", "aastex", "achemso", "acmsiggraph", "AEA",
1234                     "agu-dtd", "agums", "agutex", "amsart", "amsbook", "apa",
1235                     "arab-article", "armenian-article", "article-beamer", "article",
1236                     "beamer", "book", "broadway", "chess", "cl2emult", "ctex-article",
1237                     "ctex-book", "ctex-report", "dinbrief", "docbook-book", "docbook-chapter",
1238                     "docbook", "docbook-section", "doublecol-new", "dtk", "ectaart", "egs",
1239                     "elsarticle", "elsart", "entcs", "europecv", "extarticle", "extbook",
1240                     "extletter", "extreport", "foils", "frletter", "g-brief2", "g-brief",
1241                     "heb-article", "heb-letter", "hollywood", "IEEEtran", "ijmpc", "ijmpd",
1242                     "iopart", "isprs", "jarticle", "jasatex", "jbook", "jgrga", "jreport",
1243                     "jsarticle", "jsbeamer", "jsbook", "jss", "kluwer", "latex8", "letter", "lettre",
1244                     "literate-article", "literate-book", "literate-report", "llncs", "ltugboat",
1245                     "memoir", "moderncv", "mwart", "mwbk", "mwrep", "paper", "powerdot",
1246                     "recipebook", "report", "revtex4", "revtex", "scrartcl", "scrarticle-beamer",
1247                     "scrbook", "scrlettr", "scrlttr2", "scrreprt", "seminar", "siamltex",
1248                     "sigplanconf", "simplecv", "singlecol", "singlecol-new", "slides", "spie",
1249                     "svglobal3", "svglobal", "svjog", "svmono", "svmult", "svprobth", "tarticle",
1250                     "tbook", "treport", "tufte-book", "tufte-handout"]
1251     # A list of "safe" modules, same as above
1252     safe_modules = ["biblatex", "beameraddons", "beamersession", "braille", "customHeadersFooters",
1253                     "endnotes", "enumitem", "eqs-within-sections", "figs-within-sections", "fix-cm",
1254                     "fixltx2e", "foottoend", "hanging", "jscharstyles", "knitr", "lilypond",
1255                     "linguistics", "linguisticx", "logicalmkup", "minimalistic", "nomindex", "noweb",
1256                     "pdfcomment", "sweave", "tabs-within-sections", "theorems-ams-bytype",
1257                     "theorems-ams-extended-bytype", "theorems-ams-extended", "theorems-ams", "theorems-bytype",
1258                     "theorems-chap-bytype", "theorems-chap", "theorems-named", "theorems-sec-bytype",
1259                     "theorems-sec", "theorems-starred", "theorems-std", "todonotes"]
1260     # Modules we need to take care of
1261     caveat_modules = ["initials"]
1262     # information about the relevant styles in caveat_modules (number of opt and req args)
1263     # use this if we get more caveat_modules. For now, use hard coding (see below).
1264     # initials = [{'Layout' : 'Initial', 'opt' : 1, 'req' : 1}]
1265
1266     # Is this a known safe layout?
1267     safe_layout = document.textclass in safe_layouts
1268     if not safe_layout:
1269         document.warning("Lyx2lyx knows nothing about textclass '%s'. "
1270                          "Please check if short title insets have been converted correctly."
1271                          % document.textclass)
1272     # Do we use unsafe or unknown modules
1273     mods = document.get_module_list()
1274     unknown_modules = False
1275     used_caveat_modules = list()
1276     for mod in mods:
1277         if mod in safe_modules:
1278             continue
1279         if mod in caveat_modules:
1280             used_caveat_modules.append(mod)
1281             continue
1282         unknown_modules = True
1283         document.warning("Lyx2lyx knows nothing about module '%s'. "
1284                          "Please check if short title insets have been converted correctly."
1285                          % mod)
1286
1287     i = 0
1288     while True:
1289         i = find_token(document.body, "\\begin_inset Argument", i)
1290         if i == -1:
1291             return
1292
1293         if not safe_layout or unknown_modules:
1294             # We cannot do more here since we have no access to this layout.
1295             # InsetArgument itself will do the real work
1296             # (see InsetArgument::updateBuffer())
1297             document.body[i] = "\\begin_inset Argument 999"
1298             i = i + 1
1299             continue
1300         
1301         # Find containing paragraph layout
1302         parent = get_containing_layout(document.body, i)
1303         if parent == False:
1304             document.warning("Malformed LyX document: Can't find parent paragraph layout")
1305             i = i + 1
1306             continue
1307         parbeg = parent[1]
1308         parend = parent[2]
1309         allowed_opts = -1
1310         first_req = -1
1311         if len(used_caveat_modules) > 0:
1312             # We know for now that this must be the initials module with the Initial layout
1313             # If we get more such modules, we need some automating.
1314             if parent[0] == "Initial":
1315                 # Layout has 1 opt and 1 req arg.
1316                 # Count the actual arguments
1317                 actualargs = 0
1318                 for p in range(parbeg, parend):
1319                     if document.body[p] == "\\begin_inset Argument":
1320                         actualargs += 1
1321                 if actualargs == 1:
1322                     allowed_opts = 0
1323                     first_req = 2
1324         # Collect all arguments in this paragraph
1325         argnr = 0
1326         for p in range(parbeg, parend):
1327             if document.body[p] == "\\begin_inset Argument":
1328                 argnr += 1
1329                 if allowed_opts != -1:
1330                     # We have less arguments than opt + required.
1331                     # required must take precedence.
1332                     if argnr > allowed_opts and argnr < first_req:
1333                         argnr = first_req
1334                 document.body[p] = "\\begin_inset Argument %d" % argnr
1335         i = i + 1
1336
1337
1338 def revert_latexargs(document):
1339     " Revert InsetArgument to old syntax "
1340
1341     i = 0
1342     rx = re.compile(r'^\\begin_inset Argument (\d+)$')
1343     args = dict()
1344     while True:
1345         # Search for Argument insets
1346         i = find_token(document.body, "\\begin_inset Argument", i)
1347         if i == -1:
1348             return
1349         m = rx.match(document.body[i])
1350         if not m:
1351             # No ID: inset already reverted
1352             i = i + 1
1353             continue
1354         # Find containing paragraph layout
1355         parent = get_containing_layout(document.body, i)
1356         if parent == False:
1357             document.warning("Malformed LyX document: Can't find parent paragraph layout")
1358             i = i + 1
1359             continue
1360         parbeg = parent[1]
1361         parend = parent[2]
1362         realparbeg = parent[3]
1363         # Collect all arguments in this paragraph 
1364         realparend = parend
1365         for p in range(parbeg, parend):
1366             m = rx.match(document.body[p])
1367             if m:
1368                 val = int(m.group(1))
1369                 j = find_end_of_inset(document.body, p)
1370                 # Revert to old syntax
1371                 document.body[p] = "\\begin_inset Argument"
1372                 if j == -1:
1373                     document.warning("Malformed LyX document: Can't find end of Argument inset")
1374                     continue
1375                 if val > 0:
1376                     args[val] = document.body[p : j + 1]
1377                 # Adjust range end
1378                 realparend = realparend - len(document.body[p : j + 1])
1379                 # Remove arg inset at this position
1380                 del document.body[p : j + 1]
1381             if p >= realparend:
1382                 break
1383         # Now sort the arg insets
1384         subst = [""]
1385         for f in sorted(args):
1386             subst += args[f]
1387             del args[f]
1388         # Insert the sorted arg insets at paragraph begin
1389         document.body[realparbeg : realparbeg] = subst
1390
1391         i = realparbeg + 1 + len(subst)
1392
1393
1394 def revert_Argument_to_TeX_brace(document, line, endline, n, nmax, environment, opt):
1395     '''
1396     Reverts an InsetArgument to TeX-code
1397     usage:
1398     revert_Argument_to_TeX_brace(document, LineOfBegin, LineOfEnd, StartArgument, EndArgument, isEnvironment, isOpt)
1399     LineOfBegin is the line  of the \begin_layout or \begin_inset statement
1400     LineOfEnd is the line  of the \end_layout or \end_inset statement, if "0" is given, the end of the file is used instead
1401     StartArgument is the number of the first argument that needs to be converted
1402     EndArgument is the number of the last argument that needs to be converted or the last defined one
1403     isEnvironment must be true, if the layout is for a LaTeX environment
1404     isOpt must be true, if the argument is an optional one
1405     '''
1406     lineArg = 0
1407     wasOpt = False
1408     while lineArg != -1 and n < nmax + 1:
1409       lineArg = find_token(document.body, "\\begin_inset Argument " + str(n), line)
1410       if lineArg > endline and endline != 0:
1411         return wasOpt
1412       if lineArg != -1:
1413         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
1414         # we have to assure that no other inset is in the Argument
1415         beginInset = find_token(document.body, "\\begin_inset", beginPlain)
1416         endInset = find_token(document.body, "\\end_inset", beginPlain)
1417         k = beginPlain + 1
1418         l = k
1419         while beginInset < endInset and beginInset != -1:
1420           beginInset = find_token(document.body, "\\begin_inset", k)
1421           endInset = find_token(document.body, "\\end_inset", l)
1422           k = beginInset + 1
1423           l = endInset + 1
1424         if environment == False:
1425           if opt == False:
1426             document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}{")
1427             del(document.body[lineArg : beginPlain + 1])
1428             wasOpt = False
1429           else:
1430             document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("]")
1431             document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("[")
1432             wasOpt = True
1433         else:
1434           document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
1435           document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("{")
1436           wasOpt = False
1437         n = n + 1
1438     return wasOpt
1439
1440
1441 def convert_TeX_brace_to_Argument(document, line, n, nmax, inset, environment):
1442     '''
1443     Converts TeX code for mandatory arguments to an InsetArgument
1444     The conversion of TeX code for optional arguments must be done with another routine
1445     !!! Be careful if the braces are different in your case as expected here:
1446     - "}{" separates mandatory arguments of commands
1447     - "}" + "{" separates mandatory arguments of commands
1448     - "}" + " " + "{" separates mandatory arguments of commands
1449     - { and } surround a mandatory argument of an environment
1450     usage:
1451     convert_TeX_brace_to_Argument(document, LineOfBeginLayout/Inset, StartArgument, EndArgument, isInset, isEnvironment)
1452     LineOfBeginLayout/Inset is the line  of the \begin_layout or \begin_inset statement
1453     StartArgument is the number of the first ERT that needs to be converted
1454     EndArgument is the number of the last ERT that needs to be converted
1455     isInset must be true, if braces inside an InsetLayout needs to be converted
1456     isEnvironment must be true, if the layout is for a LaTeX environment
1457     
1458     Todo: this routine can currently handle only one mandatory argument of environments
1459     '''
1460     lineERT = line
1461     endn = line
1462     loop = 1
1463     while lineERT != -1 and n < nmax + 1:
1464       lineERT = find_token(document.body, "\\begin_inset ERT", lineERT)
1465       if environment == False and lineERT != -1:
1466         bracePair = find_token(document.body, "}{", lineERT)
1467         # assure that the "}{" is in this ERT
1468         if bracePair == lineERT + 5:
1469           end = find_token(document.body, "\\end_inset", bracePair)
1470           document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1471           if loop == 1:
1472             # in the case that n > 1 we have optional arguments before
1473             # therefore detect them if any
1474             if n > 1:
1475               # first check if there is an argument
1476               lineArg = find_token(document.body, "\\begin_inset Argument", line)
1477               if lineArg < lineERT and lineArg != -1:
1478                 # we have an argument, so now search backwards for its end
1479                 # we must now assure that we don't find other insets like e.g. a newline
1480                 endInsetArg = lineERT
1481                 endLayoutArg = endInsetArg
1482                 while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1483                   endInsetArg = endInsetArg - 1
1484                   endLayoutArg = endInsetArg
1485                   endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1486                   endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1487                 line = endInsetArg + 1
1488             if inset == False:
1489               document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1490             else:
1491               document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1492           else:
1493             document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1494           n = n + 1
1495           endn = end
1496           loop = loop + 1
1497         # now check the case that we have "}" + "{" in two ERTs
1498         else:
1499           endBrace = find_token(document.body, "}", lineERT)
1500           if endBrace == lineERT + 5:
1501             beginBrace = find_token(document.body, "{", endBrace)
1502             # assure that the ERTs are consecutive (11 or 12 depending if there is a space between the ERTs or not)
1503             if beginBrace == endBrace + 11 or beginBrace == endBrace + 12:
1504               end = find_token(document.body, "\\end_inset", beginBrace)
1505               document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1506               if loop == 1:
1507                 # in the case that n > 1 we have optional arguments before
1508                 # therefore detect them if any
1509                 if n > 1:
1510                   # first check if there is an argument
1511                   lineArg = find_token(document.body, "\\begin_inset Argument", line)
1512                   if lineArg < lineERT and lineArg != -1:
1513                     # we have an argument, so now search backwards for its end
1514                     # we must now assure that we don't find other insets like e.g. a newline
1515                     endInsetArg = lineERT
1516                     endLayoutArg = endInsetArg
1517                     while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1518                       endInsetArg = endInsetArg - 1
1519                       endLayoutArg = endInsetArg
1520                       endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1521                       endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1522                     line = endInsetArg + 1
1523                 if inset == False:
1524                   document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1525                 else:
1526                   document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1527               else:
1528                 document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1529               n += 1
1530               loop += 1
1531               # set the line where the next argument will be inserted
1532               if beginBrace == endBrace + 11:
1533                 endn = end - 11
1534               else:
1535                 endn = end - 12
1536             else:
1537               lineERT += 1
1538           else:
1539             lineERT += 1
1540       if environment == True and lineERT != -1:
1541         opening = find_token(document.body, "{", lineERT)
1542         if opening == lineERT + 5: # assure that the "{" is in this ERT
1543           end = find_token(document.body, "\\end_inset", opening)
1544           document.body[lineERT : end + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1545           n += 1
1546           lineERT2 = find_token(document.body, "\\begin_inset ERT", lineERT)
1547           closing = find_token(document.body, "}", lineERT2)
1548           if closing == lineERT2 + 5: # assure that the "}" is in this ERT
1549             end2 = find_token(document.body, "\\end_inset", closing)
1550             document.body[lineERT2 : end2 + 1] = ["\\end_layout", "", "\\end_inset"]
1551         else:
1552           lineERT += 1
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