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