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