]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_1_6.py
6e39e60cf8b00b5569372a8591759fcdc39d02d7
[lyx.git] / lib / lyx2lyx / lyx_1_6.py
1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2008 The LyX Team <lyx-devel@lists.lyx.org>
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 """ Convert files to the file format generated by lyx 1.6"""
20
21 import re
22 import unicodedata
23 import sys, os
24
25 from parser_tools import find_token, find_end_of, find_tokens, get_value, get_value_string
26
27 ####################################################################
28 # Private helper functions
29
30 def find_end_of_inset(lines, i):
31     " Find end of inset, where lines[i] is included."
32     return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
33
34 # WARNING!
35 # DO NOT do this:
36 #   document.body[i] = wrap_insert_ert(...)
37 # wrap_into_ert may returns a multiline string, which should NOT appear
38 # in document.body. Insetad, do something like this:
39 #   subst = wrap_inset_ert(...)
40 #   subst = subst.split('\n')
41 #   document.body[i:i+1] = subst
42 #   i+= len(subst) - 1
43 # where the last statement resets the counter to accord with the added
44 # lines.
45 def wrap_into_ert(string, src, dst):
46     " Wrap a something into an ERT"
47     return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
48       + dst + '\n\\end_layout\n\\end_inset\n')
49
50 def add_to_preamble(document, text):
51     """ Add text to the preamble if it is not already there.
52     Only the first line is checked!"""
53
54     if find_token(document.preamble, text[0], 0) != -1:
55         return
56
57     document.preamble.extend(text)
58
59 # Convert a LyX length into a LaTeX length
60 def convert_len(len):
61     units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
62              "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
63              "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
64
65     # Convert LyX units to LaTeX units
66     for unit in units.keys():
67         if len.find(unit) != -1:
68             len = '%f' % (len2value(len) / 100)
69             len = len.strip('0') + units[unit]
70             break
71
72     return len
73
74 # Return the value of len without the unit in numerical form.
75 def len2value(len):
76     result = re.search('([+-]?[0-9.]+)', len)
77     if result:
78         return float(result.group(1))
79     # No number means 1.0
80     return 1.0
81
82 # Unfortunately, this doesn't really work, since Standard isn't always default.
83 # But it's as good as we can do right now.
84 def find_default_layout(document, start, end):
85     l = find_token(document.body, "\\begin_layout Standard", start, end)
86     if l == -1:
87         l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
88     if l == -1:
89         l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
90     return l
91
92 def get_option(document, m, option, default):
93     l = document.body[m].find(option)
94     val = default
95     if l != -1:
96         val = document.body[m][l:].split('"')[1]
97     return val
98
99 def remove_option(document, m, option):
100     l = document.body[m].find(option)
101     if l != -1:
102         val = document.body[m][l:].split('"')[1]
103         document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
104     return l
105
106 def set_option(document, m, option, value):
107     l = document.body[m].find(option)
108     if l != -1:
109         oldval = document.body[m][l:].split('"')[1]
110         l = l + len(option + '="')
111         document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
112     else:
113         document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
114     return l
115
116
117 ####################################################################
118
119 def convert_ltcaption(document):
120     i = 0
121     while True:
122         i = find_token(document.body, "\\begin_inset Tabular", i)
123         if i == -1:
124             return
125         j = find_end_of_inset(document.body, i + 1)
126         if j == -1:
127             document.warning("Malformed LyX document: Could not find end of tabular.")
128             continue
129
130         nrows = int(document.body[i+1].split('"')[3])
131         ncols = int(document.body[i+1].split('"')[5])
132
133         m = i + 1
134         for k in range(nrows):
135             m = find_token(document.body, "<row", m)
136             r = m
137             caption = 'false'
138             for k in range(ncols):
139                 m = find_token(document.body, "<cell", m)
140                 if (k == 0):
141                     mend = find_token(document.body, "</cell>", m + 1)
142                     # first look for caption insets
143                     mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
144                     # then look for ERT captions
145                     if mcap == -1:
146                         mcap = find_token(document.body, "caption", m + 1, mend)
147                         if mcap > -1:
148                             mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
149                     if mcap > -1:
150                         caption = 'true'
151                 if caption == 'true':
152                     if (k == 0):
153                         set_option(document, r, 'caption', 'true')
154                         set_option(document, m, 'multicolumn', '1')
155                         set_option(document, m, 'bottomline', 'false')
156                         set_option(document, m, 'topline', 'false')
157                         set_option(document, m, 'rightline', 'false')
158                         set_option(document, m, 'leftline', 'false')
159                         #j = find_end_of_inset(document.body, j + 1)
160                     else:
161                         set_option(document, m, 'multicolumn', '2')
162                 m = m + 1
163             m = m + 1
164
165         i = j + 1
166
167
168 #FIXME Use of wrap_into_ert can confuse lyx2lyx
169 def revert_ltcaption(document):
170     i = 0
171     while True:
172         i = find_token(document.body, "\\begin_inset Tabular", i)
173         if i == -1:
174             return
175         j = find_end_of_inset(document.body, i + 1)
176         if j == -1:
177             document.warning("Malformed LyX document: Could not find end of tabular.")
178             continue
179
180         m = i + 1
181         nrows = int(document.body[i+1].split('"')[3])
182         ncols = int(document.body[i+1].split('"')[5])
183
184         for k in range(nrows):
185             m = find_token(document.body, "<row", m)
186             caption = get_option(document, m, 'caption', 'false')
187             if caption == 'true':
188                 remove_option(document, m, 'caption')
189                 for k in range(ncols):
190                     m = find_token(document.body, "<cell", m)
191                     remove_option(document, m, 'multicolumn')
192                     if k == 0:
193                         m = find_token(document.body, "\\begin_inset Caption", m)
194                         if m == -1:
195                             return
196                         m = find_end_of_inset(document.body, m + 1)
197                         document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
198                     m = m + 1
199             m = m + 1
200         i = j + 1
201
202
203 def convert_tablines(document):
204     i = 0
205     while True:
206         i = find_token(document.body, "\\begin_inset Tabular", i)
207         if i == -1:
208             # LyX 1.3 inserted an extra space between \begin_inset
209             # and Tabular so let us try if this is the case and fix it.
210             i = find_token(document.body, "\\begin_inset  Tabular", i)
211             if i == -1:
212                 return
213             else:
214                 document.body[i] = "\\begin_inset Tabular"
215         j = find_end_of_inset(document.body, i + 1)
216         if j == -1:
217             document.warning("Malformed LyX document: Could not find end of tabular.")
218             continue
219
220         m = i + 1
221         nrows = int(document.body[i+1].split('"')[3])
222         ncols = int(document.body[i+1].split('"')[5])
223
224         col_info = []
225         for k in range(ncols):
226             m = find_token(document.body, "<column", m)
227             left = get_option(document, m, 'leftline', 'false')
228             right = get_option(document, m, 'rightline', 'false')
229             col_info.append([left, right])
230             remove_option(document, m, 'leftline')
231             remove_option(document, m, 'rightline')
232             m = m + 1
233
234         row_info = []
235         for k in range(nrows):
236             m = find_token(document.body, "<row", m)
237             top = get_option(document, m, 'topline', 'false')
238             bottom = get_option(document, m, 'bottomline', 'false')
239             row_info.append([top, bottom])
240             remove_option(document, m, 'topline')
241             remove_option(document, m, 'bottomline')
242             m = m + 1
243
244         m = i + 1
245         mc_info = []
246         for k in range(nrows*ncols):
247             m = find_token(document.body, "<cell", m)
248             mc_info.append(get_option(document, m, 'multicolumn', '0'))
249             m = m + 1
250         m = i + 1
251         for l in range(nrows):
252             for k in range(ncols):
253                 m = find_token(document.body, '<cell', m)
254                 if mc_info[l*ncols + k] == '0':
255                     r = set_option(document, m, 'topline', row_info[l][0])
256                     r = set_option(document, m, 'bottomline', row_info[l][1])
257                     r = set_option(document, m, 'leftline', col_info[k][0])
258                     r = set_option(document, m, 'rightline', col_info[k][1])
259                 elif mc_info[l*ncols + k] == '1':
260                     s = k + 1
261                     while s < ncols and mc_info[l*ncols + s] == '2':
262                         s = s + 1
263                     if s < ncols and mc_info[l*ncols + s] != '1':
264                         r = set_option(document, m, 'rightline', col_info[k][1])
265                     if k > 0 and mc_info[l*ncols + k - 1] == '0':
266                         r = set_option(document, m, 'leftline', col_info[k][0])
267                 m = m + 1
268         i = j + 1
269
270
271 def revert_tablines(document):
272     i = 0
273     while True:
274         i = find_token(document.body, "\\begin_inset Tabular", i)
275         if i == -1:
276             return
277         j = find_end_of_inset(document.body, i + 1)
278         if j == -1:
279             document.warning("Malformed LyX document: Could not find end of tabular.")
280             continue
281
282         m = i + 1
283         nrows = int(document.body[i+1].split('"')[3])
284         ncols = int(document.body[i+1].split('"')[5])
285
286         lines = []
287         for k in range(nrows*ncols):
288             m = find_token(document.body, "<cell", m)
289             top = get_option(document, m, 'topline', 'false')
290             bottom = get_option(document, m, 'bottomline', 'false')
291             left = get_option(document, m, 'leftline', 'false')
292             right = get_option(document, m, 'rightline', 'false')
293             lines.append([top, bottom, left, right])
294             m = m + 1
295
296         # we will want to ignore longtable captions
297         m = i + 1
298         caption_info = []
299         for k in range(nrows):
300             m = find_token(document.body, "<row", m)
301             caption = get_option(document, m, 'caption', 'false')
302             caption_info.append([caption])
303             m = m + 1
304
305         m = i + 1
306         col_info = []
307         for k in range(ncols):
308             m = find_token(document.body, "<column", m)
309             left = 'true'
310             for l in range(nrows):
311                 left = lines[l*ncols + k][2]
312                 if left == 'false' and caption_info[l] == 'false':
313                     break
314             set_option(document, m, 'leftline', left)
315             right = 'true'
316             for l in range(nrows):
317                 right = lines[l*ncols + k][3]
318                 if right == 'false' and caption_info[l] == 'false':
319                     break
320             set_option(document, m, 'rightline', right)
321             m = m + 1
322
323         row_info = []
324         for k in range(nrows):
325             m = find_token(document.body, "<row", m)
326             top = 'true'
327             for l in range(ncols):
328                 top = lines[k*ncols + l][0]
329                 if top == 'false':
330                     break
331             if caption_info[k] == 'false':
332                 top = 'false'
333             set_option(document, m, 'topline', top)
334             bottom = 'true'
335             for l in range(ncols):
336                 bottom = lines[k*ncols + l][1]
337                 if bottom == 'false':
338                     break
339             if caption_info[k] == 'false':
340                 bottom = 'false'
341             set_option(document, m, 'bottomline', bottom)
342             m = m + 1
343
344         i = j + 1
345
346
347 def fix_wrong_tables(document):
348     i = 0
349     while True:
350         i = find_token(document.body, "\\begin_inset Tabular", i)
351         if i == -1:
352             return
353         j = find_end_of_inset(document.body, i + 1)
354         if j == -1:
355             document.warning("Malformed LyX document: Could not find end of tabular.")
356             continue
357
358         m = i + 1
359         nrows = int(document.body[i+1].split('"')[3])
360         ncols = int(document.body[i+1].split('"')[5])
361
362         for l in range(nrows):
363             prev_multicolumn = 0
364             for k in range(ncols):
365                 m = find_token(document.body, '<cell', m)
366
367                 if document.body[m].find('multicolumn') != -1:
368                     multicol_cont = int(document.body[m].split('"')[1])
369
370                     if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
371                         document.body[m] = document.body[m][:5] + document.body[m][21:]
372                         prev_multicolumn = 0
373                     else:
374                         prev_multicolumn = multicol_cont
375                 else:
376                     prev_multicolumn = 0
377
378         i = j + 1
379
380
381 def close_begin_deeper(document):
382     i = 0
383     depth = 0
384     while True:
385         i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
386
387         if i == -1:
388             break
389
390         if document.body[i][:13] == "\\begin_deeper":
391             depth += 1
392         else:
393             depth -= 1
394
395         i += 1
396
397     document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
398
399
400 def long_charstyle_names(document):
401     i = 0
402     while True:
403         i = find_token(document.body, "\\begin_inset CharStyle", i)
404         if i == -1:
405             return
406         document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
407         i += 1
408
409 def revert_long_charstyle_names(document):
410     i = 0
411     while True:
412         i = find_token(document.body, "\\begin_inset CharStyle", i)
413         if i == -1:
414             return
415         document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle")
416         i += 1
417
418
419 def axe_show_label(document):
420     i = 0
421     while True:
422         i = find_token(document.body, "\\begin_inset CharStyle", i)
423         if i == -1:
424             return
425         if document.body[i + 1].find("show_label") != -1:
426             if document.body[i + 1].find("true") != -1:
427                 document.body[i + 1] = "status open"
428                 del document.body[ i + 2]
429             else:
430                 if document.body[i + 1].find("false") != -1:
431                     document.body[i + 1] = "status collapsed"
432                     del document.body[ i + 2]
433                 else:
434                     document.warning("Malformed LyX document: show_label neither false nor true.")
435         else:
436             document.warning("Malformed LyX document: show_label missing in CharStyle.")
437
438         i += 1
439
440
441 def revert_show_label(document):
442     i = 0
443     while True:
444         i = find_token(document.body, "\\begin_inset CharStyle", i)
445         if i == -1:
446             return
447         if document.body[i + 1].find("status open") != -1:
448             document.body.insert(i + 1, "show_label true")
449         else:
450             if document.body[i + 1].find("status collapsed") != -1:
451                 document.body.insert(i + 1, "show_label false")
452             else:
453                 document.warning("Malformed LyX document: no legal status line in CharStyle.")
454         i += 1
455
456 def revert_begin_modules(document):
457     i = 0
458     while True:
459         i = find_token(document.header, "\\begin_modules", i)
460         if i == -1:
461             return
462         j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
463         if j == -1:
464             # this should not happen
465             break
466         document.header[i : j + 1] = []
467
468 def convert_flex(document):
469     "Convert CharStyle to Flex"
470     i = 0
471     while True:
472         i = find_token(document.body, "\\begin_inset CharStyle", i)
473         if i == -1:
474             return
475         document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
476
477 def revert_flex(document):
478     "Convert Flex to CharStyle"
479     i = 0
480     while True:
481         i = find_token(document.body, "\\begin_inset Flex", i)
482         if i == -1:
483             return
484         document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
485
486
487 #  Discard PDF options for hyperref
488 def revert_pdf_options(document):
489         "Revert PDF options for hyperref."
490         # store the PDF options and delete the entries from the Lyx file
491         i = 0
492         hyperref = False
493         title = ""
494         author = ""
495         subject = ""
496         keywords = ""
497         bookmarks = ""
498         bookmarksnumbered = ""
499         bookmarksopen = ""
500         bookmarksopenlevel = ""
501         breaklinks = ""
502         pdfborder = ""
503         colorlinks = ""
504         backref = ""
505         pagebackref = ""
506         pagemode = ""
507         otheroptions = ""
508         i = find_token(document.header, "\\use_hyperref", i)
509         if i != -1:
510             hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
511             del document.header[i]
512         i = find_token(document.header, "\\pdf_store_options", i)
513         if i != -1:
514             del document.header[i]
515         i = find_token(document.header, "\\pdf_title", 0)
516         if i != -1:
517             title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
518             title = ' pdftitle={' + title + '}'
519             del document.header[i]
520         i = find_token(document.header, "\\pdf_author", 0)
521         if i != -1:
522             author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
523             if title == "":
524                 author = ' pdfauthor={' + author + '}'
525             else:
526                 author = ',\n pdfauthor={' + author + '}'
527             del document.header[i]
528         i = find_token(document.header, "\\pdf_subject", 0)
529         if i != -1:
530             subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
531             if title == "" and author == "":
532                 subject = ' pdfsubject={' + subject + '}'
533             else:
534                 subject = ',\n pdfsubject={' + subject + '}'
535             del document.header[i]
536         i = find_token(document.header, "\\pdf_keywords", 0)
537         if i != -1:
538             keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
539             if title == "" and author == "" and subject == "":
540                 keywords = ' pdfkeywords={' + keywords + '}'
541             else:
542                 keywords = ',\n pdfkeywords={' + keywords + '}'
543             del document.header[i]
544         i = find_token(document.header, "\\pdf_bookmarks", 0)
545         if i != -1:
546             bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
547             bookmarks = ',\n bookmarks=' + bookmarks
548             del document.header[i]
549         i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
550         if i != -1:
551             bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
552             bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
553             del document.header[i]
554         i = find_token(document.header, "\\pdf_bookmarksopen", i)
555         if i != -1:
556             bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
557             bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
558             del document.header[i]
559         i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
560         if i != -1:
561             bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
562             bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
563             del document.header[i]
564         i = find_token(document.header, "\\pdf_breaklinks", i)
565         if i != -1:
566             breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
567             breaklinks = ',\n breaklinks=' + breaklinks
568             del document.header[i]
569         i = find_token(document.header, "\\pdf_pdfborder", i)
570         if i != -1:
571             pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
572             if pdfborder == 'true':
573                 pdfborder = ',\n pdfborder={0 0 0}'
574             else:
575                 pdfborder = ',\n pdfborder={0 0 1}'
576             del document.header[i]
577         i = find_token(document.header, "\\pdf_colorlinks", i)
578         if i != -1:
579             colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
580             colorlinks = ',\n colorlinks=' + colorlinks
581             del document.header[i]
582         i = find_token(document.header, "\\pdf_backref", i)
583         if i != -1:
584             backref = get_value_string(document.header, '\\pdf_backref', 0)
585             backref = ',\n backref=' + backref
586             del document.header[i]
587         i = find_token(document.header, "\\pdf_pagebackref", i)
588         if i != -1:
589             pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
590             pagebackref = ',\n pagebackref=' + pagebackref
591             del document.header[i]
592         i = find_token(document.header, "\\pdf_pagemode", 0)
593         if i != -1:
594             pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
595             pagemode = ',\n pdfpagemode=' + pagemode
596             del document.header[i]
597         i = find_token(document.header, "\\pdf_quoted_options", 0)
598         if i != -1:
599             otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
600             if title == "" and author == "" and subject == "" and keywords == "":
601                 otheroptions = ' ' + otheroptions
602             else:
603                 otheroptions = ',\n ' + otheroptions
604             del document.header[i]
605
606         # write to the preamble when hyperref was used
607         if hyperref == True:
608             # preamble write preparations
609             # bookmark numbers are only output when they are turned on
610             if bookmarksopen == ',\n bookmarksopen=true':
611                 bookmarksopen = bookmarksopen + bookmarksopenlevel
612             if bookmarks == ',\n bookmarks=true':
613                 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
614             else:
615                 bookmarks = bookmarks
616             # hypersetup is only output when there are things to be set up
617             setupstart = '\\hypersetup{%\n'
618             setupend = ' }\n'
619             if otheroptions == "" and title == "" and  author == ""\
620                and  subject == "" and keywords == "":
621                 setupstart = ""
622                 setupend = ""
623             # write the preamble
624             add_to_preamble(document,
625                                 ['% Commands inserted by lyx2lyx for PDF properties',
626                                  '\\usepackage[unicode=true'
627                                  + bookmarks
628                                  + breaklinks
629                                  + pdfborder
630                                  + backref
631                                  + pagebackref
632                                  + colorlinks
633                                  + pagemode
634                                  + ']\n'
635                                  ' {hyperref}\n'
636                                  + setupstart
637                                  + title
638                                  + author
639                                  + subject
640                                  + keywords
641                                  + otheroptions
642                                  + setupend])
643
644
645 def remove_inzip_options(document):
646     "Remove inzipName and embed options from the Graphics inset"
647     i = 0
648     while 1:
649         i = find_token(document.body, "\\begin_inset Graphics", i)
650         if i == -1:
651             return
652         j = find_end_of_inset(document.body, i + 1)
653         if j == -1:
654             # should not happen
655             document.warning("Malformed LyX document: Could not find end of graphics inset.")
656         # If there's a inzip param, just remove that
657         k = find_token(document.body, "\tinzipName", i + 1, j)
658         if k != -1:
659             del document.body[k]
660             # embed option must follow the inzipName option
661             del document.body[k+1]
662         i = i + 1
663
664
665 def convert_inset_command(document):
666     """
667         Convert:
668             \begin_inset LatexCommand cmd
669         to
670             \begin_inset CommandInset InsetType
671             LatexCommand cmd
672     """
673     i = 0
674     while 1:
675         i = find_token(document.body, "\\begin_inset LatexCommand", i)
676         if i == -1:
677             return
678         line = document.body[i]
679         r = re.compile(r'\\begin_inset LatexCommand (.*)$')
680         m = r.match(line)
681         cmdName = m.group(1)
682         insetName = ""
683         #this is adapted from factory.cpp
684         if cmdName[0:4].lower() == "cite":
685             insetName = "citation"
686         elif cmdName == "url" or cmdName == "htmlurl":
687             insetName = "url"
688         elif cmdName[-3:] == "ref":
689             insetName = "ref"
690         elif cmdName == "tableofcontents":
691             insetName = "toc"
692         elif cmdName == "printnomenclature":
693             insetName = "nomencl_print"
694         elif cmdName == "printindex":
695             insetName = "index_print"
696         else:
697             insetName = cmdName
698         insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
699         document.body[i : i+1] = insertion
700
701
702 def revert_inset_command(document):
703     """
704         Convert:
705             \begin_inset CommandInset InsetType
706             LatexCommand cmd
707         to
708             \begin_inset LatexCommand cmd
709         Some insets may end up being converted to insets earlier versions of LyX
710         will not be able to recognize. Not sure what to do about that.
711     """
712     i = 0
713     while 1:
714         i = find_token(document.body, "\\begin_inset CommandInset", i)
715         if i == -1:
716             return
717         nextline = document.body[i+1]
718         r = re.compile(r'LatexCommand\s+(.*)$')
719         m = r.match(nextline)
720         if not m:
721             document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
722             continue
723         cmdName = m.group(1)
724         insertion = ["\\begin_inset LatexCommand " + cmdName]
725         document.body[i : i+2] = insertion
726
727
728 def convert_wrapfig_options(document):
729     "Convert optional options for wrap floats (wrapfig)."
730     # adds the tokens "lines", "placement", and "overhang"
731     i = 0
732     while True:
733         i = find_token(document.body, "\\begin_inset Wrap figure", i)
734         if i == -1:
735             return
736         document.body.insert(i + 1, "lines 0")
737         j = find_token(document.body, "placement", i)
738         # placement can be already set or not; if not, set it
739         if j == i+2:
740             document.body.insert(i + 3, "overhang 0col%")
741         else:
742            document.body.insert(i + 2, "placement o")
743            document.body.insert(i + 3, "overhang 0col%")
744         i = i + 1
745
746
747 def revert_wrapfig_options(document):
748     "Revert optional options for wrap floats (wrapfig)."
749     i = 0
750     while True:
751         i = find_token(document.body, "\\begin_inset Wrap figure", i)
752         if i == -1:
753             return
754         j = find_end_of_inset(document.body, i)
755         if j == -1:
756             document.warning("Can't find end of Wrap inset at line " + str(i))
757             i += 1
758             continue
759         k = find_default_layout(document, i, j)
760         if k == -1:
761             document.warning("Can't find default layout for Wrap figure!")
762             i = j
763             continue
764         # Options should be between i and k now
765         l = find_token(document.body, "lines", i, k)
766         if l == -1:
767             document.warning("Can't find lines option for Wrap figure!")
768             i = k
769             continue
770         m = find_token(document.body, "overhang", i + 1, k)
771         if m == -1:
772             document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
773             i = k
774             continue
775         # Do these in reverse order
776         del document.body[m]
777         del document.body[l]
778         i = k
779
780
781 # To convert and revert indices, we need to convert between LaTeX 
782 # strings and LyXText. Here we do a minimal conversion to prevent 
783 # crashes and data loss. Manual patch-up may be needed.
784 replacements = [
785   [r'\\\"a', u'ä'], 
786   [r'\\\"o', u'ö'], 
787   [r'\\\"u', u'ü'],
788   [r'\\\'a', u'á'],
789   [r'\\\'e', u'é'],
790   [r'\\\'i', u'í'],
791   [r'\\\'o', u'ó'],
792   [r'\\\'u', u'ú']
793 ]
794
795 def convert_latexcommand_index(document):
796     "Convert from LatexCommand form to collapsable form."
797     i = 0
798     while True:
799         i = find_token(document.body, "\\begin_inset CommandInset index", i)
800         if i == -1:
801             return
802         if document.body[i + 1] != "LatexCommand index": # Might also be index_print
803             return
804         fullcontent = document.body[i + 2][5:]
805         fullcontent.strip()
806         fullcontent = fullcontent[1:-1]
807         document.body[i:i + 3] = ["\\begin_inset Index",
808           "status collapsed",
809           "\\begin_layout Standard"]
810         i += 3
811         # We are now on the blank line preceding "\end_inset"
812         # We will write the content here, into the inset.
813
814         # Do the LaTeX --> LyX text conversion
815         for rep in replacements:
816             fullcontent = fullcontent.replace(rep[0], rep[1])
817         # Generic, \" -> ":
818         fullcontent = wrap_into_ert(fullcontent, r'\"', '"')
819         # Math:
820         r = re.compile('^(.*?)(\$.*?\$)(.*)')
821         lines = fullcontent.split('\n')
822         for line in lines:
823             #document.warning("LINE: " + line)
824             #document.warning(str(i) + ":" + document.body[i])
825             #document.warning("LAST: " + document.body[-1])
826             g = line
827             while r.match(g):
828                 m = r.match(g)
829                 s = m.group(1)
830                 f = m.group(2).replace('\\\\', '\\')
831                 g = m.group(3)
832                 if s:
833                   # this is non-math!
834                   s = wrap_into_ert(s, r'\\', '\\backslash')
835                   s = wrap_into_ert(s, '{', '{')
836                   s = wrap_into_ert(s, '}', '}')
837                   subst = s.split('\n')
838                   document.body[i:i] = subst
839                   i += len(subst)
840                 document.body.insert(i + 1, "\\begin_inset Formula " + f)
841                 document.body.insert(i + 2, "\\end_inset")
842                 i += 2
843             # Generic, \\ -> \backslash:
844             g = wrap_into_ert(g, r'\\', '\\backslash')
845             g = wrap_into_ert(g, '{', '{')
846             g = wrap_into_ert(g, '}', '}')
847             subst = g.split('\n')
848             document.body[i+1:i+1] = subst
849             i += len(subst)
850         document.body.insert(i + 1, "\\end_layout")
851
852
853 def revert_latexcommand_index(document):
854     "Revert from collapsable form to LatexCommand form."
855     i = 0
856     while True:
857         i = find_token(document.body, "\\begin_inset Index", i)
858         if i == -1:
859           return
860         j = find_end_of_inset(document.body, i + 1)
861         if j == -1:
862           return
863         del document.body[j - 1]
864         del document.body[j - 2] # \end_layout
865         document.body[i] =  "\\begin_inset CommandInset index"
866         document.body[i + 1] =  "LatexCommand index"
867         # clean up multiline stuff
868         content = ""
869         ert_end = 0
870         for k in range(i + 3, j - 2):
871           line = document.body[k]
872           if line.startswith("\\begin_inset ERT"):
873               ert_end = find_end_of_inset(document.body, k + 1)
874               line = line[16:]
875           if line.startswith("\\begin_inset Formula"):
876             line = line[20:]
877           if line.startswith("\\begin_layout Standard"):
878             line = line[22:]
879           if line.startswith("\\begin_layout Plain Layout"):
880             line = line[26:]
881           if line.startswith("\\end_layout"):
882             line = line[11:]
883           if line.startswith("\\end_inset"):
884             line = line[10:]
885           if line.startswith("status collapsed"):
886             line = line[16:]
887           if line.startswith("status open"):
888             line = line[11:]
889           # a lossless reversion is not possible
890           # try at least to handle some common insets and settings
891           # do not replace inside ERTs
892           if ert_end < k:
893               # Do the LyX text --> LaTeX conversion
894               for rep in replacements:
895                 line = line.replace(rep[1], rep[0])
896               line = line.replace(r'\backslash', r'\textbackslash{}')
897               line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
898               line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
899               line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
900               line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
901               line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
902               line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
903               line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
904               line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
905               line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
906           else:
907               line = line.replace(r'\backslash', r'\\')
908           content = content + line;
909         document.body[i + 3] = "name " + '"' + content + '"'
910         for k in range(i + 4, j - 2):
911           del document.body[i + 4]
912         document.body.insert(i + 4, "")
913         del document.body[i + 2] # \begin_layout standard
914         i = i + 5
915
916
917 def revert_wraptable(document):
918     "Revert wrap table to wrap figure."
919     i = 0
920     while True:
921         i = find_token(document.body, "\\begin_inset Wrap table", i)
922         if i == -1:
923             return
924         document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
925         i = i + 1
926
927
928 def revert_vietnamese(document):
929     "Set language Vietnamese to English"
930     # Set document language from Vietnamese to English
931     i = 0
932     if document.language == "vietnamese":
933         document.language = "english"
934         i = find_token(document.header, "\\language", 0)
935         if i != -1:
936             document.header[i] = "\\language english"
937     j = 0
938     while True:
939         j = find_token(document.body, "\\lang vietnamese", j)
940         if j == -1:
941             return
942         document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
943         j = j + 1
944
945
946 def revert_japanese(document):
947     "Set language japanese-plain to japanese"
948     # Set document language from japanese-plain to japanese
949     i = 0
950     if document.language == "japanese-plain":
951         document.language = "japanese"
952         i = find_token(document.header, "\\language", 0)
953         if i != -1:
954             document.header[i] = "\\language japanese"
955     j = 0
956     while True:
957         j = find_token(document.body, "\\lang japanese-plain", j)
958         if j == -1:
959             return
960         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
961         j = j + 1
962
963
964 def revert_japanese_encoding(document):
965     "Set input encoding form EUC-JP-plain to EUC-JP etc."
966     # Set input encoding form EUC-JP-plain to EUC-JP etc.
967     i = 0
968     i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
969     if i != -1:
970         document.header[i] = "\\inputencoding EUC-JP"
971     j = 0
972     j = find_token(document.header, "\\inputencoding JIS-plain", 0)
973     if j != -1:
974         document.header[j] = "\\inputencoding JIS"
975     k = 0
976     k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
977     if k != -1: # convert to UTF8 since there is currently no SJIS encoding
978         document.header[k] = "\\inputencoding UTF8"
979
980
981 def revert_inset_info(document):
982     'Replace info inset with its content'
983     i = 0
984     while 1:
985         i = find_token(document.body, '\\begin_inset Info', i)
986         if i == -1:
987             return
988         j = find_end_of_inset(document.body, i + 1)
989         if j == -1:
990             # should not happen
991             document.warning("Malformed LyX document: Could not find end of Info inset.")
992         type = 'unknown'
993         arg = ''
994         for k in range(i, j+1):
995             if document.body[k].startswith("arg"):
996                 arg = document.body[k][3:].strip().strip('"')
997             if document.body[k].startswith("type"):
998                 type = document.body[k][4:].strip().strip('"')
999         # I think there is a newline after \\end_inset, which should be removed.
1000         if document.body[j + 1].strip() == "":
1001             document.body[i : (j + 2)] = [type + ':' + arg]
1002         else:
1003             document.body[i : (j + 1)] = [type + ':' + arg]
1004
1005
1006 def convert_pdf_options(document):
1007     # Set the pdfusetitle tag, delete the pdf_store_options,
1008     # set quotes for bookmarksopenlevel"
1009     has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1010     if has_hr == "1":
1011         k = find_token(document.header, "\\use_hyperref", 0)
1012         document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1013     k = find_token(document.header, "\\pdf_store_options", 0)
1014     if k != -1:
1015         del document.header[k]
1016     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1017     if i == -1: return
1018     document.header[i] = document.header[i].replace('"', '')
1019
1020
1021 def revert_pdf_options_2(document):
1022     # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1023     k = find_token(document.header, "\\use_hyperref", 0)
1024     i = find_token(document.header, "\\pdf_pdfusetitle", k)
1025     if i != -1:
1026         del document.header[i]
1027     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1028     if i == -1: return
1029     values = document.header[i].split()
1030     values[1] = ' "' + values[1] + '"'
1031     document.header[i] = ''.join(values)
1032
1033
1034 def convert_htmlurl(document):
1035     'Convert "htmlurl" to "href" insets for docbook'
1036     if document.backend != "docbook":
1037       return
1038     i = 0
1039     while True:
1040       i = find_token(document.body, "\\begin_inset CommandInset url", i)
1041       if i == -1:
1042         return
1043       document.body[i] = "\\begin_inset CommandInset href"
1044       document.body[i + 1] = "LatexCommand href"
1045       i = i + 1
1046
1047
1048 def convert_url(document):
1049     'Convert url insets to url charstyles'
1050     if document.backend == "docbook":
1051       return
1052     i = 0
1053     while True:
1054       i = find_token(document.body, "\\begin_inset CommandInset url", i)
1055       if i == -1:
1056         break
1057       n = find_token(document.body, "name", i)
1058       if n == i + 2:
1059         # place the URL name in typewriter before the new URL insert
1060         # grab the name 'bla' from the e.g. the line 'name "bla"',
1061         # therefore start with the 6th character
1062         name = document.body[n][6:-1]
1063         newname = [name + " "]
1064         document.body[i:i] = newname
1065         i = i + 1
1066       j = find_token(document.body, "target", i)
1067       if j == -1:
1068         document.warning("Malformed LyX document: Can't find target for url inset")
1069         i = j
1070         continue
1071       target = document.body[j][8:-1]
1072       k = find_token(document.body, "\\end_inset", j)
1073       if k == -1:
1074         document.warning("Malformed LyX document: Can't find end of url inset")
1075         i = k
1076         continue
1077       newstuff = ["\\begin_inset Flex URL",
1078         "status collapsed", "",
1079         "\\begin_layout Standard",
1080         "",
1081         target,
1082         "\\end_layout",
1083         ""]
1084       document.body[i:k] = newstuff
1085       i = k
1086
1087 def convert_ams_classes(document):
1088   tc = document.textclass
1089   if (tc != "amsart" and tc != "amsart-plain" and
1090       tc != "amsart-seq" and tc != "amsbook"):
1091     return
1092   if tc == "amsart-plain":
1093     document.textclass = "amsart"
1094     document.set_textclass()
1095     document.add_module("Theorems (Starred)")
1096     return
1097   if tc == "amsart-seq":
1098     document.textclass = "amsart"
1099     document.set_textclass()
1100   document.add_module("Theorems (AMS)")
1101
1102   #Now we want to see if any of the environments in the extended theorems
1103   #module were used in this document. If so, we'll add that module, too.
1104   layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note",  \
1105     "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1106     "Assumption"]
1107
1108   r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1109   i = 0
1110   while True:
1111     i = find_token(document.body, "\\begin_layout", i)
1112     if i == -1:
1113       return
1114     m = r.match(document.body[i])
1115     if m == None:
1116       document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1117       i += 1
1118       continue
1119     m = m.group(1)
1120     if layouts.count(m) != 0:
1121       document.add_module("Theorems (AMS-Extended)")
1122       return
1123     i += 1
1124
1125 def revert_href(document):
1126     'Reverts hyperlink insets (href) to url insets (url)'
1127     i = 0
1128     while True:
1129       i = find_token(document.body, "\\begin_inset CommandInset href", i)
1130       if i == -1:
1131           return
1132       document.body[i : i + 2] = \
1133         ["\\begin_inset CommandInset url", "LatexCommand url"]
1134       i = i + 2
1135
1136 def revert_url(document):
1137     'Reverts Flex URL insets to old-style URL insets'
1138     i = 0
1139     while True:
1140         i = find_token(document.body, "\\begin_inset Flex URL", i)
1141         if i == -1:
1142             return
1143         j = find_end_of_inset(document.body, i)
1144         if j == -1:
1145             document.warning("Can't find end of inset in revert_url!")
1146             return
1147         k = find_default_layout(document, i, j)
1148         if k == -1:
1149             document.warning("Can't find default layout in revert_url!")
1150             i = j
1151             continue
1152         l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1153         if l == -1 or l >= j:
1154             document.warning("Can't find end of default layout in revert_url!")
1155             i = j
1156             continue
1157         # OK, so the inset's data is between lines k and l.
1158         data =  " ".join(document.body[k+1:l])
1159         data = data.strip()
1160         newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1161                     "", "\\end_inset"]
1162         document.body[i:j+1] = newinset
1163         i = i + len(newinset)
1164
1165
1166 def convert_include(document):
1167   'Converts include insets to new format.'
1168   i = 0
1169   r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1170   while True:
1171     i = find_token(document.body, "\\begin_inset Include", i)
1172     if i == -1:
1173       return
1174     line = document.body[i]
1175     previewline = document.body[i + 1]
1176     m = r.match(line)
1177     if m == None:
1178       document.warning("Unable to match line " + str(i) + " of body!")
1179       i += 1
1180       continue
1181     cmd = m.group(1)
1182     fn  = m.group(2)
1183     opt = m.group(3)
1184     insertion = ["\\begin_inset CommandInset include",
1185        "LatexCommand " + cmd, previewline,
1186        "filename \"" + fn + "\""]
1187     newlines = 2
1188     if opt:
1189       insertion.append("lstparams " + '"' + opt + '"')
1190       newlines += 1
1191     document.body[i : i + 2] = insertion
1192     i += newlines
1193
1194
1195 def revert_include(document):
1196   'Reverts include insets to old format.'
1197   i = 0
1198   r0 = re.compile('preview.*')
1199   r1 = re.compile('LatexCommand (.+)')
1200   r2 = re.compile('filename (.+)')
1201   r3 = re.compile('lstparams "(.*)"')
1202   while True:
1203     i = find_token(document.body, "\\begin_inset CommandInset include", i)
1204     if i == -1:
1205       return
1206     nextline = i + 1
1207     if r0.match(document.body[nextline]):
1208       previewline = document.body[nextline]
1209       nextline += 1
1210     else:
1211       previewline = ""
1212     m = r1.match(document.body[nextline])
1213     if m == None:
1214       document.warning("Malformed LyX document: No LatexCommand line for `" +
1215         document.body[i] + "' on line " + str(i) + ".")
1216       i += 1
1217       continue
1218     cmd = m.group(1)
1219     nextline += 1
1220     m = r2.match(document.body[nextline])
1221     if m == None:
1222       document.warning("Malformed LyX document: No filename line for `" + \
1223         document.body[i] + "' on line " + str(i) + ".")
1224       i += 2
1225       continue
1226     fn = m.group(1)
1227     nextline += 1
1228     options = ""
1229     if (cmd == "lstinputlisting"):
1230       m = r3.match(document.body[nextline])
1231       if m != None:
1232         options = m.group(1)
1233         numlines = 5
1234         nextline += 1
1235     newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1236     if options:
1237       newline += ("[" + options + "]")
1238     insertion = [newline]
1239     if previewline != "":
1240       insertion.append(previewline)
1241     document.body[i : nextline] = insertion
1242     i += 2
1243
1244
1245 def revert_albanian(document):
1246     "Set language Albanian to English"
1247     i = 0
1248     if document.language == "albanian":
1249         document.language = "english"
1250         i = find_token(document.header, "\\language", 0)
1251         if i != -1:
1252             document.header[i] = "\\language english"
1253     j = 0
1254     while True:
1255         j = find_token(document.body, "\\lang albanian", j)
1256         if j == -1:
1257             return
1258         document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1259         j = j + 1
1260
1261
1262 def revert_lowersorbian(document):
1263     "Set language lower Sorbian to English"
1264     i = 0
1265     if document.language == "lowersorbian":
1266         document.language = "english"
1267         i = find_token(document.header, "\\language", 0)
1268         if i != -1:
1269             document.header[i] = "\\language english"
1270     j = 0
1271     while True:
1272         j = find_token(document.body, "\\lang lowersorbian", j)
1273         if j == -1:
1274             return
1275         document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1276         j = j + 1
1277
1278
1279 def revert_uppersorbian(document):
1280     "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1281     i = 0
1282     if document.language == "uppersorbian":
1283         document.language = "usorbian"
1284         i = find_token(document.header, "\\language", 0)
1285         if i != -1:
1286             document.header[i] = "\\language usorbian"
1287     j = 0
1288     while True:
1289         j = find_token(document.body, "\\lang uppersorbian", j)
1290         if j == -1:
1291             return
1292         document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1293         j = j + 1
1294
1295
1296 def convert_usorbian(document):
1297     "Set language usorbian to uppersorbian"
1298     i = 0
1299     if document.language == "usorbian":
1300         document.language = "uppersorbian"
1301         i = find_token(document.header, "\\language", 0)
1302         if i != -1:
1303             document.header[i] = "\\language uppersorbian"
1304     j = 0
1305     while True:
1306         j = find_token(document.body, "\\lang usorbian", j)
1307         if j == -1:
1308             return
1309         document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1310         j = j + 1
1311
1312
1313 def revert_macro_optional_params(document):
1314     "Convert macro definitions with optional parameters into ERTs"
1315     # Stub to convert macro definitions with one or more optional parameters
1316     # into uninterpreted ERT insets
1317
1318
1319 def revert_hyperlinktype(document):
1320     'Reverts hyperlink type'
1321     i = 0
1322     j = 0
1323     while True:
1324       i = find_token(document.body, "target", i)
1325       if i == -1:
1326           return
1327       j = find_token(document.body, "type", i)
1328       if j == -1:
1329           return
1330       if j == i + 1:
1331           del document.body[j]
1332       i = i + 1
1333
1334
1335 def revert_pagebreak(document):
1336     'Reverts pagebreak to ERT'
1337     i = 0
1338     while True:
1339       i = find_token(document.body, "\\pagebreak", i)
1340       if i == -1:
1341           return
1342       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1343       '\\begin_layout Standard\n\n\n\\backslash\n' \
1344       'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1345       i = i + 1
1346
1347
1348 def revert_linebreak(document):
1349     'Reverts linebreak to ERT'
1350     i = 0
1351     while True:
1352       i = find_token(document.body, "\\linebreak", i)
1353       if i == -1:
1354           return
1355       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1356       '\\begin_layout Standard\n\n\n\\backslash\n' \
1357       'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1358       i = i + 1
1359
1360
1361 def revert_latin(document):
1362     "Set language Latin to English"
1363     i = 0
1364     if document.language == "latin":
1365         document.language = "english"
1366         i = find_token(document.header, "\\language", 0)
1367         if i != -1:
1368             document.header[i] = "\\language english"
1369     j = 0
1370     while True:
1371         j = find_token(document.body, "\\lang latin", j)
1372         if j == -1:
1373             return
1374         document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1375         j = j + 1
1376
1377
1378 def revert_samin(document):
1379     "Set language North Sami to English"
1380     i = 0
1381     if document.language == "samin":
1382         document.language = "english"
1383         i = find_token(document.header, "\\language", 0)
1384         if i != -1:
1385             document.header[i] = "\\language english"
1386     j = 0
1387     while True:
1388         j = find_token(document.body, "\\lang samin", j)
1389         if j == -1:
1390             return
1391         document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1392         j = j + 1
1393
1394
1395 def convert_serbocroatian(document):
1396     "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1397     i = 0
1398     if document.language == "serbocroatian":
1399         document.language = "croatian"
1400         i = find_token(document.header, "\\language", 0)
1401         if i != -1:
1402             document.header[i] = "\\language croatian"
1403     j = 0
1404     while True:
1405         j = find_token(document.body, "\\lang serbocroatian", j)
1406         if j == -1:
1407             return
1408         document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1409         j = j + 1
1410
1411
1412 def convert_framed_notes(document):
1413     "Convert framed notes to boxes. "
1414     i = 0
1415     while 1:
1416         i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1417         if i == -1:
1418             return
1419         subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1420                  'position "t"',
1421                  'hor_pos "c"',
1422                  'has_inner_box 0',
1423                  'inner_pos "t"', 
1424                  'use_parbox 0',
1425                  'width "100col%"',
1426                  'special "none"',
1427                  'height "1in"',
1428                  'height_special "totalheight"']
1429         document.body[i:i+1] = subst
1430         i = i + 9
1431
1432
1433 def convert_module_names(document):
1434   modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1435     'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1436     'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1437     'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1438     'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1439   modlist = document.get_module_list()
1440   if len(modlist) == 0:
1441     return
1442   newmodlist = []
1443   for mod in modlist:
1444     if modulemap.has_key(mod):
1445       newmodlist.append(modulemap[mod])
1446     else:
1447       document.warning("Can't find module %s in the module map!" % mod)
1448       newmodlist.append(mod)
1449   document.set_module_list(newmodlist)
1450
1451
1452 def revert_module_names(document):
1453   modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1454     'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1455     'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1456     'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1457     'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1458   modlist = document.get_module_list()
1459   if len(modlist) == 0:
1460     return
1461   newmodlist = []
1462   for mod in modlist:
1463     if modulemap.has_key(mod):
1464       newmodlist.append(modulemap[mod])
1465     else:
1466       document.warning("Can't find module %s in the module map!" % mod)
1467       newmodlist.append(mod)
1468   document.set_module_list(newmodlist)
1469
1470
1471 def revert_colsep(document):
1472     i = find_token(document.header, "\\columnsep", 0)
1473     if i == -1:
1474         return
1475     colsepline = document.header[i]
1476     r = re.compile(r'\\columnsep (.*)')
1477     m = r.match(colsepline)
1478     if not m:
1479         document.warning("Malformed column separation line!")
1480         return
1481     colsep = m.group(1)
1482     del document.header[i]
1483     #it seems to be safe to add the package even if it is already used
1484     pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1485
1486     add_to_preamble(document, pretext)
1487
1488
1489 def revert_framed_notes(document):
1490     "Revert framed boxes to notes. "
1491     i = 0
1492     while 1:
1493         i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1494
1495         if i == -1:
1496             return
1497         j = find_end_of_inset(document.body, i + 1)
1498         if j == -1:
1499             # should not happen
1500             document.warning("Malformed LyX document: Could not find end of Box inset.")
1501         k = find_token(document.body, "status", i + 1, j)
1502         if k == -1:
1503             document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1504             return
1505         status = document.body[k]
1506         l = find_default_layout(document, i + 1, j)
1507         if l == -1:
1508             document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1509             return
1510         m = find_token(document.body, "\\end_layout", i + 1, j)
1511         if m == -1:
1512             document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1513             return
1514         ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1515         pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1516         if ibox == -1 and pbox == -1:
1517             document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1518             del document.body[i+1:k]
1519         else:
1520             document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1521             subst1 = [document.body[l],
1522                       "\\begin_inset Note Shaded",
1523                       status,
1524                       '\\begin_layout Standard']
1525             document.body[l:l + 1] = subst1
1526             subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1527             document.body[m:m + 1] = subst2
1528         i = i + 1
1529
1530
1531 def revert_slash(document):
1532     'Revert \\SpecialChar \\slash{} to ERT'
1533     r = re.compile(r'\\SpecialChar \\slash{}')
1534     i = 0
1535     while i < len(document.body):
1536         m = r.match(document.body[i])
1537         if m:
1538           subst = ['\\begin_inset ERT',
1539                    'status collapsed', '',
1540                    '\\begin_layout Standard',
1541                    '', '', '\\backslash',
1542                    'slash{}',
1543                    '\\end_layout', '',
1544                    '\\end_inset', '']
1545           document.body[i: i+1] = subst
1546           i = i + len(subst)
1547         else:
1548           i = i + 1
1549
1550
1551 def revert_nobreakdash(document):
1552     'Revert \\SpecialChar \\nobreakdash- to ERT'
1553     i = 0
1554     while i < len(document.body):
1555         line = document.body[i]
1556         r = re.compile(r'\\SpecialChar \\nobreakdash-')
1557         m = r.match(line)
1558         if m:
1559             subst = ['\\begin_inset ERT',
1560                     'status collapsed', '',
1561                     '\\begin_layout Standard', '', '',
1562                     '\\backslash',
1563                     'nobreakdash-',
1564                     '\\end_layout', '',
1565                     '\\end_inset', '']
1566             document.body[i:i+1] = subst
1567             i = i + len(subst)
1568             j = find_token(document.header, "\\use_amsmath", 0)
1569             if j == -1:
1570                 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1571                 return
1572             document.header[j] = "\\use_amsmath 2"
1573         else:
1574             i = i + 1
1575
1576
1577 #Returns number of lines added/removed
1578 def revert_nocite_key(body, start, end):
1579     'key "..." -> \nocite{...}' 
1580     r = re.compile(r'^key "(.*)"')
1581     i = start
1582     j = end
1583     while i < j:
1584         m = r.match(body[i])
1585         if m:
1586             body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1587             j += 1     # because we added a line
1588             i += 2     # skip that line
1589         else:
1590             del body[i]
1591             j -= 1     # because we deleted a line
1592             # no need to change i, since it now points to the next line
1593     return j - end
1594
1595
1596 def revert_nocite(document):
1597     "Revert LatexCommand nocite to ERT"
1598     i = 0
1599     while 1:
1600         i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1601         if i == -1:
1602             return
1603         if (document.body[i+1] != "LatexCommand nocite"):
1604             # note that we already incremented i
1605             i = i + 1
1606             continue
1607         insetEnd = find_end_of_inset(document.body, i)
1608         if insetEnd == -1:
1609             #this should not happen
1610             document.warning("End of CommandInset citation not found in revert_nocite!")
1611             return
1612
1613         paramLocation = i + 2 #start of the inset's parameters
1614         addedLines = 0
1615         document.body[i:i+2] = \
1616             ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1617         # that added two lines
1618         paramLocation += 2
1619         insetEnd += 2
1620         #print insetEnd, document.body[i: insetEnd + 1]
1621         insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1622         #print insetEnd, document.body[i: insetEnd + 1]
1623         document.body.insert(insetEnd, "\\end_layout")
1624         document.body.insert(insetEnd + 1, "")
1625         i = insetEnd + 1
1626
1627
1628 def revert_btprintall(document):
1629     "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1630     i = find_token(document.header, '\\use_bibtopic', 0)
1631     if i == -1:
1632         document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1633         return
1634     if get_value(document.header, '\\use_bibtopic', 0) == "false":
1635         i = 0
1636         while i < len(document.body):
1637             i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1638             if i == -1:
1639                 return
1640             j = find_end_of_inset(document.body, i + 1)
1641             if j == -1:
1642                 #this should not happen
1643                 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1644                 j = len(document.body)
1645             # this range isn't really right, but it should be OK, since we shouldn't
1646             # see more than one matching line in each inset
1647             addedlines = 0
1648             for k in range(i, j):
1649                 if (document.body[k] == 'btprint "btPrintAll"'):
1650                     del document.body[k]
1651                     subst = ["\\begin_inset ERT",
1652                              "status collapsed", "",
1653                              "\\begin_layout Standard", "",
1654                              "\\backslash",
1655                              "nocite{*}",
1656                              "\\end_layout",
1657                              "\\end_inset"]
1658                     document.body[i:i] = subst
1659                     addlines = addedlines + len(subst) - 1
1660             i = j + addedlines
1661
1662
1663 def revert_bahasam(document):
1664     "Set language Bahasa Malaysia to Bahasa Indonesia"
1665     i = 0
1666     if document.language == "bahasam":
1667         document.language = "bahasa"
1668         i = find_token(document.header, "\\language", 0)
1669         if i != -1:
1670             document.header[i] = "\\language bahasa"
1671     j = 0
1672     while True:
1673         j = find_token(document.body, "\\lang bahasam", j)
1674         if j == -1:
1675             return
1676         document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1677         j = j + 1
1678
1679
1680 def revert_interlingua(document):
1681     "Set language Interlingua to English"
1682     i = 0
1683     if document.language == "interlingua":
1684         document.language = "english"
1685         i = find_token(document.header, "\\language", 0)
1686         if i != -1:
1687             document.header[i] = "\\language english"
1688     j = 0
1689     while True:
1690         j = find_token(document.body, "\\lang interlingua", j)
1691         if j == -1:
1692             return
1693         document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1694         j = j + 1
1695
1696
1697 def revert_serbianlatin(document):
1698     "Set language Serbian-Latin to Croatian"
1699     i = 0
1700     if document.language == "serbian-latin":
1701         document.language = "croatian"
1702         i = find_token(document.header, "\\language", 0)
1703         if i != -1:
1704             document.header[i] = "\\language croatian"
1705     j = 0
1706     while True:
1707         j = find_token(document.body, "\\lang serbian-latin", j)
1708         if j == -1:
1709             return
1710         document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
1711         j = j + 1
1712
1713
1714 def revert_rotfloat(document):
1715     " Revert sideways custom floats. "
1716     i = 0
1717     while 1:
1718         # whitespace intended (exclude \\begin_inset FloatList)
1719         i = find_token(document.body, "\\begin_inset Float ", i)
1720         if i == -1:
1721             return
1722         line = document.body[i]
1723         r = re.compile(r'\\begin_inset Float (.*)$')
1724         m = r.match(line)
1725         if m == None:
1726             document.warning("Unable to match line " + str(i) + " of body!")
1727             i += 1
1728             continue
1729         floattype = m.group(1)
1730         if floattype == "figure" or floattype == "table":
1731             i += 1
1732             continue
1733         j = find_end_of_inset(document.body, i)
1734         if j == -1:
1735             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
1736             i += 1
1737             continue
1738         addedLines = 0
1739         if get_value(document.body, 'sideways', i, j) == "false":
1740             i += 1
1741             continue
1742         l = find_default_layout(document, i + 1, j)
1743         if l == -1:
1744             document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1745             return
1746         subst = ['\\begin_layout Standard',
1747                   '\\begin_inset ERT',
1748                   'status collapsed', '',
1749                   '\\begin_layout Standard', '', '', 
1750                   '\\backslash', '',
1751                   'end{sideways' + floattype + '}',
1752                   '\\end_layout', '', '\\end_inset']
1753         document.body[j : j+1] = subst
1754         addedLines = len(subst) - 1
1755         del document.body[i+1 : l]
1756         addedLines -= (l-1) - (i+1) 
1757         subst = ['\\begin_inset ERT', 'status collapsed', '',
1758                   '\\begin_layout Standard', '', '', '\\backslash', 
1759                   'begin{sideways' + floattype + '}', 
1760                   '\\end_layout', '', '\\end_inset', '',
1761                   '\\end_layout', '']
1762         document.body[i : i+1] = subst
1763         addedLines += len(subst) - 1
1764         if floattype == "algorithm":
1765             add_to_preamble(document,
1766                             ['% Commands inserted by lyx2lyx for sideways algorithm float',
1767                               '\\usepackage{rotfloat}',
1768                               '\\floatstyle{ruled}',
1769                               '\\newfloat{algorithm}{tbp}{loa}',
1770                               '\\floatname{algorithm}{Algorithm}'])
1771         else:
1772             document.warning("Cannot create preamble definition for custom float" + floattype + ".")
1773         i += addedLines + 1
1774
1775
1776 def revert_widesideways(document):
1777     " Revert wide sideways floats. "
1778     i = 0
1779     while 1:
1780         # whitespace intended (exclude \\begin_inset FloatList)
1781         i = find_token(document.body, '\\begin_inset Float ', i)
1782         if i == -1:
1783             return
1784         line = document.body[i]
1785         r = re.compile(r'\\begin_inset Float (.*)$')
1786         m = r.match(line)
1787         if m == None:
1788             document.warning("Unable to match line " + str(i) + " of body!")
1789             i += 1
1790             continue
1791         floattype = m.group(1)
1792         if floattype != "figure" and floattype != "table":
1793             i += 1
1794             continue
1795         j = find_end_of_inset(document.body, i)
1796         if j == -1:
1797             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
1798             i += 1
1799             continue
1800         if get_value(document.body, 'sideways', i, j) == "false" or \
1801            get_value(document.body, 'wide', i, j) == "false":
1802              i += 1
1803              continue
1804         l = find_default_layout(document, i + 1, j)
1805         if l == -1:
1806             document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1807             return
1808         subst = ['\\begin_layout Standard', '\\begin_inset ERT', 
1809                   'status collapsed', '', 
1810                   '\\begin_layout Standard', '', '', '\\backslash',
1811                   'end{sideways' + floattype + '*}', 
1812                   '\\end_layout', '', '\\end_inset']
1813         document.body[j : j+1] = subst
1814         addedLines = len(subst) - 1
1815         del document.body[i+1:l-1]
1816         addedLines -= (l-1) - (i+1)
1817         subst = ['\\begin_inset ERT', 'status collapsed', '',
1818                  '\\begin_layout Standard', '', '', '\\backslash',
1819                  'begin{sideways' + floattype + '*}', '\\end_layout', '',
1820                  '\\end_inset', '', '\\end_layout', '']
1821         document.body[i : i+1] = subst
1822         addedLines += len(subst) - 1
1823         add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
1824         i += addedLines + 1
1825
1826
1827 def revert_inset_embedding(document, type):
1828     ' Remove embed tag from certain type of insets'
1829     i = 0
1830     while 1:
1831         i = find_token(document.body, "\\begin_inset %s" % type, i)
1832         if i == -1:
1833             return
1834         j = find_end_of_inset(document.body, i)
1835         if j == -1:
1836             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
1837             i = i + 1
1838             continue
1839         k = find_token(document.body, "\tembed", i, j)
1840         if k == -1:
1841             k = find_token(document.body, "embed", i, j)
1842         if k != -1:
1843             del document.body[k]
1844         i = i + 1
1845
1846
1847 def revert_external_embedding(document):
1848     ' Remove embed tag from external inset '
1849     revert_inset_embedding(document, 'External')
1850
1851
1852 # FIXME This code can still be cleaned up a fair bit.
1853 def convert_subfig(document):
1854     " Convert subfigures to subfloats. "
1855     i = 0
1856     while 1:
1857         i = find_token(document.body, '\\begin_inset Graphics', i)
1858         if i == -1:
1859             return
1860         endInset = find_end_of_inset(document.body, i)
1861         if endInset == -1:
1862             document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
1863             i += 1
1864             continue
1865         k = find_token(document.body, '\tsubcaption', i, endInset)
1866         if k == -1:
1867             i += 1
1868             continue
1869         l = find_token(document.body, '\tsubcaptionText', i, endInset)
1870         caption = document.body[l][16:].strip('"')
1871         savestr = document.body[i]
1872         laststr = document.body[endInset]
1873         del document.body[l]
1874         del document.body[k]
1875         addedLines = -2
1876         # savestr should no longer be needed here.
1877         subst = ['\\begin_inset Float figure', 'wide false', 'sideways false', 
1878                  'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption', 
1879                  '', '\\begin_layout Plain Layout',
1880                  caption, '\\end_layout', '', '\\end_inset', '', 
1881                  '\\end_layout', '', '\\begin_layout Plain Layout', savestr]
1882         document.body[i : i+1] = subst
1883         addedLines += len(subst) - 1
1884         endInset += addedLines
1885         # There should be an easier way to do this.
1886         subst = ['', '\\end_inset', '', '\\end_layout', laststr]
1887         document.body[endInset : endInset+1] = subst
1888         addedLines += len(subst) - 1
1889         i += addedLines + 1
1890
1891
1892 def revert_subfig(document):
1893     " Revert subfloats. "
1894     i = 0
1895     while 1:
1896         # whitespace intended (exclude \\begin_inset FloatList)
1897         i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
1898         if i == -1:
1899             return
1900         j = 0
1901         addedLines = 0
1902         while j != -1:
1903             j = find_end_of_inset(document.body, i)
1904             if j == -1:
1905                 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
1906                 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
1907                 i += 1
1908                 continue # this will get us back to the outer loop, since j == -1
1909             # look for embedded float (= subfloat)
1910             # whitespace intended (exclude \\begin_inset FloatList)
1911             k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
1912             if k == -1:
1913                 break
1914             l = find_end_of_inset(document.body, k)
1915             if l == -1:
1916                 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
1917                 i += 1
1918                 j == -1
1919                 continue # escape to the outer loop
1920             m = find_default_layout(document, k + 1, l)
1921             # caption?
1922             cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
1923             caption = ''
1924             shortcap = ''
1925             capend = cap
1926             if cap != -1:
1927                 capend = find_end_of_inset(document.body, cap)
1928                 if capend == -1:
1929                     document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
1930                     return
1931                 # label?
1932                 label = ''
1933                 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
1934                 if lbl != -1:
1935                     lblend = find_end_of_inset(document.body, lbl + 1)
1936                     if lblend == -1:
1937                         document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
1938                         return
1939                     for line in document.body[lbl:lblend + 1]:
1940                         if line.startswith('name '):
1941                             label = line.split()[1].strip('"')
1942                             break
1943                 else:
1944                     lbl = capend
1945                     lblend = capend
1946                     label = ''
1947                 # opt arg?
1948                 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
1949                 if opt != -1:
1950                     optend = find_end_of_inset(document.body, opt)
1951                     if optend == -1:
1952                         document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
1953                         return
1954                     optc = find_default_layout(document, opt, optend)
1955                     if optc == -1:
1956                         document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1957                         return
1958                     optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
1959                     for line in document.body[optc:optcend]:
1960                         if not line.startswith('\\'):
1961                             shortcap += line.strip()
1962                 else:
1963                     opt = capend
1964                     optend = capend
1965                 for line in document.body[cap:capend]:
1966                     if line in document.body[lbl:lblend]:
1967                         continue
1968                     elif line in document.body[opt:optend]:
1969                         continue
1970                     elif not line.startswith('\\'):
1971                         caption += line.strip()
1972                 if len(label) > 0:
1973                     caption += "\\backslash\nlabel{" + label + "}"
1974             subst = '\\begin_layout Plain Layout\n\\begin_inset ERT\nstatus collapsed\n\n' \
1975                       '\\begin_layout Plain Layout\n\n}\n\\end_layout\n\n\\end_inset\n\n' \
1976                       '\\end_layout\n\n\\begin_layout Plain Layout\n'
1977             subst = subst.split('\n')
1978             document.body[l : l+1] = subst
1979             addedLines = len(subst) - 1
1980             # this is before l and so is unchanged by the multiline insertion
1981             if cap != capend:
1982                 del document.body[cap:capend+1]
1983                 addedLines -= (capend + 1 - cap)
1984             del document.body[k+1:m-1]
1985             addedLines -= (m - 1 - (k + 1))
1986             insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
1987                         '\\begin_layout Plain Layout\n\n\\backslash\n' \
1988                         'subfloat'
1989             if len(shortcap) > 0:
1990                 insertion = insertion + "[" + shortcap + "]"
1991             if len(caption) > 0:
1992                 insertion = insertion + "[" + caption + "]"
1993             insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
1994             insertion = insertion.split('\n')
1995             document.body[k : k + 1] = insertion
1996             addedLines += len(insertion) - 1
1997             add_to_preamble(document,
1998                             ['\\usepackage{subfig}\n'])
1999         i += addedLines + 1
2000
2001
2002 def revert_wrapplacement(document):
2003     " Revert placement options wrap floats (wrapfig). "
2004     i = 0
2005     while True:
2006         i = find_token(document.body, "\\begin_inset Wrap figure", i)
2007         if i == -1:
2008             return
2009         e = find_end_of_inset(document.body, i)
2010         j = find_token(document.body, "placement", i + 1, e)
2011         if j == -1:
2012             document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2013             i += 1
2014             continue
2015         r = re.compile("placement (o|i|l|r)")
2016         m = r.match(document.body[j])
2017         if m == None:
2018             document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2019         document.body[j] = "placement " + m.group(1).lower()
2020         i = j
2021
2022
2023 def remove_extra_embedded_files(document):
2024     " Remove \extra_embedded_files from buffer params "
2025     i = find_token(document.header, '\\extra_embedded_files', 0)
2026     if i == -1:
2027         return
2028     document.header.pop(i)
2029
2030
2031 def convert_spaceinset(document):
2032     " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2033     i = 0
2034     while i < len(document.body):
2035         m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2036         if m:
2037             before = m.group(1)
2038             after = m.group(2)
2039             subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2040             document.body[i: i+1] = subst
2041             i = i + len(subst)
2042         else:
2043             i = i + 1
2044
2045
2046 def revert_spaceinset(document):
2047     " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2048     i = 0
2049     while True:
2050         i = find_token(document.body, "\\begin_inset Space", i)
2051         if i == -1:
2052             return
2053         j = find_end_of_inset(document.body, i)
2054         if j == -1:
2055             document.warning("Malformed LyX document: Could not find end of space inset.")
2056             continue
2057         document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2058         del document.body[j]
2059
2060
2061 def convert_hfill(document):
2062     " Convert hfill to space inset "
2063     i = 0
2064     while True:
2065         i = find_token(document.body, "\\hfill", i)
2066         if i == -1:
2067             return
2068         subst = document.body[i].replace('\\hfill', \
2069                   '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2070         subst = subst.split('\n')
2071         document.body[i : i+1] = subst
2072         i += len(subst)
2073
2074
2075 def revert_hfills(document):
2076     ' Revert \\hfill commands '
2077     hfill = re.compile(r'\\hfill')
2078     dotfill = re.compile(r'\\dotfill')
2079     hrulefill = re.compile(r'\\hrulefill')
2080     i = 0
2081     while True:
2082         i = find_token(document.body, "\\InsetSpace", i)
2083         if i == -1:
2084             return
2085         if hfill.search(document.body[i]):
2086             document.body[i] = \
2087               document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2088             i += 1
2089             continue
2090         if dotfill.search(document.body[i]):
2091             subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2092               '\\begin_inset ERT\nstatus collapsed\n\n' \
2093               '\\begin_layout Standard\n\n\n\\backslash\n' \
2094               'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2095             subst = subst.split('\n')
2096             document.body[i : i+1] = subst
2097             i += len(subst)
2098             continue
2099         if hrulefill.search(document.body[i]):
2100             subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2101               '\\begin_inset ERT\nstatus collapsed\n\n' \
2102               '\\begin_layout Standard\n\n\n\\backslash\n' \
2103               'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2104             subst = subst.split('\n')
2105             document.body[i : i+1] = subst
2106             i += len(subst)
2107             continue
2108         i += 1
2109
2110 def revert_hspace(document):
2111     ' Revert \\InsetSpace \\hspace{} to ERT '
2112     i = 0
2113     hspace = re.compile(r'\\hspace{}')
2114     hstar  = re.compile(r'\\hspace\*{}')
2115     while True:
2116         i = find_token(document.body, "\\InsetSpace \\hspace", i)
2117         if i == -1:
2118             return
2119         length = get_value(document.body, '\\length', i+1)
2120         if length == '':
2121             document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2122             return
2123         del document.body[i+1]
2124         addedLines = -1
2125         if hstar.search(document.body[i]):
2126             subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2127               '\\begin_inset ERT\nstatus collapsed\n\n' \
2128               '\\begin_layout Standard\n\n\n\\backslash\n' \
2129               'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2130             subst = subst.split('\n')
2131             document.body[i : i+1] = subst
2132             addedLines += len(subst) - 1
2133             i += addedLines + 1
2134             continue
2135         if hspace.search(document.body[i]):
2136             subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2137               '\\begin_inset ERT\nstatus collapsed\n\n' \
2138               '\\begin_layout Standard\n\n\n\\backslash\n' \
2139               'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2140             subst = subst.split('\n')
2141             document.body[i : i+1] = subst
2142             addedLines += len(subst) - 1
2143             i += addedLines + 1
2144             continue
2145         i += 1
2146
2147
2148 def revert_protected_hfill(document):
2149     ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2150     i = 0
2151     while True:
2152         i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2153         if i == -1:
2154             return
2155         j = find_end_of_inset(document.body, i)
2156         if j == -1:
2157             document.warning("Malformed LyX document: Could not find end of space inset.")
2158             continue
2159         del document.body[j]
2160         subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2161           '\\begin_inset ERT\nstatus collapsed\n\n' \
2162           '\\begin_layout Standard\n\n\n\\backslash\n' \
2163           'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2164         subst = subst.split('\n')
2165         document.body[i : i+1] = subst
2166         i += len(subst)
2167
2168
2169 def revert_leftarrowfill(document):
2170     ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2171     i = 0
2172     while True:
2173         i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2174         if i == -1:
2175             return
2176         j = find_end_of_inset(document.body, i)
2177         if j == -1:
2178             document.warning("Malformed LyX document: Could not find end of space inset.")
2179             continue
2180         del document.body[j]
2181         subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2182           '\\begin_inset ERT\nstatus collapsed\n\n' \
2183           '\\begin_layout Standard\n\n\n\\backslash\n' \
2184           'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2185         subst = subst.split('\n')
2186         document.body[i : i+1] = subst
2187         i += len(subst)
2188
2189
2190 def revert_rightarrowfill(document):
2191     ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2192     i = 0
2193     while True:
2194         i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2195         if i == -1:
2196             return
2197         j = find_end_of_inset(document.body, i)
2198         if j == -1:
2199             document.warning("Malformed LyX document: Could not find end of space inset.")
2200             continue
2201         del document.body[j]
2202         subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2203           '\\begin_inset ERT\nstatus collapsed\n\n' \
2204           '\\begin_layout Standard\n\n\n\\backslash\n' \
2205           'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2206         subst = subst.split('\n')
2207         document.body[i : i+1] = subst
2208         i += len(subst)
2209
2210
2211 def revert_upbracefill(document):
2212     ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2213     i = 0
2214     while True:
2215         i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2216         if i == -1:
2217             return
2218         j = find_end_of_inset(document.body, i)
2219         if j == -1:
2220             document.warning("Malformed LyX document: Could not find end of space inset.")
2221             continue
2222         del document.body[j]
2223         subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2224           '\\begin_inset ERT\nstatus collapsed\n\n' \
2225           '\\begin_layout Standard\n\n\n\\backslash\n' \
2226           'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2227         subst = subst.split('\n')
2228         document.body[i : i+1] = subst
2229         i += len(subst)
2230
2231
2232 def revert_downbracefill(document):
2233     ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2234     i = 0
2235     while True:
2236         i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2237         if i == -1:
2238             return
2239         j = find_end_of_inset(document.body, i)
2240         if j == -1:
2241             document.warning("Malformed LyX document: Could not find end of space inset.")
2242             continue
2243         del document.body[j]
2244         subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2245           '\\begin_inset ERT\nstatus collapsed\n\n' \
2246           '\\begin_layout Standard\n\n\n\\backslash\n' \
2247           'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2248         subst = subst.split('\n')
2249         document.body[i : i+1] = subst
2250         i += len(subst)
2251
2252
2253 def revert_local_layout(document):
2254     ' Revert local layout headers.'
2255     i = 0
2256     while True:
2257         i = find_token(document.header, "\\begin_local_layout", i)
2258         if i == -1:
2259             return
2260         j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2261         if j == -1:
2262             # this should not happen
2263             break
2264         document.header[i : j + 1] = []
2265
2266
2267 def convert_pagebreaks(document):
2268     ' Convert inline Newpage insets to new format '
2269     i = 0
2270     while True:
2271         i = find_token(document.body, '\\newpage', i)
2272         if i == -1:
2273             break
2274         document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2275                                 '\\end_inset']
2276     i = 0
2277     while True:
2278         i = find_token(document.body, '\\pagebreak', i)
2279         if i == -1:
2280             break
2281         document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2282                                 '\\end_inset']
2283     i = 0
2284     while True:
2285         i = find_token(document.body, '\\clearpage', i)
2286         if i == -1:
2287             break
2288         document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2289                                 '\\end_inset']
2290     i = 0
2291     while True:
2292         i = find_token(document.body, '\\cleardoublepage', i)
2293         if i == -1:
2294             break
2295         document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2296                                 '\\end_inset']
2297
2298
2299 def revert_pagebreaks(document):
2300     ' Revert \\begin_inset Newpage to previous inline format '
2301     i = 0
2302     while True:
2303         i = find_token(document.body, '\\begin_inset Newpage', i)
2304         if i == -1:
2305             return
2306         j = find_end_of_inset(document.body, i)
2307         if j == -1:
2308             document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2309             continue
2310         del document.body[j]
2311         document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2312         document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2313         document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2314         document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2315
2316
2317 def convert_linebreaks(document):
2318     ' Convert inline Newline insets to new format '
2319     i = 0
2320     while True:
2321         i = find_token(document.body, '\\newline', i)
2322         if i == -1:
2323             break
2324         document.body[i:i+1] = ['\\begin_inset Newline newline',
2325                                 '\\end_inset']
2326     i = 0
2327     while True:
2328         i = find_token(document.body, '\\linebreak', i)
2329         if i == -1:
2330             break
2331         document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2332                                 '\\end_inset']
2333
2334
2335 def revert_linebreaks(document):
2336     ' Revert \\begin_inset Newline to previous inline format '
2337     i = 0
2338     while True:
2339         i = find_token(document.body, '\\begin_inset Newline', i)
2340         if i == -1:
2341             return
2342         j = find_end_of_inset(document.body, i)
2343         if j == -1:
2344             document.warning("Malformed LyX document: Could not find end of Newline inset.")
2345             continue
2346         del document.body[j]
2347         document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2348         document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2349
2350
2351 def convert_japanese_plain(document):
2352     ' Set language japanese-plain to japanese '
2353     i = 0
2354     if document.language == "japanese-plain":
2355         document.language = "japanese"
2356         i = find_token(document.header, "\\language", 0)
2357         if i != -1:
2358             document.header[i] = "\\language japanese"
2359     j = 0
2360     while True:
2361         j = find_token(document.body, "\\lang japanese-plain", j)
2362         if j == -1:
2363             return
2364         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2365         j = j + 1
2366
2367
2368 def revert_pdfpages(document):
2369     ' Revert pdfpages external inset to ERT '
2370     i = 0
2371     while 1:
2372         i = find_token(document.body, "\\begin_inset External", i)
2373         if i == -1:
2374             return
2375         j = find_end_of_inset(document.body, i)
2376         if j == -1:
2377             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2378             i = i + 1
2379             continue
2380         if get_value(document.body, 'template', i, j) == "PDFPages":
2381             filename = get_value(document.body, 'filename', i, j)
2382             extra = ''
2383             r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2384             for k in range(i, j):
2385                 m = r.match(document.body[k])
2386                 if m:
2387                     extra = m.group(1)
2388             angle = get_value(document.body, 'rotateAngle', i, j)
2389             width = get_value(document.body, 'width', i, j)
2390             height = get_value(document.body, 'height', i, j)
2391             scale = get_value(document.body, 'scale', i, j)
2392             keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2393             options = extra
2394             if angle != '':
2395                  if options != '':
2396                      options += ",angle=" + angle
2397                  else:
2398                      options += "angle=" + angle
2399             if width != '':
2400                  if options != '':
2401                      options += ",width=" + convert_len(width)
2402                  else:
2403                      options += "width=" + convert_len(width)
2404             if height != '':
2405                  if options != '':
2406                      options += ",height=" + convert_len(height)
2407                  else:
2408                      options += "height=" + convert_len(height)
2409             if scale != '':
2410                  if options != '':
2411                      options += ",scale=" + scale
2412                  else:
2413                      options += "scale=" + scale
2414             if keepAspectRatio != '':
2415                  if options != '':
2416                      options += ",keepaspectratio"
2417                  else:
2418                      options += "keepaspectratio"
2419             if options != '':
2420                      options = '[' + options + ']'
2421             del document.body[i+1:j+1]
2422             document.body[i:i+1] = ['\\begin_inset ERT',
2423                                 'status collapsed',
2424                                 '',
2425                                 '\\begin_layout Standard',
2426                                 '',
2427                                 '\\backslash',
2428                                 'includepdf' + options + '{' + filename + '}',
2429                                 '\\end_layout',
2430                                 '',
2431                                 '\\end_inset']
2432             add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2433             i = i + 1
2434             continue
2435         i = i + 1
2436
2437
2438 def revert_mexican(document):
2439     ' Set language Spanish(Mexico) to Spanish '
2440     i = 0
2441     if document.language == "spanish-mexico":
2442         document.language = "spanish"
2443         i = find_token(document.header, "\\language", 0)
2444         if i != -1:
2445             document.header[i] = "\\language spanish"
2446     j = 0
2447     while True:
2448         j = find_token(document.body, "\\lang spanish-mexico", j)
2449         if j == -1:
2450             return
2451         document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2452         j = j + 1
2453
2454
2455 def remove_embedding(document):
2456     ' Remove embed tag from all insets '
2457     revert_inset_embedding(document, 'Graphics')
2458     revert_inset_embedding(document, 'External')
2459     revert_inset_embedding(document, 'CommandInset include')
2460     revert_inset_embedding(document, 'CommandInset bibtex')
2461
2462
2463 def revert_master(document):
2464     ' Remove master param '
2465     i = find_token(document.header, "\\master", 0)
2466     if i != -1:
2467         del document.header[i]
2468
2469
2470 def revert_graphics_group(document):
2471     ' Revert group information from graphics insets '
2472     i = 0
2473     while 1:
2474         i = find_token(document.body, "\\begin_inset Graphics", i)
2475         if i == -1:
2476             return
2477         j = find_end_of_inset(document.body, i)
2478         if j == -1:
2479             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2480             i = i + 1
2481             continue
2482         k = find_token(document.body, " groupId", i, j)
2483         if k == -1:
2484             i = i + 1
2485             continue
2486         del document.body[k]
2487         i = i + 1
2488
2489
2490 def update_apa_styles(document):
2491     ' Replace obsolete styles '
2492
2493     if document.textclass != "apa":
2494         return
2495
2496     obsoletedby = { "Acknowledgments": "Acknowledgements",
2497                     "Section*":        "Section",
2498                     "Subsection*":     "Subsection",
2499                     "Subsubsection*":  "Subsubsection",
2500                     "Paragraph*":      "Paragraph",
2501                     "Subparagraph*":   "Subparagraph"}
2502     i = 0
2503     while 1:
2504         i = find_token(document.body, "\\begin_layout", i)
2505         if i == -1:
2506             return
2507
2508         layout = document.body[i][14:]
2509         if layout in obsoletedby:
2510             document.body[i] = "\\begin_layout " + obsoletedby[layout]
2511
2512         i += 1
2513
2514
2515 def convert_paper_sizes(document):
2516     ' exchange size options legalpaper and executivepaper to correct order '
2517     # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2518     i = 0
2519     j = 0
2520     i = find_token(document.header, "\\papersize executivepaper", 0)
2521     if i != -1:
2522         document.header[i] = "\\papersize legalpaper"
2523         return
2524     j = find_token(document.header, "\\papersize legalpaper", 0)
2525     if j != -1:
2526         document.header[j] = "\\papersize executivepaper"
2527
2528
2529 def revert_paper_sizes(document):
2530     ' exchange size options legalpaper and executivepaper to correct order '
2531     i = 0
2532     j = 0
2533     i = find_token(document.header, "\\papersize executivepaper", 0)
2534     if i != -1:
2535         document.header[i] = "\\papersize legalpaper"
2536         return
2537     j = find_token(document.header, "\\papersize legalpaper", 0)
2538     if j != -1:
2539         document.header[j] = "\\papersize executivepaper"
2540
2541
2542 def convert_InsetSpace(document):
2543     " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2544     i = 0
2545     while True:
2546         i = find_token(document.body, "\\begin_inset Space", i)
2547         if i == -1:
2548             return
2549         document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2550
2551
2552 def revert_InsetSpace(document):
2553     " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2554     i = 0
2555     while True:
2556         i = find_token(document.body, "\\begin_inset space", i)
2557         if i == -1:
2558             return
2559         document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2560
2561
2562 def convert_display_enum(document):
2563     " Convert 'display foo' to 'display false/true'"
2564     i = 0
2565     while True:
2566         i = find_token(document.body, "\tdisplay", i)
2567         if i == -1:
2568             return
2569         val = get_value(document.body, 'display', i)
2570         if val == "none":
2571             document.body[i] = document.body[i].replace('none', 'false')
2572         if val == "default":
2573             document.body[i] = document.body[i].replace('default', 'true')
2574         if val == "monochrome":
2575             document.body[i] = document.body[i].replace('monochrome', 'true')
2576         if val == "grayscale":
2577             document.body[i] = document.body[i].replace('grayscale', 'true')
2578         if val == "color":
2579             document.body[i] = document.body[i].replace('color', 'true')
2580         if val == "preview":
2581             document.body[i] = document.body[i].replace('preview', 'true')
2582         i += 1
2583
2584
2585 def revert_display_enum(document):
2586     " Revert 'display false/true' to 'display none/color'"
2587     i = 0
2588     while True:
2589         i = find_token(document.body, "\tdisplay", i)
2590         if i == -1:
2591             return
2592         val = get_value(document.body, 'display', i)
2593         if val == "false":
2594             document.body[i] = document.body[i].replace('false', 'none')
2595         if val == "true":
2596             document.body[i] = document.body[i].replace('true', 'default')
2597         i += 1
2598
2599
2600 def remove_fontsCJK(document):
2601     ' Remove font_cjk param '
2602     i = find_token(document.header, "\\font_cjk", 0)
2603     if i != -1:
2604         del document.header[i]
2605
2606
2607 def convert_plain_layout(document):
2608     " Convert 'PlainLayout' to 'Plain Layout'" 
2609     i = 0
2610     while True:
2611         i = find_token(document.body, '\\begin_layout PlainLayout', i)
2612         if i == -1:
2613             return
2614         document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2615           '\\begin_layout Plain Layout')
2616         i += 1
2617
2618
2619 def revert_plain_layout(document):
2620     " Convert 'PlainLayout' to 'Plain Layout'" 
2621     i = 0
2622     while True:
2623         i = find_token(document.body, '\\begin_layout Plain Layout', i)
2624         if i == -1:
2625             return
2626         document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2627           '\\begin_layout PlainLayout')
2628         i += 1
2629
2630
2631 def revert_plainlayout(document):
2632     " Convert 'PlainLayout' to 'Plain Layout'" 
2633     i = 0
2634     while True:
2635         i = find_token(document.body, '\\begin_layout PlainLayout', i)
2636         if i == -1:
2637             return
2638         # This will be incorrect for some document classes, since Standard is not always
2639         # the default. But (a) it is probably the best we can do and (b) it will actually
2640         # work, in fact, since an unknown layout will be converted to default.
2641         document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2642           '\\begin_layout Standard')
2643         i += 1
2644
2645
2646 def revert_polytonicgreek(document):
2647     "Set language polytonic Greek to Greek"
2648     i = 0
2649     if document.language == "polutonikogreek":
2650         document.language = "greek"
2651         i = find_token(document.header, "\\language", 0)
2652         if i != -1:
2653             document.header[i] = "\\language greek"
2654     j = 0
2655     while True:
2656         j = find_token(document.body, "\\lang polutonikogreek", j)
2657         if j == -1:
2658             return
2659         document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2660         j = j + 1
2661
2662
2663 ##
2664 # Conversion hub
2665 #
2666
2667 supported_versions = ["1.6.0","1.6"]
2668 convert = [[277, [fix_wrong_tables]],
2669            [278, [close_begin_deeper]],
2670            [279, [long_charstyle_names]],
2671            [280, [axe_show_label]],
2672            [281, []],
2673            [282, []],
2674            [283, [convert_flex]],
2675            [284, []],
2676            [285, []],
2677            [286, []],
2678            [287, [convert_wrapfig_options]],
2679            [288, [convert_inset_command]],
2680            [289, [convert_latexcommand_index]],
2681            [290, []],
2682            [291, []],
2683            [292, []],
2684            [293, []],
2685            [294, [convert_pdf_options]],
2686            [295, [convert_htmlurl, convert_url]],
2687            [296, [convert_include]],
2688            [297, [convert_usorbian]],
2689            [298, []],
2690            [299, []],
2691            [300, []],
2692            [301, []],
2693            [302, []],
2694            [303, [convert_serbocroatian]],
2695            [304, [convert_framed_notes]],
2696            [305, []],
2697            [306, []],
2698            [307, []],
2699            [308, []],
2700            [309, []],
2701            [310, []],
2702            [311, [convert_ams_classes]],
2703            [312, []],
2704            [313, [convert_module_names]],
2705            [314, []],
2706            [315, []],
2707            [316, [convert_subfig]],
2708            [317, []],
2709            [318, []],
2710            [319, [convert_spaceinset, convert_hfill]],
2711            [320, []],
2712            [321, [convert_tablines]],
2713            [322, [convert_plain_layout]],
2714            [323, [convert_pagebreaks]],
2715            [324, [convert_linebreaks]],
2716            [325, [convert_japanese_plain]],
2717            [326, []],
2718            [327, []],
2719            [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
2720            [329, []],
2721            [330, []],
2722            [331, [convert_ltcaption]],
2723            [332, []],
2724            [333, [update_apa_styles]],
2725            [334, [convert_paper_sizes]],
2726            [335, [convert_InsetSpace]],
2727            [336, []],
2728            [337, [convert_display_enum]],
2729            [338, []],
2730           ]
2731
2732 revert =  [[337, [revert_polytonicgreek]],
2733            [336, [revert_display_enum]],
2734            [335, [remove_fontsCJK]],
2735            [334, [revert_InsetSpace]],
2736            [333, [revert_paper_sizes]],
2737            [332, []],
2738            [331, [revert_graphics_group]],
2739            [330, [revert_ltcaption]],
2740            [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
2741            [328, [revert_master]],
2742            [327, []],
2743            [326, [revert_mexican]],
2744            [325, [revert_pdfpages]],
2745            [324, []],
2746            [323, [revert_linebreaks]],
2747            [322, [revert_pagebreaks]],
2748            [321, [revert_local_layout, revert_plain_layout]],
2749            [320, [revert_tablines]],
2750            [319, [revert_protected_hfill]],
2751            [318, [revert_spaceinset, revert_hfills, revert_hspace]],
2752            [317, [remove_extra_embedded_files]],
2753            [316, [revert_wrapplacement]],
2754            [315, [revert_subfig]],
2755            [314, [revert_colsep, revert_plainlayout]],
2756            [313, []],
2757            [312, [revert_module_names]],
2758            [311, [revert_rotfloat, revert_widesideways]],
2759            [310, [revert_external_embedding]],
2760            [309, [revert_btprintall]],
2761            [308, [revert_nocite]],
2762            [307, [revert_serbianlatin]],
2763            [306, [revert_slash, revert_nobreakdash]],
2764            [305, [revert_interlingua]],
2765            [304, [revert_bahasam]],
2766            [303, [revert_framed_notes]],
2767            [302, []],
2768            [301, [revert_latin, revert_samin]],
2769            [300, [revert_linebreak]],
2770            [299, [revert_pagebreak]],
2771            [298, [revert_hyperlinktype]],
2772            [297, [revert_macro_optional_params]],
2773            [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
2774            [295, [revert_include]],
2775            [294, [revert_href, revert_url]],
2776            [293, [revert_pdf_options_2]],
2777            [292, [revert_inset_info]],
2778            [291, [revert_japanese, revert_japanese_encoding]],
2779            [290, [revert_vietnamese]],
2780            [289, [revert_wraptable]],
2781            [288, [revert_latexcommand_index]],
2782            [287, [revert_inset_command]],
2783            [286, [revert_wrapfig_options]],
2784            [285, [revert_pdf_options]],
2785            [284, [remove_inzip_options]],
2786            [283, []],
2787            [282, [revert_flex]],
2788            [281, []],
2789            [280, [revert_begin_modules]],
2790            [279, [revert_show_label]],
2791            [278, [revert_long_charstyle_names]],
2792            [277, []],
2793            [276, []]
2794           ]
2795
2796
2797 if __name__ == "__main__":
2798     pass