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