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