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