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