]> git.lyx.org Git - features.git/blob - lib/lyx2lyx/lyx_1_6.py
Cosmetics, mostly.
[features.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     r1 = re.compile('name "(.*)"')
799     r2 = re.compile('^(.*?)(\$.*?\$)(.*)')
800     while True:
801         i = find_token(document.body, "\\begin_inset CommandInset index", i)
802         if i == -1:
803             return
804         if document.body[i + 1] != "LatexCommand index": # Might also be index_print
805             return
806         m = r1.match(document.body[i + 2])
807         if m == None:
808             document.warning("Unable to match: " + document.body[i+2])
809             i += 1
810             continue
811         fullcontent = m.group(1)
812         document.body[i:i + 3] = ["\\begin_inset Index",
813           "status collapsed",
814           "\\begin_layout Standard"]
815         i += 3
816         # We are now on the blank line preceding "\end_inset"
817         # We will write the content here, into the inset.
818
819         # Do the LaTeX --> LyX text conversion
820         for rep in replacements:
821             fullcontent = fullcontent.replace(rep[0], rep[1])
822         # Generic, \" -> ":
823         fullcontent = wrap_into_ert(fullcontent, r'\"', '"')
824         # Math:
825         lines = fullcontent.split('\n')
826         for line in lines:
827             #document.warning("LINE: " + line)
828             #document.warning(str(i) + ":" + document.body[i])
829             #document.warning("LAST: " + document.body[-1])
830             g = line
831             while r2.match(g):
832                 m = r2.match(g)
833                 s = m.group(1)
834                 f = m.group(2).replace('\\\\', '\\')
835                 g = m.group(3)
836                 if s:
837                   # this is non-math!
838                   s = wrap_into_ert(s, r'\\', '\\backslash')
839                   s = wrap_into_ert(s, '{', '{')
840                   s = wrap_into_ert(s, '}', '}')
841                   subst = s.split('\n')
842                   document.body[i:i] = subst
843                   i += len(subst)
844                 document.body.insert(i + 1, "\\begin_inset Formula " + f)
845                 document.body.insert(i + 2, "\\end_inset")
846                 i += 2
847             # Generic, \\ -> \backslash:
848             g = wrap_into_ert(g, r'\\', '\\backslash')
849             g = wrap_into_ert(g, '{', '{')
850             g = wrap_into_ert(g, '}', '}')
851             subst = g.split('\n')
852             document.body[i+1:i+1] = subst
853             i += len(subst)
854         document.body.insert(i + 1, "\\end_layout")
855
856
857 def revert_latexcommand_index(document):
858     "Revert from collapsable form to LatexCommand form."
859     i = 0
860     while True:
861         i = find_token(document.body, "\\begin_inset Index", i)
862         if i == -1:
863           return
864         j = find_end_of_inset(document.body, i + 1)
865         if j == -1:
866           return
867         del document.body[j - 1]
868         del document.body[j - 2] # \end_layout
869         document.body[i] =  "\\begin_inset CommandInset index"
870         document.body[i + 1] =  "LatexCommand index"
871         # clean up multiline stuff
872         content = ""
873         ert_end = 0
874         for k in range(i + 3, j - 2):
875           line = document.body[k]
876           if line.startswith("\\begin_inset ERT"):
877               ert_end = find_end_of_inset(document.body, k + 1)
878               line = line[16:]
879           if line.startswith("\\begin_inset Formula"):
880             line = line[20:]
881           if line.startswith("\\begin_layout Standard"):
882             line = line[22:]
883           if line.startswith("\\begin_layout Plain Layout"):
884             line = line[26:]
885           if line.startswith("\\end_layout"):
886             line = line[11:]
887           if line.startswith("\\end_inset"):
888             line = line[10:]
889           if line.startswith("status collapsed"):
890             line = line[16:]
891           if line.startswith("status open"):
892             line = line[11:]
893           # a lossless reversion is not possible
894           # try at least to handle some common insets and settings
895           # do not replace inside ERTs
896           if ert_end < k:
897               # Do the LyX text --> LaTeX conversion
898               for rep in replacements:
899                 line = line.replace(rep[1], rep[0])
900               line = line.replace(r'\backslash', r'\textbackslash{}')
901               line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
902               line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
903               line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
904               line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
905               line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
906               line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
907               line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
908               line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
909               line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
910           else:
911               line = line.replace(r'\backslash', r'\\')
912           content = content + line;
913         document.body[i + 3] = "name " + '"' + content + '"'
914         for k in range(i + 4, j - 2):
915           del document.body[i + 4]
916         document.body.insert(i + 4, "")
917         del document.body[i + 2] # \begin_layout standard
918         i = i + 5
919
920
921 def revert_wraptable(document):
922     "Revert wrap table to wrap figure."
923     i = 0
924     while True:
925         i = find_token(document.body, "\\begin_inset Wrap table", i)
926         if i == -1:
927             return
928         document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
929         i = i + 1
930
931
932 def revert_vietnamese(document):
933     "Set language Vietnamese to English"
934     # Set document language from Vietnamese to English
935     i = 0
936     if document.language == "vietnamese":
937         document.language = "english"
938         i = find_token(document.header, "\\language", 0)
939         if i != -1:
940             document.header[i] = "\\language english"
941     j = 0
942     while True:
943         j = find_token(document.body, "\\lang vietnamese", j)
944         if j == -1:
945             return
946         document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
947         j = j + 1
948
949
950 def revert_japanese(document):
951     "Set language japanese-plain to japanese"
952     # Set document language from japanese-plain to japanese
953     i = 0
954     if document.language == "japanese-plain":
955         document.language = "japanese"
956         i = find_token(document.header, "\\language", 0)
957         if i != -1:
958             document.header[i] = "\\language japanese"
959     j = 0
960     while True:
961         j = find_token(document.body, "\\lang japanese-plain", j)
962         if j == -1:
963             return
964         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
965         j = j + 1
966
967
968 def revert_japanese_encoding(document):
969     "Set input encoding form EUC-JP-plain to EUC-JP etc."
970     # Set input encoding form EUC-JP-plain to EUC-JP etc.
971     i = 0
972     i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
973     if i != -1:
974         document.header[i] = "\\inputencoding EUC-JP"
975     j = 0
976     j = find_token(document.header, "\\inputencoding JIS-plain", 0)
977     if j != -1:
978         document.header[j] = "\\inputencoding JIS"
979     k = 0
980     k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
981     if k != -1: # convert to UTF8 since there is currently no SJIS encoding
982         document.header[k] = "\\inputencoding UTF8"
983
984
985 def revert_inset_info(document):
986     'Replace info inset with its content'
987     i = 0
988     while 1:
989         i = find_token(document.body, '\\begin_inset Info', i)
990         if i == -1:
991             return
992         j = find_end_of_inset(document.body, i + 1)
993         if j == -1:
994             # should not happen
995             document.warning("Malformed LyX document: Could not find end of Info inset.")
996         type = 'unknown'
997         arg = ''
998         for k in range(i, j+1):
999             if document.body[k].startswith("arg"):
1000                 arg = document.body[k][3:].strip().strip('"')
1001             if document.body[k].startswith("type"):
1002                 type = document.body[k][4:].strip().strip('"')
1003         # I think there is a newline after \\end_inset, which should be removed.
1004         if document.body[j + 1].strip() == "":
1005             document.body[i : (j + 2)] = [type + ':' + arg]
1006         else:
1007             document.body[i : (j + 1)] = [type + ':' + arg]
1008
1009
1010 def convert_pdf_options(document):
1011     # Set the pdfusetitle tag, delete the pdf_store_options,
1012     # set quotes for bookmarksopenlevel"
1013     has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1014     if has_hr == "1":
1015         k = find_token(document.header, "\\use_hyperref", 0)
1016         document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1017     k = find_token(document.header, "\\pdf_store_options", 0)
1018     if k != -1:
1019         del document.header[k]
1020     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1021     if i == -1: return
1022     document.header[i] = document.header[i].replace('"', '')
1023
1024
1025 def revert_pdf_options_2(document):
1026     # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1027     k = find_token(document.header, "\\use_hyperref", 0)
1028     i = find_token(document.header, "\\pdf_pdfusetitle", k)
1029     if i != -1:
1030         del document.header[i]
1031     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1032     if i == -1: return
1033     values = document.header[i].split()
1034     values[1] = ' "' + values[1] + '"'
1035     document.header[i] = ''.join(values)
1036
1037
1038 def convert_htmlurl(document):
1039     'Convert "htmlurl" to "href" insets for docbook'
1040     if document.backend != "docbook":
1041       return
1042     i = 0
1043     while True:
1044       i = find_token(document.body, "\\begin_inset CommandInset url", i)
1045       if i == -1:
1046         return
1047       document.body[i] = "\\begin_inset CommandInset href"
1048       document.body[i + 1] = "LatexCommand href"
1049       i = i + 1
1050
1051
1052 def convert_url(document):
1053     'Convert url insets to url charstyles'
1054     if document.backend == "docbook":
1055       return
1056     i = 0
1057     while True:
1058       i = find_token(document.body, "\\begin_inset CommandInset url", i)
1059       if i == -1:
1060         break
1061       n = find_token(document.body, "name", i)
1062       if n == i + 2:
1063         # place the URL name in typewriter before the new URL insert
1064         # grab the name 'bla' from the e.g. the line 'name "bla"',
1065         # therefore start with the 6th character
1066         name = document.body[n][6:-1]
1067         newname = [name + " "]
1068         document.body[i:i] = newname
1069         i = i + 1
1070       j = find_token(document.body, "target", i)
1071       if j == -1:
1072         document.warning("Malformed LyX document: Can't find target for url inset")
1073         i = j
1074         continue
1075       target = document.body[j][8:-1]
1076       k = find_token(document.body, "\\end_inset", j)
1077       if k == -1:
1078         document.warning("Malformed LyX document: Can't find end of url inset")
1079         i = k
1080         continue
1081       newstuff = ["\\begin_inset Flex URL",
1082         "status collapsed", "",
1083         "\\begin_layout Standard",
1084         "",
1085         target,
1086         "\\end_layout",
1087         ""]
1088       document.body[i:k] = newstuff
1089       i = k
1090
1091 def convert_ams_classes(document):
1092   tc = document.textclass
1093   if (tc != "amsart" and tc != "amsart-plain" and
1094       tc != "amsart-seq" and tc != "amsbook"):
1095     return
1096   if tc == "amsart-plain":
1097     document.textclass = "amsart"
1098     document.set_textclass()
1099     document.add_module("Theorems (Starred)")
1100     return
1101   if tc == "amsart-seq":
1102     document.textclass = "amsart"
1103     document.set_textclass()
1104   document.add_module("Theorems (AMS)")
1105
1106   #Now we want to see if any of the environments in the extended theorems
1107   #module were used in this document. If so, we'll add that module, too.
1108   layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note",  \
1109     "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1110     "Assumption"]
1111
1112   r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1113   i = 0
1114   while True:
1115     i = find_token(document.body, "\\begin_layout", i)
1116     if i == -1:
1117       return
1118     m = r.match(document.body[i])
1119     if m == None:
1120       document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1121       i += 1
1122       continue
1123     m = m.group(1)
1124     if layouts.count(m) != 0:
1125       document.add_module("Theorems (AMS-Extended)")
1126       return
1127     i += 1
1128
1129 def revert_href(document):
1130     'Reverts hyperlink insets (href) to url insets (url)'
1131     i = 0
1132     while True:
1133       i = find_token(document.body, "\\begin_inset CommandInset href", i)
1134       if i == -1:
1135           return
1136       document.body[i : i + 2] = \
1137         ["\\begin_inset CommandInset url", "LatexCommand url"]
1138       i = i + 2
1139
1140 def revert_url(document):
1141     'Reverts Flex URL insets to old-style URL insets'
1142     i = 0
1143     while True:
1144         i = find_token(document.body, "\\begin_inset Flex URL", i)
1145         if i == -1:
1146             return
1147         j = find_end_of_inset(document.body, i)
1148         if j == -1:
1149             document.warning("Can't find end of inset in revert_url!")
1150             return
1151         k = find_default_layout(document, i, j)
1152         if k == -1:
1153             document.warning("Can't find default layout in revert_url!")
1154             i = j
1155             continue
1156         l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1157         if l == -1 or l >= j:
1158             document.warning("Can't find end of default layout in revert_url!")
1159             i = j
1160             continue
1161         # OK, so the inset's data is between lines k and l.
1162         data =  " ".join(document.body[k+1:l])
1163         data = data.strip()
1164         newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1165                     "", "\\end_inset"]
1166         document.body[i:j+1] = newinset
1167         i = i + len(newinset)
1168
1169
1170 def convert_include(document):
1171   'Converts include insets to new format.'
1172   i = 0
1173   r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1174   while True:
1175     i = find_token(document.body, "\\begin_inset Include", i)
1176     if i == -1:
1177       return
1178     line = document.body[i]
1179     previewline = document.body[i + 1]
1180     m = r.match(line)
1181     if m == None:
1182       document.warning("Unable to match line " + str(i) + " of body!")
1183       i += 1
1184       continue
1185     cmd = m.group(1)
1186     fn  = m.group(2)
1187     opt = m.group(3)
1188     insertion = ["\\begin_inset CommandInset include",
1189        "LatexCommand " + cmd, previewline,
1190        "filename \"" + fn + "\""]
1191     newlines = 2
1192     if opt:
1193       insertion.append("lstparams " + '"' + opt + '"')
1194       newlines += 1
1195     document.body[i : i + 2] = insertion
1196     i += newlines
1197
1198
1199 def revert_include(document):
1200   'Reverts include insets to old format.'
1201   i = 0
1202   r0 = re.compile('preview.*')
1203   r1 = re.compile('LatexCommand (.+)')
1204   r2 = re.compile('filename "(.+)"')
1205   r3 = re.compile('lstparams "(.*)"')
1206   while True:
1207     i = find_token(document.body, "\\begin_inset CommandInset include", i)
1208     if i == -1:
1209       return
1210     nextline = i + 1
1211     if r0.match(document.body[nextline]):
1212       previewline = document.body[nextline]
1213       nextline += 1
1214     else:
1215       previewline = ""
1216     m = r1.match(document.body[nextline])
1217     if m == None:
1218       document.warning("Malformed LyX document: No LatexCommand line for `" +
1219         document.body[i] + "' on line " + str(i) + ".")
1220       i += 1
1221       continue
1222     cmd = m.group(1)
1223     nextline += 1
1224     m = r2.match(document.body[nextline])
1225     if m == None:
1226       document.warning("Malformed LyX document: No filename line for `" + \
1227         document.body[i] + "' on line " + str(i) + ".")
1228       i += 2
1229       continue
1230     fn = m.group(1)
1231     nextline += 1
1232     options = ""
1233     if (cmd == "lstinputlisting"):
1234       m = r3.match(document.body[nextline])
1235       if m != None:
1236         options = m.group(1)
1237         numlines = 5
1238         nextline += 1
1239     newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1240     if options:
1241       newline += ("[" + options + "]")
1242     insertion = [newline]
1243     if previewline != "":
1244       insertion.append(previewline)
1245     document.body[i : nextline] = insertion
1246     i += 2
1247
1248
1249 def revert_albanian(document):
1250     "Set language Albanian to English"
1251     i = 0
1252     if document.language == "albanian":
1253         document.language = "english"
1254         i = find_token(document.header, "\\language", 0)
1255         if i != -1:
1256             document.header[i] = "\\language english"
1257     j = 0
1258     while True:
1259         j = find_token(document.body, "\\lang albanian", j)
1260         if j == -1:
1261             return
1262         document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1263         j = j + 1
1264
1265
1266 def revert_lowersorbian(document):
1267     "Set language lower Sorbian to English"
1268     i = 0
1269     if document.language == "lowersorbian":
1270         document.language = "english"
1271         i = find_token(document.header, "\\language", 0)
1272         if i != -1:
1273             document.header[i] = "\\language english"
1274     j = 0
1275     while True:
1276         j = find_token(document.body, "\\lang lowersorbian", j)
1277         if j == -1:
1278             return
1279         document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1280         j = j + 1
1281
1282
1283 def revert_uppersorbian(document):
1284     "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1285     i = 0
1286     if document.language == "uppersorbian":
1287         document.language = "usorbian"
1288         i = find_token(document.header, "\\language", 0)
1289         if i != -1:
1290             document.header[i] = "\\language usorbian"
1291     j = 0
1292     while True:
1293         j = find_token(document.body, "\\lang uppersorbian", j)
1294         if j == -1:
1295             return
1296         document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1297         j = j + 1
1298
1299
1300 def convert_usorbian(document):
1301     "Set language usorbian to uppersorbian"
1302     i = 0
1303     if document.language == "usorbian":
1304         document.language = "uppersorbian"
1305         i = find_token(document.header, "\\language", 0)
1306         if i != -1:
1307             document.header[i] = "\\language uppersorbian"
1308     j = 0
1309     while True:
1310         j = find_token(document.body, "\\lang usorbian", j)
1311         if j == -1:
1312             return
1313         document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1314         j = j + 1
1315
1316
1317 def revert_macro_optional_params(document):
1318     "Convert macro definitions with optional parameters into ERTs"
1319     # Stub to convert macro definitions with one or more optional parameters
1320     # into uninterpreted ERT insets
1321
1322
1323 def revert_hyperlinktype(document):
1324     'Reverts hyperlink type'
1325     i = 0
1326     j = 0
1327     while True:
1328       i = find_token(document.body, "target", i)
1329       if i == -1:
1330           return
1331       j = find_token(document.body, "type", i)
1332       if j == -1:
1333           return
1334       if j == i + 1:
1335           del document.body[j]
1336       i = i + 1
1337
1338
1339 def revert_pagebreak(document):
1340     'Reverts pagebreak to ERT'
1341     i = 0
1342     while True:
1343       i = find_token(document.body, "\\pagebreak", i)
1344       if i == -1:
1345           return
1346       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1347       '\\begin_layout Standard\n\n\n\\backslash\n' \
1348       'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1349       i = i + 1
1350
1351
1352 def revert_linebreak(document):
1353     'Reverts linebreak to ERT'
1354     i = 0
1355     while True:
1356       i = find_token(document.body, "\\linebreak", i)
1357       if i == -1:
1358           return
1359       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1360       '\\begin_layout Standard\n\n\n\\backslash\n' \
1361       'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1362       i = i + 1
1363
1364
1365 def revert_latin(document):
1366     "Set language Latin to English"
1367     i = 0
1368     if document.language == "latin":
1369         document.language = "english"
1370         i = find_token(document.header, "\\language", 0)
1371         if i != -1:
1372             document.header[i] = "\\language english"
1373     j = 0
1374     while True:
1375         j = find_token(document.body, "\\lang latin", j)
1376         if j == -1:
1377             return
1378         document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1379         j = j + 1
1380
1381
1382 def revert_samin(document):
1383     "Set language North Sami to English"
1384     i = 0
1385     if document.language == "samin":
1386         document.language = "english"
1387         i = find_token(document.header, "\\language", 0)
1388         if i != -1:
1389             document.header[i] = "\\language english"
1390     j = 0
1391     while True:
1392         j = find_token(document.body, "\\lang samin", j)
1393         if j == -1:
1394             return
1395         document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1396         j = j + 1
1397
1398
1399 def convert_serbocroatian(document):
1400     "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1401     i = 0
1402     if document.language == "serbocroatian":
1403         document.language = "croatian"
1404         i = find_token(document.header, "\\language", 0)
1405         if i != -1:
1406             document.header[i] = "\\language croatian"
1407     j = 0
1408     while True:
1409         j = find_token(document.body, "\\lang serbocroatian", j)
1410         if j == -1:
1411             return
1412         document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1413         j = j + 1
1414
1415
1416 def convert_framed_notes(document):
1417     "Convert framed notes to boxes. "
1418     i = 0
1419     while 1:
1420         i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1421         if i == -1:
1422             return
1423         subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1424                  'position "t"',
1425                  'hor_pos "c"',
1426                  'has_inner_box 0',
1427                  'inner_pos "t"', 
1428                  'use_parbox 0',
1429                  'width "100col%"',
1430                  'special "none"',
1431                  'height "1in"',
1432                  'height_special "totalheight"']
1433         document.body[i:i+1] = subst
1434         i = i + 9
1435
1436
1437 def convert_module_names(document):
1438   modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1439     'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1440     'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1441     'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1442     'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1443   modlist = document.get_module_list()
1444   if len(modlist) == 0:
1445     return
1446   newmodlist = []
1447   for mod in modlist:
1448     if modulemap.has_key(mod):
1449       newmodlist.append(modulemap[mod])
1450     else:
1451       document.warning("Can't find module %s in the module map!" % mod)
1452       newmodlist.append(mod)
1453   document.set_module_list(newmodlist)
1454
1455
1456 def revert_module_names(document):
1457   modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1458     'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1459     'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1460     'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1461     'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1462   modlist = document.get_module_list()
1463   if len(modlist) == 0:
1464     return
1465   newmodlist = []
1466   for mod in modlist:
1467     if modulemap.has_key(mod):
1468       newmodlist.append(modulemap[mod])
1469     else:
1470       document.warning("Can't find module %s in the module map!" % mod)
1471       newmodlist.append(mod)
1472   document.set_module_list(newmodlist)
1473
1474
1475 def revert_colsep(document):
1476     i = find_token(document.header, "\\columnsep", 0)
1477     if i == -1:
1478         return
1479     colsepline = document.header[i]
1480     r = re.compile(r'\\columnsep (.*)')
1481     m = r.match(colsepline)
1482     if not m:
1483         document.warning("Malformed column separation line!")
1484         return
1485     colsep = m.group(1)
1486     del document.header[i]
1487     #it seems to be safe to add the package even if it is already used
1488     pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1489
1490     add_to_preamble(document, pretext)
1491
1492
1493 def revert_framed_notes(document):
1494     "Revert framed boxes to notes. "
1495     i = 0
1496     while 1:
1497         i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1498
1499         if i == -1:
1500             return
1501         j = find_end_of_inset(document.body, i + 1)
1502         if j == -1:
1503             # should not happen
1504             document.warning("Malformed LyX document: Could not find end of Box inset.")
1505         k = find_token(document.body, "status", i + 1, j)
1506         if k == -1:
1507             document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1508             return
1509         status = document.body[k]
1510         l = find_default_layout(document, i + 1, j)
1511         if l == -1:
1512             document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1513             return
1514         m = find_token(document.body, "\\end_layout", i + 1, j)
1515         if m == -1:
1516             document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1517             return
1518         ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1519         pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1520         if ibox == -1 and pbox == -1:
1521             document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1522             del document.body[i+1:k]
1523         else:
1524             document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1525             subst1 = [document.body[l],
1526                       "\\begin_inset Note Shaded",
1527                       status,
1528                       '\\begin_layout Standard']
1529             document.body[l:l + 1] = subst1
1530             subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1531             document.body[m:m + 1] = subst2
1532         i = i + 1
1533
1534
1535 def revert_slash(document):
1536     'Revert \\SpecialChar \\slash{} to ERT'
1537     r = re.compile(r'\\SpecialChar \\slash{}')
1538     i = 0
1539     while i < len(document.body):
1540         m = r.match(document.body[i])
1541         if m:
1542           subst = ['\\begin_inset ERT',
1543                    'status collapsed', '',
1544                    '\\begin_layout Standard',
1545                    '', '', '\\backslash',
1546                    'slash{}',
1547                    '\\end_layout', '',
1548                    '\\end_inset', '']
1549           document.body[i: i+1] = subst
1550           i = i + len(subst)
1551         else:
1552           i = i + 1
1553
1554
1555 def revert_nobreakdash(document):
1556     'Revert \\SpecialChar \\nobreakdash- to ERT'
1557     i = 0
1558     while i < len(document.body):
1559         line = document.body[i]
1560         r = re.compile(r'\\SpecialChar \\nobreakdash-')
1561         m = r.match(line)
1562         if m:
1563             subst = ['\\begin_inset ERT',
1564                     'status collapsed', '',
1565                     '\\begin_layout Standard', '', '',
1566                     '\\backslash',
1567                     'nobreakdash-',
1568                     '\\end_layout', '',
1569                     '\\end_inset', '']
1570             document.body[i:i+1] = subst
1571             i = i + len(subst)
1572             j = find_token(document.header, "\\use_amsmath", 0)
1573             if j == -1:
1574                 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1575                 return
1576             document.header[j] = "\\use_amsmath 2"
1577         else:
1578             i = i + 1
1579
1580
1581 #Returns number of lines added/removed
1582 def revert_nocite_key(body, start, end):
1583     'key "..." -> \nocite{...}' 
1584     r = re.compile(r'^key "(.*)"')
1585     i = start
1586     j = end
1587     while i < j:
1588         m = r.match(body[i])
1589         if m:
1590             body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1591             j += 1     # because we added a line
1592             i += 2     # skip that line
1593         else:
1594             del body[i]
1595             j -= 1     # because we deleted a line
1596             # no need to change i, since it now points to the next line
1597     return j - end
1598
1599
1600 def revert_nocite(document):
1601     "Revert LatexCommand nocite to ERT"
1602     i = 0
1603     while 1:
1604         i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1605         if i == -1:
1606             return
1607         if (document.body[i+1] != "LatexCommand nocite"):
1608             # note that we already incremented i
1609             i = i + 1
1610             continue
1611         insetEnd = find_end_of_inset(document.body, i)
1612         if insetEnd == -1:
1613             #this should not happen
1614             document.warning("End of CommandInset citation not found in revert_nocite!")
1615             return
1616
1617         paramLocation = i + 2 #start of the inset's parameters
1618         addedLines = 0
1619         document.body[i:i+2] = \
1620             ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1621         # that added two lines
1622         paramLocation += 2
1623         insetEnd += 2
1624         #print insetEnd, document.body[i: insetEnd + 1]
1625         insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1626         #print insetEnd, document.body[i: insetEnd + 1]
1627         document.body.insert(insetEnd, "\\end_layout")
1628         document.body.insert(insetEnd + 1, "")
1629         i = insetEnd + 1
1630
1631
1632 def revert_btprintall(document):
1633     "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1634     i = find_token(document.header, '\\use_bibtopic', 0)
1635     if i == -1:
1636         document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1637         return
1638     if get_value(document.header, '\\use_bibtopic', 0) == "false":
1639         i = 0
1640         while i < len(document.body):
1641             i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1642             if i == -1:
1643                 return
1644             j = find_end_of_inset(document.body, i + 1)
1645             if j == -1:
1646                 #this should not happen
1647                 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1648                 j = len(document.body)
1649             # this range isn't really right, but it should be OK, since we shouldn't
1650             # see more than one matching line in each inset
1651             addedlines = 0
1652             for k in range(i, j):
1653                 if (document.body[k] == 'btprint "btPrintAll"'):
1654                     del document.body[k]
1655                     subst = ["\\begin_inset ERT",
1656                              "status collapsed", "",
1657                              "\\begin_layout Standard", "",
1658                              "\\backslash",
1659                              "nocite{*}",
1660                              "\\end_layout",
1661                              "\\end_inset"]
1662                     document.body[i:i] = subst
1663                     addlines = addedlines + len(subst) - 1
1664             i = j + addedlines
1665
1666
1667 def revert_bahasam(document):
1668     "Set language Bahasa Malaysia to Bahasa Indonesia"
1669     i = 0
1670     if document.language == "bahasam":
1671         document.language = "bahasa"
1672         i = find_token(document.header, "\\language", 0)
1673         if i != -1:
1674             document.header[i] = "\\language bahasa"
1675     j = 0
1676     while True:
1677         j = find_token(document.body, "\\lang bahasam", j)
1678         if j == -1:
1679             return
1680         document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1681         j = j + 1
1682
1683
1684 def revert_interlingua(document):
1685     "Set language Interlingua to English"
1686     i = 0
1687     if document.language == "interlingua":
1688         document.language = "english"
1689         i = find_token(document.header, "\\language", 0)
1690         if i != -1:
1691             document.header[i] = "\\language english"
1692     j = 0
1693     while True:
1694         j = find_token(document.body, "\\lang interlingua", j)
1695         if j == -1:
1696             return
1697         document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1698         j = j + 1
1699
1700
1701 def revert_serbianlatin(document):
1702     "Set language Serbian-Latin to Croatian"
1703     i = 0
1704     if document.language == "serbian-latin":
1705         document.language = "croatian"
1706         i = find_token(document.header, "\\language", 0)
1707         if i != -1:
1708             document.header[i] = "\\language croatian"
1709     j = 0
1710     while True:
1711         j = find_token(document.body, "\\lang serbian-latin", j)
1712         if j == -1:
1713             return
1714         document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
1715         j = j + 1
1716
1717
1718 def revert_rotfloat(document):
1719     " Revert sideways custom floats. "
1720     i = 0
1721     while 1:
1722         # whitespace intended (exclude \\begin_inset FloatList)
1723         i = find_token(document.body, "\\begin_inset Float ", i)
1724         if i == -1:
1725             return
1726         line = document.body[i]
1727         r = re.compile(r'\\begin_inset Float (.*)$')
1728         m = r.match(line)
1729         if m == None:
1730             document.warning("Unable to match line " + str(i) + " of body!")
1731             i += 1
1732             continue
1733         floattype = m.group(1)
1734         if floattype == "figure" or floattype == "table":
1735             i += 1
1736             continue
1737         j = find_end_of_inset(document.body, i)
1738         if j == -1:
1739             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
1740             i += 1
1741             continue
1742         addedLines = 0
1743         if get_value(document.body, 'sideways', i, j) == "false":
1744             i += 1
1745             continue
1746         l = find_default_layout(document, i + 1, j)
1747         if l == -1:
1748             document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1749             return
1750         subst = ['\\begin_layout Standard',
1751                   '\\begin_inset ERT',
1752                   'status collapsed', '',
1753                   '\\begin_layout Standard', '', '', 
1754                   '\\backslash', '',
1755                   'end{sideways' + floattype + '}',
1756                   '\\end_layout', '', '\\end_inset']
1757         document.body[j : j+1] = subst
1758         addedLines = len(subst) - 1
1759         del document.body[i+1 : l]
1760         addedLines -= (l-1) - (i+1) 
1761         subst = ['\\begin_inset ERT', 'status collapsed', '',
1762                   '\\begin_layout Standard', '', '', '\\backslash', 
1763                   'begin{sideways' + floattype + '}', 
1764                   '\\end_layout', '', '\\end_inset', '',
1765                   '\\end_layout', '']
1766         document.body[i : i+1] = subst
1767         addedLines += len(subst) - 1
1768         if floattype == "algorithm":
1769             add_to_preamble(document,
1770                             ['% Commands inserted by lyx2lyx for sideways algorithm float',
1771                               '\\usepackage{rotfloat}',
1772                               '\\floatstyle{ruled}',
1773                               '\\newfloat{algorithm}{tbp}{loa}',
1774                               '\\floatname{algorithm}{Algorithm}'])
1775         else:
1776             document.warning("Cannot create preamble definition for custom float" + floattype + ".")
1777         i += addedLines + 1
1778
1779
1780 def revert_widesideways(document):
1781     " Revert wide sideways floats. "
1782     i = 0
1783     while 1:
1784         # whitespace intended (exclude \\begin_inset FloatList)
1785         i = find_token(document.body, '\\begin_inset Float ', i)
1786         if i == -1:
1787             return
1788         line = document.body[i]
1789         r = re.compile(r'\\begin_inset Float (.*)$')
1790         m = r.match(line)
1791         if m == None:
1792             document.warning("Unable to match line " + str(i) + " of body!")
1793             i += 1
1794             continue
1795         floattype = m.group(1)
1796         if floattype != "figure" and floattype != "table":
1797             i += 1
1798             continue
1799         j = find_end_of_inset(document.body, i)
1800         if j == -1:
1801             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
1802             i += 1
1803             continue
1804         if get_value(document.body, 'sideways', i, j) == "false" or \
1805            get_value(document.body, 'wide', i, j) == "false":
1806              i += 1
1807              continue
1808         l = find_default_layout(document, i + 1, j)
1809         if l == -1:
1810             document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1811             return
1812         subst = ['\\begin_layout Standard', '\\begin_inset ERT', 
1813                   'status collapsed', '', 
1814                   '\\begin_layout Standard', '', '', '\\backslash',
1815                   'end{sideways' + floattype + '*}', 
1816                   '\\end_layout', '', '\\end_inset']
1817         document.body[j : j+1] = subst
1818         addedLines = len(subst) - 1
1819         del document.body[i+1:l-1]
1820         addedLines -= (l-1) - (i+1)
1821         subst = ['\\begin_inset ERT', 'status collapsed', '',
1822                  '\\begin_layout Standard', '', '', '\\backslash',
1823                  'begin{sideways' + floattype + '*}', '\\end_layout', '',
1824                  '\\end_inset', '', '\\end_layout', '']
1825         document.body[i : i+1] = subst
1826         addedLines += len(subst) - 1
1827         add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
1828         i += addedLines + 1
1829
1830
1831 def revert_inset_embedding(document, type):
1832     ' Remove embed tag from certain type of insets'
1833     i = 0
1834     while 1:
1835         i = find_token(document.body, "\\begin_inset %s" % type, i)
1836         if i == -1:
1837             return
1838         j = find_end_of_inset(document.body, i)
1839         if j == -1:
1840             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
1841             i = i + 1
1842             continue
1843         k = find_token(document.body, "\tembed", i, j)
1844         if k == -1:
1845             k = find_token(document.body, "embed", i, j)
1846         if k != -1:
1847             del document.body[k]
1848         i = i + 1
1849
1850
1851 def revert_external_embedding(document):
1852     ' Remove embed tag from external inset '
1853     revert_inset_embedding(document, 'External')
1854
1855
1856 def convert_subfig(document):
1857     " Convert subfigures to subfloats. "
1858     i = 0
1859     while 1:
1860         i = find_token(document.body, '\\begin_inset Graphics', i)
1861         if i == -1:
1862             return
1863         endInset = find_end_of_inset(document.body, i)
1864         if endInset == -1:
1865             document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
1866             i += 1
1867             continue
1868         k = find_token(document.body, '\tsubcaption', i, endInset)
1869         if k == -1:
1870             i = endInset
1871             continue
1872         l = find_token(document.body, '\tsubcaptionText', i, endInset)
1873         if l == -1:
1874             document.warning("Malformed lyx document: Can't find subcaptionText!")
1875             i = endInset
1876             continue
1877         caption = document.body[l][16:].strip('"')
1878         del document.body[l]
1879         del document.body[k]
1880         addedLines = -2
1881         subst = ['\\begin_inset Float figure', 'wide false', 'sideways false', 
1882                  'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption', 
1883                  '', '\\begin_layout Plain Layout',
1884                  caption, '\\end_layout', '', '\\end_inset', '', 
1885                  '\\end_layout', '', '\\begin_layout Plain Layout']
1886         document.body[i : i] = subst
1887         addedLines += len(subst)
1888         endInset += addedLines
1889         subst = ['', '\\end_inset', '', '\\end_layout']
1890         document.body[endInset : endInset] = subst
1891         addedLines += len(subst)
1892         i += addedLines + 1
1893
1894
1895 def revert_subfig(document):
1896     " Revert subfloats. "
1897     i = 0
1898     while 1:
1899         # whitespace intended (exclude \\begin_inset FloatList)
1900         i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
1901         if i == -1:
1902             return
1903         j = 0
1904         addedLines = 0
1905         while j != -1:
1906             j = find_end_of_inset(document.body, i)
1907             if j == -1:
1908                 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
1909                 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
1910                 i += 1
1911                 continue # this will get us back to the outer loop, since j == -1
1912             # look for embedded float (= subfloat)
1913             # whitespace intended (exclude \\begin_inset FloatList)
1914             k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
1915             if k == -1:
1916                 break
1917             l = find_end_of_inset(document.body, k)
1918             if l == -1:
1919                 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
1920                 i += 1
1921                 j == -1
1922                 continue # escape to the outer loop
1923             m = find_default_layout(document, k + 1, l)
1924             # caption?
1925             cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
1926             caption = ''
1927             shortcap = ''
1928             capend = cap
1929             if cap != -1:
1930                 capend = find_end_of_inset(document.body, cap)
1931                 if capend == -1:
1932                     document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
1933                     return
1934                 # label?
1935                 label = ''
1936                 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
1937                 if lbl != -1:
1938                     lblend = find_end_of_inset(document.body, lbl + 1)
1939                     if lblend == -1:
1940                         document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
1941                         return
1942                     for line in document.body[lbl:lblend + 1]:
1943                         if line.startswith('name '):
1944                             label = line.split()[1].strip('"')
1945                             break
1946                 else:
1947                     lbl = capend
1948                     lblend = capend
1949                     label = ''
1950                 # opt arg?
1951                 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
1952                 if opt != -1:
1953                     optend = find_end_of_inset(document.body, opt)
1954                     if optend == -1:
1955                         document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
1956                         return
1957                     optc = find_default_layout(document, opt, optend)
1958                     if optc == -1:
1959                         document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1960                         return
1961                     optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
1962                     for line in document.body[optc:optcend]:
1963                         if not line.startswith('\\'):
1964                             shortcap += line.strip()
1965                 else:
1966                     opt = capend
1967                     optend = capend
1968                 for line in document.body[cap:capend]:
1969                     if line in document.body[lbl:lblend]:
1970                         continue
1971                     elif line in document.body[opt:optend]:
1972                         continue
1973                     elif not line.startswith('\\'):
1974                         caption += line.strip()
1975                 if len(label) > 0:
1976                     caption += "\\backslash\nlabel{" + label + "}"
1977             subst = '\\begin_layout Plain Layout\n\\begin_inset ERT\nstatus collapsed\n\n' \
1978                       '\\begin_layout Plain Layout\n\n}\n\\end_layout\n\n\\end_inset\n\n' \
1979                       '\\end_layout\n\n\\begin_layout Plain Layout\n'
1980             subst = subst.split('\n')
1981             document.body[l : l+1] = subst
1982             addedLines = len(subst) - 1
1983             # this is before l and so is unchanged by the multiline insertion
1984             if cap != capend:
1985                 del document.body[cap:capend+1]
1986                 addedLines -= (capend + 1 - cap)
1987             del document.body[k+1:m-1]
1988             addedLines -= (m - 1 - (k + 1))
1989             insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
1990                         '\\begin_layout Plain Layout\n\n\\backslash\n' \
1991                         'subfloat'
1992             if len(shortcap) > 0:
1993                 insertion = insertion + "[" + shortcap + "]"
1994             if len(caption) > 0:
1995                 insertion = insertion + "[" + caption + "]"
1996             insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
1997             insertion = insertion.split('\n')
1998             document.body[k : k + 1] = insertion
1999             addedLines += len(insertion) - 1
2000             add_to_preamble(document, ['\\usepackage{subfig}\n'])
2001         i += addedLines + 1
2002
2003
2004 def revert_wrapplacement(document):
2005     " Revert placement options wrap floats (wrapfig). "
2006     i = 0
2007     while True:
2008         i = find_token(document.body, "\\begin_inset Wrap figure", i)
2009         if i == -1:
2010             return
2011         e = find_end_of_inset(document.body, i)
2012         j = find_token(document.body, "placement", i + 1, e)
2013         if j == -1:
2014             document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2015             i += 1
2016             continue
2017         r = re.compile("placement (o|i|l|r)")
2018         m = r.match(document.body[j])
2019         if m == None:
2020             document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2021         document.body[j] = "placement " + m.group(1).lower()
2022         i = j
2023
2024
2025 def remove_extra_embedded_files(document):
2026     " Remove \extra_embedded_files from buffer params "
2027     i = find_token(document.header, '\\extra_embedded_files', 0)
2028     if i == -1:
2029         return
2030     document.header.pop(i)
2031
2032
2033 def convert_spaceinset(document):
2034     " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2035     i = 0
2036     while i < len(document.body):
2037         m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2038         if m:
2039             before = m.group(1)
2040             after = m.group(2)
2041             subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2042             document.body[i: i+1] = subst
2043             i = i + len(subst)
2044         else:
2045             i = i + 1
2046
2047
2048 def revert_spaceinset(document):
2049     " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2050     i = 0
2051     while True:
2052         i = find_token(document.body, "\\begin_inset Space", i)
2053         if i == -1:
2054             return
2055         j = find_end_of_inset(document.body, i)
2056         if j == -1:
2057             document.warning("Malformed LyX document: Could not find end of space inset.")
2058             continue
2059         document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2060         del document.body[j]
2061
2062
2063 def convert_hfill(document):
2064     " Convert hfill to space inset "
2065     i = 0
2066     while True:
2067         i = find_token(document.body, "\\hfill", i)
2068         if i == -1:
2069             return
2070         subst = document.body[i].replace('\\hfill', \
2071                   '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2072         subst = subst.split('\n')
2073         document.body[i : i+1] = subst
2074         i += len(subst)
2075
2076
2077 def revert_hfills(document):
2078     ' Revert \\hfill commands '
2079     hfill = re.compile(r'\\hfill')
2080     dotfill = re.compile(r'\\dotfill')
2081     hrulefill = re.compile(r'\\hrulefill')
2082     i = 0
2083     while True:
2084         i = find_token(document.body, "\\InsetSpace", i)
2085         if i == -1:
2086             return
2087         if hfill.search(document.body[i]):
2088             document.body[i] = \
2089               document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2090             i += 1
2091             continue
2092         if dotfill.search(document.body[i]):
2093             subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2094               '\\begin_inset ERT\nstatus collapsed\n\n' \
2095               '\\begin_layout Standard\n\n\n\\backslash\n' \
2096               'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2097             subst = subst.split('\n')
2098             document.body[i : i+1] = subst
2099             i += len(subst)
2100             continue
2101         if hrulefill.search(document.body[i]):
2102             subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2103               '\\begin_inset ERT\nstatus collapsed\n\n' \
2104               '\\begin_layout Standard\n\n\n\\backslash\n' \
2105               'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2106             subst = subst.split('\n')
2107             document.body[i : i+1] = subst
2108             i += len(subst)
2109             continue
2110         i += 1
2111
2112 def revert_hspace(document):
2113     ' Revert \\InsetSpace \\hspace{} to ERT '
2114     i = 0
2115     hspace = re.compile(r'\\hspace{}')
2116     hstar  = re.compile(r'\\hspace\*{}')
2117     while True:
2118         i = find_token(document.body, "\\InsetSpace \\hspace", i)
2119         if i == -1:
2120             return
2121         length = get_value(document.body, '\\length', i+1)
2122         if length == '':
2123             document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2124             return
2125         del document.body[i+1]
2126         addedLines = -1
2127         if hstar.search(document.body[i]):
2128             subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2129               '\\begin_inset ERT\nstatus collapsed\n\n' \
2130               '\\begin_layout Standard\n\n\n\\backslash\n' \
2131               'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2132             subst = subst.split('\n')
2133             document.body[i : i+1] = subst
2134             addedLines += len(subst) - 1
2135             i += addedLines + 1
2136             continue
2137         if hspace.search(document.body[i]):
2138             subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2139               '\\begin_inset ERT\nstatus collapsed\n\n' \
2140               '\\begin_layout Standard\n\n\n\\backslash\n' \
2141               'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2142             subst = subst.split('\n')
2143             document.body[i : i+1] = subst
2144             addedLines += len(subst) - 1
2145             i += addedLines + 1
2146             continue
2147         i += 1
2148
2149
2150 def revert_protected_hfill(document):
2151     ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2152     i = 0
2153     while True:
2154         i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2155         if i == -1:
2156             return
2157         j = find_end_of_inset(document.body, i)
2158         if j == -1:
2159             document.warning("Malformed LyX document: Could not find end of space inset.")
2160             continue
2161         del document.body[j]
2162         subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2163           '\\begin_inset ERT\nstatus collapsed\n\n' \
2164           '\\begin_layout Standard\n\n\n\\backslash\n' \
2165           'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2166         subst = subst.split('\n')
2167         document.body[i : i+1] = subst
2168         i += len(subst)
2169
2170
2171 def revert_leftarrowfill(document):
2172     ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2173     i = 0
2174     while True:
2175         i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2176         if i == -1:
2177             return
2178         j = find_end_of_inset(document.body, i)
2179         if j == -1:
2180             document.warning("Malformed LyX document: Could not find end of space inset.")
2181             continue
2182         del document.body[j]
2183         subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2184           '\\begin_inset ERT\nstatus collapsed\n\n' \
2185           '\\begin_layout Standard\n\n\n\\backslash\n' \
2186           'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2187         subst = subst.split('\n')
2188         document.body[i : i+1] = subst
2189         i += len(subst)
2190
2191
2192 def revert_rightarrowfill(document):
2193     ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2194     i = 0
2195     while True:
2196         i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2197         if i == -1:
2198             return
2199         j = find_end_of_inset(document.body, i)
2200         if j == -1:
2201             document.warning("Malformed LyX document: Could not find end of space inset.")
2202             continue
2203         del document.body[j]
2204         subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2205           '\\begin_inset ERT\nstatus collapsed\n\n' \
2206           '\\begin_layout Standard\n\n\n\\backslash\n' \
2207           'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2208         subst = subst.split('\n')
2209         document.body[i : i+1] = subst
2210         i += len(subst)
2211
2212
2213 def revert_upbracefill(document):
2214     ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2215     i = 0
2216     while True:
2217         i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2218         if i == -1:
2219             return
2220         j = find_end_of_inset(document.body, i)
2221         if j == -1:
2222             document.warning("Malformed LyX document: Could not find end of space inset.")
2223             continue
2224         del document.body[j]
2225         subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2226           '\\begin_inset ERT\nstatus collapsed\n\n' \
2227           '\\begin_layout Standard\n\n\n\\backslash\n' \
2228           'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2229         subst = subst.split('\n')
2230         document.body[i : i+1] = subst
2231         i += len(subst)
2232
2233
2234 def revert_downbracefill(document):
2235     ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2236     i = 0
2237     while True:
2238         i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2239         if i == -1:
2240             return
2241         j = find_end_of_inset(document.body, i)
2242         if j == -1:
2243             document.warning("Malformed LyX document: Could not find end of space inset.")
2244             continue
2245         del document.body[j]
2246         subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2247           '\\begin_inset ERT\nstatus collapsed\n\n' \
2248           '\\begin_layout Standard\n\n\n\\backslash\n' \
2249           'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2250         subst = subst.split('\n')
2251         document.body[i : i+1] = subst
2252         i += len(subst)
2253
2254
2255 def revert_local_layout(document):
2256     ' Revert local layout headers.'
2257     i = 0
2258     while True:
2259         i = find_token(document.header, "\\begin_local_layout", i)
2260         if i == -1:
2261             return
2262         j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2263         if j == -1:
2264             # this should not happen
2265             break
2266         document.header[i : j + 1] = []
2267
2268
2269 def convert_pagebreaks(document):
2270     ' Convert inline Newpage insets to new format '
2271     i = 0
2272     while True:
2273         i = find_token(document.body, '\\newpage', i)
2274         if i == -1:
2275             break
2276         document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2277                                 '\\end_inset']
2278     i = 0
2279     while True:
2280         i = find_token(document.body, '\\pagebreak', i)
2281         if i == -1:
2282             break
2283         document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2284                                 '\\end_inset']
2285     i = 0
2286     while True:
2287         i = find_token(document.body, '\\clearpage', i)
2288         if i == -1:
2289             break
2290         document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2291                                 '\\end_inset']
2292     i = 0
2293     while True:
2294         i = find_token(document.body, '\\cleardoublepage', i)
2295         if i == -1:
2296             break
2297         document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2298                                 '\\end_inset']
2299
2300
2301 def revert_pagebreaks(document):
2302     ' Revert \\begin_inset Newpage to previous inline format '
2303     i = 0
2304     while True:
2305         i = find_token(document.body, '\\begin_inset Newpage', i)
2306         if i == -1:
2307             return
2308         j = find_end_of_inset(document.body, i)
2309         if j == -1:
2310             document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2311             continue
2312         del document.body[j]
2313         document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2314         document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2315         document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2316         document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2317
2318
2319 def convert_linebreaks(document):
2320     ' Convert inline Newline insets to new format '
2321     i = 0
2322     while True:
2323         i = find_token(document.body, '\\newline', i)
2324         if i == -1:
2325             break
2326         document.body[i:i+1] = ['\\begin_inset Newline newline',
2327                                 '\\end_inset']
2328     i = 0
2329     while True:
2330         i = find_token(document.body, '\\linebreak', i)
2331         if i == -1:
2332             break
2333         document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2334                                 '\\end_inset']
2335
2336
2337 def revert_linebreaks(document):
2338     ' Revert \\begin_inset Newline to previous inline format '
2339     i = 0
2340     while True:
2341         i = find_token(document.body, '\\begin_inset Newline', i)
2342         if i == -1:
2343             return
2344         j = find_end_of_inset(document.body, i)
2345         if j == -1:
2346             document.warning("Malformed LyX document: Could not find end of Newline inset.")
2347             continue
2348         del document.body[j]
2349         document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2350         document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2351
2352
2353 def convert_japanese_plain(document):
2354     ' Set language japanese-plain to japanese '
2355     i = 0
2356     if document.language == "japanese-plain":
2357         document.language = "japanese"
2358         i = find_token(document.header, "\\language", 0)
2359         if i != -1:
2360             document.header[i] = "\\language japanese"
2361     j = 0
2362     while True:
2363         j = find_token(document.body, "\\lang japanese-plain", j)
2364         if j == -1:
2365             return
2366         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2367         j = j + 1
2368
2369
2370 def revert_pdfpages(document):
2371     ' Revert pdfpages external inset to ERT '
2372     i = 0
2373     while 1:
2374         i = find_token(document.body, "\\begin_inset External", i)
2375         if i == -1:
2376             return
2377         j = find_end_of_inset(document.body, i)
2378         if j == -1:
2379             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2380             i = i + 1
2381             continue
2382         if get_value(document.body, 'template', i, j) == "PDFPages":
2383             filename = get_value(document.body, 'filename', i, j)
2384             extra = ''
2385             r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2386             for k in range(i, j):
2387                 m = r.match(document.body[k])
2388                 if m:
2389                     extra = m.group(1)
2390             angle = get_value(document.body, 'rotateAngle', i, j)
2391             width = get_value(document.body, 'width', i, j)
2392             height = get_value(document.body, 'height', i, j)
2393             scale = get_value(document.body, 'scale', i, j)
2394             keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2395             options = extra
2396             if angle != '':
2397                  if options != '':
2398                      options += ",angle=" + angle
2399                  else:
2400                      options += "angle=" + angle
2401             if width != '':
2402                  if options != '':
2403                      options += ",width=" + convert_len(width)
2404                  else:
2405                      options += "width=" + convert_len(width)
2406             if height != '':
2407                  if options != '':
2408                      options += ",height=" + convert_len(height)
2409                  else:
2410                      options += "height=" + convert_len(height)
2411             if scale != '':
2412                  if options != '':
2413                      options += ",scale=" + scale
2414                  else:
2415                      options += "scale=" + scale
2416             if keepAspectRatio != '':
2417                  if options != '':
2418                      options += ",keepaspectratio"
2419                  else:
2420                      options += "keepaspectratio"
2421             if options != '':
2422                      options = '[' + options + ']'
2423             del document.body[i+1:j+1]
2424             document.body[i:i+1] = ['\\begin_inset ERT',
2425                                 'status collapsed',
2426                                 '',
2427                                 '\\begin_layout Standard',
2428                                 '',
2429                                 '\\backslash',
2430                                 'includepdf' + options + '{' + filename + '}',
2431                                 '\\end_layout',
2432                                 '',
2433                                 '\\end_inset']
2434             add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2435             i = i + 1
2436             continue
2437         i = i + 1
2438
2439
2440 def revert_mexican(document):
2441     ' Set language Spanish(Mexico) to Spanish '
2442     i = 0
2443     if document.language == "spanish-mexico":
2444         document.language = "spanish"
2445         i = find_token(document.header, "\\language", 0)
2446         if i != -1:
2447             document.header[i] = "\\language spanish"
2448     j = 0
2449     while True:
2450         j = find_token(document.body, "\\lang spanish-mexico", j)
2451         if j == -1:
2452             return
2453         document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2454         j = j + 1
2455
2456
2457 def remove_embedding(document):
2458     ' Remove embed tag from all insets '
2459     revert_inset_embedding(document, 'Graphics')
2460     revert_inset_embedding(document, 'External')
2461     revert_inset_embedding(document, 'CommandInset include')
2462     revert_inset_embedding(document, 'CommandInset bibtex')
2463
2464
2465 def revert_master(document):
2466     ' Remove master param '
2467     i = find_token(document.header, "\\master", 0)
2468     if i != -1:
2469         del document.header[i]
2470
2471
2472 def revert_graphics_group(document):
2473     ' Revert group information from graphics insets '
2474     i = 0
2475     while 1:
2476         i = find_token(document.body, "\\begin_inset Graphics", i)
2477         if i == -1:
2478             return
2479         j = find_end_of_inset(document.body, i)
2480         if j == -1:
2481             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2482             i = i + 1
2483             continue
2484         k = find_token(document.body, " groupId", i, j)
2485         if k == -1:
2486             i = i + 1
2487             continue
2488         del document.body[k]
2489         i = i + 1
2490
2491
2492 def update_apa_styles(document):
2493     ' Replace obsolete styles '
2494
2495     if document.textclass != "apa":
2496         return
2497
2498     obsoletedby = { "Acknowledgments": "Acknowledgements",
2499                     "Section*":        "Section",
2500                     "Subsection*":     "Subsection",
2501                     "Subsubsection*":  "Subsubsection",
2502                     "Paragraph*":      "Paragraph",
2503                     "Subparagraph*":   "Subparagraph"}
2504     i = 0
2505     while 1:
2506         i = find_token(document.body, "\\begin_layout", i)
2507         if i == -1:
2508             return
2509
2510         layout = document.body[i][14:]
2511         if layout in obsoletedby:
2512             document.body[i] = "\\begin_layout " + obsoletedby[layout]
2513
2514         i += 1
2515
2516
2517 def convert_paper_sizes(document):
2518     ' exchange size options legalpaper and executivepaper to correct order '
2519     # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2520     i = 0
2521     j = 0
2522     i = find_token(document.header, "\\papersize executivepaper", 0)
2523     if i != -1:
2524         document.header[i] = "\\papersize legalpaper"
2525         return
2526     j = find_token(document.header, "\\papersize legalpaper", 0)
2527     if j != -1:
2528         document.header[j] = "\\papersize executivepaper"
2529
2530
2531 def revert_paper_sizes(document):
2532     ' exchange size options legalpaper and executivepaper to correct order '
2533     i = 0
2534     j = 0
2535     i = find_token(document.header, "\\papersize executivepaper", 0)
2536     if i != -1:
2537         document.header[i] = "\\papersize legalpaper"
2538         return
2539     j = find_token(document.header, "\\papersize legalpaper", 0)
2540     if j != -1:
2541         document.header[j] = "\\papersize executivepaper"
2542
2543
2544 def convert_InsetSpace(document):
2545     " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2546     i = 0
2547     while True:
2548         i = find_token(document.body, "\\begin_inset Space", i)
2549         if i == -1:
2550             return
2551         document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2552
2553
2554 def revert_InsetSpace(document):
2555     " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2556     i = 0
2557     while True:
2558         i = find_token(document.body, "\\begin_inset space", i)
2559         if i == -1:
2560             return
2561         document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2562
2563
2564 def convert_display_enum(document):
2565     " Convert 'display foo' to 'display false/true'"
2566     i = 0
2567     while True:
2568         i = find_token(document.body, "\tdisplay", i)
2569         if i == -1:
2570             return
2571         val = get_value(document.body, 'display', i)
2572         if val == "none":
2573             document.body[i] = document.body[i].replace('none', 'false')
2574         if val == "default":
2575             document.body[i] = document.body[i].replace('default', 'true')
2576         if val == "monochrome":
2577             document.body[i] = document.body[i].replace('monochrome', 'true')
2578         if val == "grayscale":
2579             document.body[i] = document.body[i].replace('grayscale', 'true')
2580         if val == "color":
2581             document.body[i] = document.body[i].replace('color', 'true')
2582         if val == "preview":
2583             document.body[i] = document.body[i].replace('preview', 'true')
2584         i += 1
2585
2586
2587 def revert_display_enum(document):
2588     " Revert 'display false/true' to 'display none/color'"
2589     i = 0
2590     while True:
2591         i = find_token(document.body, "\tdisplay", i)
2592         if i == -1:
2593             return
2594         val = get_value(document.body, 'display', i)
2595         if val == "false":
2596             document.body[i] = document.body[i].replace('false', 'none')
2597         if val == "true":
2598             document.body[i] = document.body[i].replace('true', 'default')
2599         i += 1
2600
2601
2602 def remove_fontsCJK(document):
2603     ' Remove font_cjk param '
2604     i = find_token(document.header, "\\font_cjk", 0)
2605     if i != -1:
2606         del document.header[i]
2607
2608
2609 def convert_plain_layout(document):
2610     " Convert 'PlainLayout' to 'Plain Layout'" 
2611     i = 0
2612     while True:
2613         i = find_token(document.body, '\\begin_layout PlainLayout', i)
2614         if i == -1:
2615             return
2616         document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2617           '\\begin_layout Plain Layout')
2618         i += 1
2619
2620
2621 def revert_plain_layout(document):
2622     " Convert 'PlainLayout' to 'Plain Layout'" 
2623     i = 0
2624     while True:
2625         i = find_token(document.body, '\\begin_layout Plain Layout', i)
2626         if i == -1:
2627             return
2628         document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2629           '\\begin_layout PlainLayout')
2630         i += 1
2631
2632
2633 def revert_plainlayout(document):
2634     " Convert 'PlainLayout' to 'Plain Layout'" 
2635     i = 0
2636     while True:
2637         i = find_token(document.body, '\\begin_layout PlainLayout', i)
2638         if i == -1:
2639             return
2640         # This will be incorrect for some document classes, since Standard is not always
2641         # the default. But (a) it is probably the best we can do and (b) it will actually
2642         # work, in fact, since an unknown layout will be converted to default.
2643         document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2644           '\\begin_layout Standard')
2645         i += 1
2646
2647
2648 def revert_polytonicgreek(document):
2649     "Set language polytonic Greek to Greek"
2650     i = 0
2651     if document.language == "polutonikogreek":
2652         document.language = "greek"
2653         i = find_token(document.header, "\\language", 0)
2654         if i != -1:
2655             document.header[i] = "\\language greek"
2656     j = 0
2657     while True:
2658         j = find_token(document.body, "\\lang polutonikogreek", j)
2659         if j == -1:
2660             return
2661         document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2662         j = j + 1
2663
2664
2665 ##
2666 # Conversion hub
2667 #
2668
2669 supported_versions = ["1.6.0","1.6"]
2670 convert = [[277, [fix_wrong_tables]],
2671            [278, [close_begin_deeper]],
2672            [279, [long_charstyle_names]],
2673            [280, [axe_show_label]],
2674            [281, []],
2675            [282, []],
2676            [283, [convert_flex]],
2677            [284, []],
2678            [285, []],
2679            [286, []],
2680            [287, [convert_wrapfig_options]],
2681            [288, [convert_inset_command]],
2682            [289, [convert_latexcommand_index]],
2683            [290, []],
2684            [291, []],
2685            [292, []],
2686            [293, []],
2687            [294, [convert_pdf_options]],
2688            [295, [convert_htmlurl, convert_url]],
2689            [296, [convert_include]],
2690            [297, [convert_usorbian]],
2691            [298, []],
2692            [299, []],
2693            [300, []],
2694            [301, []],
2695            [302, []],
2696            [303, [convert_serbocroatian]],
2697            [304, [convert_framed_notes]],
2698            [305, []],
2699            [306, []],
2700            [307, []],
2701            [308, []],
2702            [309, []],
2703            [310, []],
2704            [311, [convert_ams_classes]],
2705            [312, []],
2706            [313, [convert_module_names]],
2707            [314, []],
2708            [315, []],
2709            [316, [convert_subfig]],
2710            [317, []],
2711            [318, []],
2712            [319, [convert_spaceinset, convert_hfill]],
2713            [320, []],
2714            [321, [convert_tablines]],
2715            [322, [convert_plain_layout]],
2716            [323, [convert_pagebreaks]],
2717            [324, [convert_linebreaks]],
2718            [325, [convert_japanese_plain]],
2719            [326, []],
2720            [327, []],
2721            [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
2722            [329, []],
2723            [330, []],
2724            [331, [convert_ltcaption]],
2725            [332, []],
2726            [333, [update_apa_styles]],
2727            [334, [convert_paper_sizes]],
2728            [335, [convert_InsetSpace]],
2729            [336, []],
2730            [337, [convert_display_enum]],
2731            [338, []],
2732           ]
2733
2734 revert =  [[337, [revert_polytonicgreek]],
2735            [336, [revert_display_enum]],
2736            [335, [remove_fontsCJK]],
2737            [334, [revert_InsetSpace]],
2738            [333, [revert_paper_sizes]],
2739            [332, []],
2740            [331, [revert_graphics_group]],
2741            [330, [revert_ltcaption]],
2742            [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
2743            [328, [revert_master]],
2744            [327, []],
2745            [326, [revert_mexican]],
2746            [325, [revert_pdfpages]],
2747            [324, []],
2748            [323, [revert_linebreaks]],
2749            [322, [revert_pagebreaks]],
2750            [321, [revert_local_layout, revert_plain_layout]],
2751            [320, [revert_tablines]],
2752            [319, [revert_protected_hfill]],
2753            [318, [revert_spaceinset, revert_hfills, revert_hspace]],
2754            [317, [remove_extra_embedded_files]],
2755            [316, [revert_wrapplacement]],
2756            [315, [revert_subfig]],
2757            [314, [revert_colsep, revert_plainlayout]],
2758            [313, []],
2759            [312, [revert_module_names]],
2760            [311, [revert_rotfloat, revert_widesideways]],
2761            [310, [revert_external_embedding]],
2762            [309, [revert_btprintall]],
2763            [308, [revert_nocite]],
2764            [307, [revert_serbianlatin]],
2765            [306, [revert_slash, revert_nobreakdash]],
2766            [305, [revert_interlingua]],
2767            [304, [revert_bahasam]],
2768            [303, [revert_framed_notes]],
2769            [302, []],
2770            [301, [revert_latin, revert_samin]],
2771            [300, [revert_linebreak]],
2772            [299, [revert_pagebreak]],
2773            [298, [revert_hyperlinktype]],
2774            [297, [revert_macro_optional_params]],
2775            [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
2776            [295, [revert_include]],
2777            [294, [revert_href, revert_url]],
2778            [293, [revert_pdf_options_2]],
2779            [292, [revert_inset_info]],
2780            [291, [revert_japanese, revert_japanese_encoding]],
2781            [290, [revert_vietnamese]],
2782            [289, [revert_wraptable]],
2783            [288, [revert_latexcommand_index]],
2784            [287, [revert_inset_command]],
2785            [286, [revert_wrapfig_options]],
2786            [285, [revert_pdf_options]],
2787            [284, [remove_inzip_options]],
2788            [283, []],
2789            [282, [revert_flex]],
2790            [281, []],
2791            [280, [revert_begin_modules]],
2792            [279, [revert_show_label]],
2793            [278, [revert_long_charstyle_names]],
2794            [277, []],
2795            [276, []]
2796           ]
2797
2798
2799 if __name__ == "__main__":
2800     pass