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