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