]> git.lyx.org Git - features.git/blob - lib/lyx2lyx/lyx_1_6.py
More work on 5006.
[features.git] / lib / lyx2lyx / lyx_1_6.py
1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2008 The LyX Team <lyx-devel@lists.lyx.org>
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 """ Convert files to the file format generated by lyx 1.6"""
20
21 import re
22 import unicodedata
23 import sys, os
24
25 from parser_tools import find_token, find_end_of, find_tokens, get_value, get_value_string
26
27 ####################################################################
28 # Private helper functions
29
30 def find_end_of_inset(lines, i):
31     " Find end of inset, where lines[i] is included."
32     return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
33
34 # WARNING!
35 # DO NOT do this:
36 #   document.body[i] = wrap_insert_ert(...)
37 # wrap_into_ert may returns a multiline string, which should NOT appear
38 # in document.body. Insetad, do something like this:
39 #   subst = wrap_inset_ert(...)
40 #   subst = subst.split('\n')
41 #   document.body[i:i+1] = subst
42 #   i+= len(subst) - 1
43 # where the last statement resets the counter to accord with the added
44 # lines.
45 def wrap_into_ert(string, src, dst):
46     '''Within string, replace occurrences of src with dst, wrapped into ERT
47        E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
48        sch<ERT>\\backslash</ERT>"on'''
49     return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
50       + dst + '\n\\end_layout\n\\end_inset\n')
51
52 def put_cmd_in_ert(string):
53     string = string.replace('\\', "\\backslash\n")
54     string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \
55       + string + "\n\\end_layout\n\\end_inset"
56     return string
57
58 def add_to_preamble(document, text):
59     """ Add text to the preamble if it is not already there.
60     Only the first line is checked!"""
61
62     if find_token(document.preamble, text[0], 0) != -1:
63         return
64
65     document.preamble.extend(text)
66
67 # Convert a LyX length into a LaTeX length
68 def convert_len(len):
69     units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
70              "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
71              "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
72
73     # Convert LyX units to LaTeX units
74     for unit in units.keys():
75         if len.find(unit) != -1:
76             len = '%f' % (len2value(len) / 100)
77             len = len.strip('0') + units[unit]
78             break
79
80     return len
81
82 # Return the value of len without the unit in numerical form.
83 def len2value(len):
84     result = re.search('([+-]?[0-9.]+)', len)
85     if result:
86         return float(result.group(1))
87     # No number means 1.0
88     return 1.0
89
90 # Unfortunately, this doesn't really work, since Standard isn't always default.
91 # But it's as good as we can do right now.
92 def find_default_layout(document, start, end):
93     l = find_token(document.body, "\\begin_layout Standard", start, end)
94     if l == -1:
95         l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
96     if l == -1:
97         l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
98     return l
99
100 def get_option(document, m, option, default):
101     l = document.body[m].find(option)
102     val = default
103     if l != -1:
104         val = document.body[m][l:].split('"')[1]
105     return val
106
107 def remove_option(document, m, option):
108     l = document.body[m].find(option)
109     if l != -1:
110         val = document.body[m][l:].split('"')[1]
111         document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
112     return l
113
114 def set_option(document, m, option, value):
115     l = document.body[m].find(option)
116     if l != -1:
117         oldval = document.body[m][l:].split('"')[1]
118         l = l + len(option + '="')
119         document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
120     else:
121         document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
122     return l
123
124
125 def read_unicodesymbols():
126     " Read the unicodesymbols list of unicode characters and corresponding commands."
127     pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
128     fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
129     spec_chars = []
130     # Two backslashes, followed by some non-word character, and then a character
131     # in brackets. The idea is to check for constructs like: \"{u}, which is how
132     # they are written in the unicodesymbols file; but they can also be written
133     # as: \"u.
134     r = re.compile(r'\\\\(\W)\{(\w)\}')
135     for line in fp.readlines():
136         if line[0] != '#' and line.strip() != "":
137             line=line.replace(' "',' ') # remove all quotation marks with spaces before
138             line=line.replace('" ',' ') # remove all quotation marks with spaces after
139             line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
140             try:
141                 [ucs4,command,dead] = line.split(None,2)
142                 if command[0:1] != "\\":
143                     continue
144                 spec_chars.append([command, unichr(eval(ucs4))])
145             except:
146                 continue
147             m = r.match(command)
148             if m != None:
149                 command = "\\\\"
150                 # If the character is a double-quote, then we need to escape it, too,
151                 # since it is done that way in the LyX file.
152                 if m.group(1) == "\"":
153                     command += "\\"
154                 command += m.group(1) + m.group(2)
155                 spec_chars.append([command, unichr(eval(ucs4))])
156     fp.close()
157     return spec_chars
158
159
160 def extract_argument(line):
161     'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
162
163     if not line:
164         return (None, "")
165
166     bracere = re.compile("(\s*)(.*)")
167     n = bracere.match(line)
168     whitespace = n.group(1)
169     stuff = n.group(2)
170     brace = stuff[:1]
171     if brace != "[" and brace != "{":
172         return (None, line)
173
174     # find closing brace
175     remain = stuff[1:]
176     pos = 0
177     num = 1
178     term = "}"
179     if brace == "[":
180         term = "]"
181     skip = False
182     for c in remain:
183         if skip:
184             skip = False
185         elif c == "\\":
186             skip = True
187         elif c == brace:
188             num += 1
189         elif c == term:
190             num -= 1
191         if c == 0:
192             break
193         pos += 1
194     if num != 0:
195         # We never found the matching brace
196         # So, to be on the safe side, let's just return everything
197         # which will then get wrapped as ERT
198         return (line, "")
199     return (line[:pos + 1], line[pos + 1:])
200
201
202 def latex2ert(line):
203     '''Converts LaTeX commands into ERT. line may well be a multi-line
204        string when it is returned.'''
205     if not line:
206         return line
207
208     retval = ""
209     ## FIXME Escaped \ ??
210     labelre = re.compile(r'(.*?)\\(\\(?:[a-zA-Z]+|.))(.*)')
211
212     m = labelre.match(line)
213     while m != None:
214         retval += m.group(1)
215         cmd = m.group(2)
216         end = m.group(3)
217
218         while True:
219             (arg, rest) = extract_argument(end)
220             if arg == None:
221                 break
222             cmd += arg
223             end = rest
224         cmd = put_cmd_in_ert(cmd)
225         retval += "\n" + cmd + "\n"
226         line = end
227         m = labelre.match(line)
228     retval += line
229     return retval
230
231
232 def latex2lyx(data):
233     '''Takes a string, possibly multi-line, and returns the result of 
234     converting LaTeX constructs into LyX constructs. Returns a list of
235     lines, suitable for insertion into document.body.'''
236
237     retval = []
238
239     # Convert LaTeX to Unicode
240     reps = read_unicodesymbols()
241     # Commands of this sort need to be checked to make sure they are
242     # followed by a non-alpha character, lest we replace too much.
243     hardone = re.compile(r'^\\\\[a-zA-Z]+$')
244     
245     for rep in reps:
246         if hardone.match(rep[0]):
247             pos = 0
248             while True:
249                 pos = data.find(rep[0], pos)
250                 if pos == -1:
251                     break
252                 nextpos = pos + len(rep[0])
253                 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.isspace() or \
1015                line.startswith("\\begin_layout Standard") or \
1016                line.startswith("\\begin_layout Plain Layout") or \
1017                line.startswith("\\end_layout") or \
1018                line.startswith("\\end_inset") or \
1019                line.startswith("\\lang") or \
1020                line.startswith("status collapsed") or \
1021                line.startswith("status open"):
1022               #skip all that stuff
1023               continue
1024
1025           # a lossless reversion is not possible
1026           # try at least to handle some common insets and settings
1027           # do not replace inside ERTs
1028           if ert_end >= curline:
1029               line = line.replace(r'\backslash', r'\\')
1030           else:
1031               # Do the LyX text --> LaTeX conversion
1032               for rep in reps:
1033                 line = line.replace(rep[1], rep[0])
1034               line = line.replace(r'\backslash', r'\textbackslash{}')
1035               line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
1036               line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
1037               line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
1038               line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
1039               line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
1040               line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
1041               line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
1042               line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
1043               line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
1044           content += line;
1045
1046         # end of curline loop
1047         # escape quotes
1048         content = content.replace('"', r'\"')
1049         document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1050             "name " + '"' + content + '"', ""]
1051         i += 5
1052
1053
1054 def revert_wraptable(document):
1055     "Revert wrap table to wrap figure."
1056     i = 0
1057     while True:
1058         i = find_token(document.body, "\\begin_inset Wrap table", i)
1059         if i == -1:
1060             return
1061         document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1062         i = i + 1
1063
1064
1065 def revert_vietnamese(document):
1066     "Set language Vietnamese to English"
1067     # Set document language from Vietnamese to English
1068     i = 0
1069     if document.language == "vietnamese":
1070         document.language = "english"
1071         i = find_token(document.header, "\\language", 0)
1072         if i != -1:
1073             document.header[i] = "\\language english"
1074     j = 0
1075     while True:
1076         j = find_token(document.body, "\\lang vietnamese", j)
1077         if j == -1:
1078             return
1079         document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1080         j = j + 1
1081
1082
1083 def convert_japanese_cjk(document):
1084     "Set language japanese to japanese-cjk"
1085     # Set document language from japanese-plain to japanese
1086     i = 0
1087     if document.language == "japanese":
1088         document.language = "japanese-cjk"
1089         i = find_token(document.header, "\\language", 0)
1090         if i != -1:
1091             document.header[i] = "\\language japanese-cjk"
1092     j = 0
1093     while True:
1094         j = find_token(document.body, "\\lang japanese", j)
1095         if j == -1:
1096             return
1097         document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1098         j = j + 1
1099
1100
1101 def revert_japanese(document):
1102     "Set language japanese-plain to japanese"
1103     # Set document language from japanese-plain to japanese
1104     i = 0
1105     if document.language == "japanese-plain":
1106         document.language = "japanese"
1107         i = find_token(document.header, "\\language", 0)
1108         if i != -1:
1109             document.header[i] = "\\language japanese"
1110     j = 0
1111     while True:
1112         j = find_token(document.body, "\\lang japanese-plain", j)
1113         if j == -1:
1114             return
1115         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1116         j = j + 1
1117
1118
1119 def revert_japanese_cjk(document):
1120     "Set language japanese-cjk to japanese"
1121     # Set document language from japanese-plain to japanese
1122     i = 0
1123     if document.language == "japanese-cjk":
1124         document.language = "japanese"
1125         i = find_token(document.header, "\\language", 0)
1126         if i != -1:
1127             document.header[i] = "\\language japanese"
1128     j = 0
1129     while True:
1130         j = find_token(document.body, "\\lang japanese-cjk", j)
1131         if j == -1:
1132             return
1133         document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1134         j = j + 1
1135
1136
1137 def revert_japanese_encoding(document):
1138     "Set input encoding form EUC-JP-plain to EUC-JP etc."
1139     # Set input encoding form EUC-JP-plain to EUC-JP etc.
1140     i = 0
1141     i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1142     if i != -1:
1143         document.header[i] = "\\inputencoding EUC-JP"
1144     j = 0
1145     j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1146     if j != -1:
1147         document.header[j] = "\\inputencoding JIS"
1148     k = 0
1149     k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1150     if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1151         document.header[k] = "\\inputencoding UTF8"
1152
1153
1154 def revert_inset_info(document):
1155     'Replace info inset with its content'
1156     i = 0
1157     while 1:
1158         i = find_token(document.body, '\\begin_inset Info', i)
1159         if i == -1:
1160             return
1161         j = find_end_of_inset(document.body, i + 1)
1162         if j == -1:
1163             # should not happen
1164             document.warning("Malformed LyX document: Could not find end of Info inset.")
1165         type = 'unknown'
1166         arg = ''
1167         for k in range(i, j+1):
1168             if document.body[k].startswith("arg"):
1169                 arg = document.body[k][3:].strip().strip('"')
1170             if document.body[k].startswith("type"):
1171                 type = document.body[k][4:].strip().strip('"')
1172         # I think there is a newline after \\end_inset, which should be removed.
1173         if document.body[j + 1].strip() == "":
1174             document.body[i : (j + 2)] = [type + ':' + arg]
1175         else:
1176             document.body[i : (j + 1)] = [type + ':' + arg]
1177
1178
1179 def convert_pdf_options(document):
1180     # Set the pdfusetitle tag, delete the pdf_store_options,
1181     # set quotes for bookmarksopenlevel"
1182     has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1183     if has_hr == "1":
1184         k = find_token(document.header, "\\use_hyperref", 0)
1185         document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1186     k = find_token(document.header, "\\pdf_store_options", 0)
1187     if k != -1:
1188         del document.header[k]
1189     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1190     if i == -1: return
1191     document.header[i] = document.header[i].replace('"', '')
1192
1193
1194 def revert_pdf_options_2(document):
1195     # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1196     k = find_token(document.header, "\\use_hyperref", 0)
1197     i = find_token(document.header, "\\pdf_pdfusetitle", k)
1198     if i != -1:
1199         del document.header[i]
1200     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1201     if i == -1: return
1202     values = document.header[i].split()
1203     values[1] = ' "' + values[1] + '"'
1204     document.header[i] = ''.join(values)
1205
1206
1207 def convert_htmlurl(document):
1208     'Convert "htmlurl" to "href" insets for docbook'
1209     if document.backend != "docbook":
1210       return
1211     i = 0
1212     while True:
1213       i = find_token(document.body, "\\begin_inset CommandInset url", i)
1214       if i == -1:
1215         return
1216       document.body[i] = "\\begin_inset CommandInset href"
1217       document.body[i + 1] = "LatexCommand href"
1218       i = i + 1
1219
1220
1221 def convert_url(document):
1222     'Convert url insets to url charstyles'
1223     if document.backend == "docbook":
1224       return
1225     i = 0
1226     while True:
1227       i = find_token(document.body, "\\begin_inset CommandInset url", i)
1228       if i == -1:
1229         break
1230       n = find_token(document.body, "name", i)
1231       if n == i + 2:
1232         # place the URL name in typewriter before the new URL insert
1233         # grab the name 'bla' from the e.g. the line 'name "bla"',
1234         # therefore start with the 6th character
1235         name = document.body[n][6:-1]
1236         newname = [name + " "]
1237         document.body[i:i] = newname
1238         i = i + 1
1239       j = find_token(document.body, "target", i)
1240       if j == -1:
1241         document.warning("Malformed LyX document: Can't find target for url inset")
1242         i = j
1243         continue
1244       target = document.body[j][8:-1]
1245       k = find_token(document.body, "\\end_inset", j)
1246       if k == -1:
1247         document.warning("Malformed LyX document: Can't find end of url inset")
1248         i = k
1249         continue
1250       newstuff = ["\\begin_inset Flex URL",
1251         "status collapsed", "",
1252         "\\begin_layout Standard",
1253         "",
1254         target,
1255         "\\end_layout",
1256         ""]
1257       document.body[i:k] = newstuff
1258       i = k
1259
1260 def convert_ams_classes(document):
1261   tc = document.textclass
1262   if (tc != "amsart" and tc != "amsart-plain" and
1263       tc != "amsart-seq" and tc != "amsbook"):
1264     return
1265   if tc == "amsart-plain":
1266     document.textclass = "amsart"
1267     document.set_textclass()
1268     document.add_module("Theorems (Starred)")
1269     return
1270   if tc == "amsart-seq":
1271     document.textclass = "amsart"
1272     document.set_textclass()
1273   document.add_module("Theorems (AMS)")
1274
1275   #Now we want to see if any of the environments in the extended theorems
1276   #module were used in this document. If so, we'll add that module, too.
1277   layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note",  \
1278     "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1279     "Assumption"]
1280
1281   r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1282   i = 0
1283   while True:
1284     i = find_token(document.body, "\\begin_layout", i)
1285     if i == -1:
1286       return
1287     m = r.match(document.body[i])
1288     if m == None:
1289       document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1290       i += 1
1291       continue
1292     m = m.group(1)
1293     if layouts.count(m) != 0:
1294       document.add_module("Theorems (AMS-Extended)")
1295       return
1296     i += 1
1297
1298 def revert_href(document):
1299     'Reverts hyperlink insets (href) to url insets (url)'
1300     i = 0
1301     while True:
1302       i = find_token(document.body, "\\begin_inset CommandInset href", i)
1303       if i == -1:
1304           return
1305       document.body[i : i + 2] = \
1306         ["\\begin_inset CommandInset url", "LatexCommand url"]
1307       i = i + 2
1308
1309 def revert_url(document):
1310     'Reverts Flex URL insets to old-style URL insets'
1311     i = 0
1312     while True:
1313         i = find_token(document.body, "\\begin_inset Flex URL", i)
1314         if i == -1:
1315             return
1316         j = find_end_of_inset(document.body, i)
1317         if j == -1:
1318             document.warning("Can't find end of inset in revert_url!")
1319             return
1320         k = find_default_layout(document, i, j)
1321         if k == -1:
1322             document.warning("Can't find default layout in revert_url!")
1323             i = j
1324             continue
1325         l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1326         if l == -1 or l >= j:
1327             document.warning("Can't find end of default layout in revert_url!")
1328             i = j
1329             continue
1330         # OK, so the inset's data is between lines k and l.
1331         data =  " ".join(document.body[k+1:l])
1332         data = data.strip()
1333         newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1334                     "", "\\end_inset"]
1335         document.body[i:j+1] = newinset
1336         i = i + len(newinset)
1337
1338
1339 def convert_include(document):
1340   'Converts include insets to new format.'
1341   i = 0
1342   r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1343   while True:
1344     i = find_token(document.body, "\\begin_inset Include", i)
1345     if i == -1:
1346       return
1347     line = document.body[i]
1348     previewline = document.body[i + 1]
1349     m = r.match(line)
1350     if m == None:
1351       document.warning("Unable to match line " + str(i) + " of body!")
1352       i += 1
1353       continue
1354     cmd = m.group(1)
1355     fn  = m.group(2)
1356     opt = m.group(3)
1357     insertion = ["\\begin_inset CommandInset include",
1358        "LatexCommand " + cmd, previewline,
1359        "filename \"" + fn + "\""]
1360     newlines = 2
1361     if opt:
1362       insertion.append("lstparams " + '"' + opt + '"')
1363       newlines += 1
1364     document.body[i : i + 2] = insertion
1365     i += newlines
1366
1367
1368 def revert_include(document):
1369   'Reverts include insets to old format.'
1370   i = 0
1371   r0 = re.compile('preview.*')
1372   r1 = re.compile('LatexCommand (.+)')
1373   r2 = re.compile('filename "(.+)"')
1374   r3 = re.compile('lstparams "(.*)"')
1375   while True:
1376     i = find_token(document.body, "\\begin_inset CommandInset include", i)
1377     if i == -1:
1378       return
1379     nextline = i + 1
1380     if r0.match(document.body[nextline]):
1381       previewline = document.body[nextline]
1382       nextline += 1
1383     else:
1384       previewline = ""
1385     m = r1.match(document.body[nextline])
1386     if m == None:
1387       document.warning("Malformed LyX document: No LatexCommand line for `" +
1388         document.body[i] + "' on line " + str(i) + ".")
1389       i += 1
1390       continue
1391     cmd = m.group(1)
1392     nextline += 1
1393     m = r2.match(document.body[nextline])
1394     if m == None:
1395       document.warning("Malformed LyX document: No filename line for `" + \
1396         document.body[i] + "' on line " + str(i) + ".")
1397       i += 2
1398       continue
1399     fn = m.group(1)
1400     nextline += 1
1401     options = ""
1402     if (cmd == "lstinputlisting"):
1403       m = r3.match(document.body[nextline])
1404       if m != None:
1405         options = m.group(1)
1406         numlines = 5
1407         nextline += 1
1408     newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1409     if options:
1410       newline += ("[" + options + "]")
1411     insertion = [newline]
1412     if previewline != "":
1413       insertion.append(previewline)
1414     document.body[i : nextline] = insertion
1415     i += 2
1416
1417
1418 def revert_albanian(document):
1419     "Set language Albanian to English"
1420     i = 0
1421     if document.language == "albanian":
1422         document.language = "english"
1423         i = find_token(document.header, "\\language", 0)
1424         if i != -1:
1425             document.header[i] = "\\language english"
1426     j = 0
1427     while True:
1428         j = find_token(document.body, "\\lang albanian", j)
1429         if j == -1:
1430             return
1431         document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1432         j = j + 1
1433
1434
1435 def revert_lowersorbian(document):
1436     "Set language lower Sorbian to English"
1437     i = 0
1438     if document.language == "lowersorbian":
1439         document.language = "english"
1440         i = find_token(document.header, "\\language", 0)
1441         if i != -1:
1442             document.header[i] = "\\language english"
1443     j = 0
1444     while True:
1445         j = find_token(document.body, "\\lang lowersorbian", j)
1446         if j == -1:
1447             return
1448         document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1449         j = j + 1
1450
1451
1452 def revert_uppersorbian(document):
1453     "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1454     i = 0
1455     if document.language == "uppersorbian":
1456         document.language = "usorbian"
1457         i = find_token(document.header, "\\language", 0)
1458         if i != -1:
1459             document.header[i] = "\\language usorbian"
1460     j = 0
1461     while True:
1462         j = find_token(document.body, "\\lang uppersorbian", j)
1463         if j == -1:
1464             return
1465         document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1466         j = j + 1
1467
1468
1469 def convert_usorbian(document):
1470     "Set language usorbian to uppersorbian"
1471     i = 0
1472     if document.language == "usorbian":
1473         document.language = "uppersorbian"
1474         i = find_token(document.header, "\\language", 0)
1475         if i != -1:
1476             document.header[i] = "\\language uppersorbian"
1477     j = 0
1478     while True:
1479         j = find_token(document.body, "\\lang usorbian", j)
1480         if j == -1:
1481             return
1482         document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1483         j = j + 1
1484
1485
1486 def revert_macro_optional_params(document):
1487     "Convert macro definitions with optional parameters into ERTs"
1488     # Stub to convert macro definitions with one or more optional parameters
1489     # into uninterpreted ERT insets
1490
1491
1492 def revert_hyperlinktype(document):
1493     'Reverts hyperlink type'
1494     i = 0
1495     j = 0
1496     while True:
1497       i = find_token(document.body, "target", i)
1498       if i == -1:
1499           return
1500       j = find_token(document.body, "type", i)
1501       if j == -1:
1502           return
1503       if j == i + 1:
1504           del document.body[j]
1505       i = i + 1
1506
1507
1508 def revert_pagebreak(document):
1509     'Reverts pagebreak to ERT'
1510     i = 0
1511     while True:
1512       i = find_token(document.body, "\\pagebreak", i)
1513       if i == -1:
1514           return
1515       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1516       '\\begin_layout Standard\n\n\n\\backslash\n' \
1517       'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1518       i = i + 1
1519
1520
1521 def revert_linebreak(document):
1522     'Reverts linebreak to ERT'
1523     i = 0
1524     while True:
1525       i = find_token(document.body, "\\linebreak", i)
1526       if i == -1:
1527           return
1528       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1529       '\\begin_layout Standard\n\n\n\\backslash\n' \
1530       'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1531       i = i + 1
1532
1533
1534 def revert_latin(document):
1535     "Set language Latin to English"
1536     i = 0
1537     if document.language == "latin":
1538         document.language = "english"
1539         i = find_token(document.header, "\\language", 0)
1540         if i != -1:
1541             document.header[i] = "\\language english"
1542     j = 0
1543     while True:
1544         j = find_token(document.body, "\\lang latin", j)
1545         if j == -1:
1546             return
1547         document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1548         j = j + 1
1549
1550
1551 def revert_samin(document):
1552     "Set language North Sami to English"
1553     i = 0
1554     if document.language == "samin":
1555         document.language = "english"
1556         i = find_token(document.header, "\\language", 0)
1557         if i != -1:
1558             document.header[i] = "\\language english"
1559     j = 0
1560     while True:
1561         j = find_token(document.body, "\\lang samin", j)
1562         if j == -1:
1563             return
1564         document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1565         j = j + 1
1566
1567
1568 def convert_serbocroatian(document):
1569     "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1570     i = 0
1571     if document.language == "serbocroatian":
1572         document.language = "croatian"
1573         i = find_token(document.header, "\\language", 0)
1574         if i != -1:
1575             document.header[i] = "\\language croatian"
1576     j = 0
1577     while True:
1578         j = find_token(document.body, "\\lang serbocroatian", j)
1579         if j == -1:
1580             return
1581         document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1582         j = j + 1
1583
1584
1585 def convert_framed_notes(document):
1586     "Convert framed notes to boxes. "
1587     i = 0
1588     while 1:
1589         i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1590         if i == -1:
1591             return
1592         subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1593                  'position "t"',
1594                  'hor_pos "c"',
1595                  'has_inner_box 0',
1596                  'inner_pos "t"', 
1597                  'use_parbox 0',
1598                  'width "100col%"',
1599                  'special "none"',
1600                  'height "1in"',
1601                  'height_special "totalheight"']
1602         document.body[i:i+1] = subst
1603         i = i + 9
1604
1605
1606 def convert_module_names(document):
1607   modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1608     'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1609     'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1610     'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1611     'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1612   modlist = document.get_module_list()
1613   if len(modlist) == 0:
1614     return
1615   newmodlist = []
1616   for mod in modlist:
1617     if modulemap.has_key(mod):
1618       newmodlist.append(modulemap[mod])
1619     else:
1620       document.warning("Can't find module %s in the module map!" % mod)
1621       newmodlist.append(mod)
1622   document.set_module_list(newmodlist)
1623
1624
1625 def revert_module_names(document):
1626   modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1627     'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1628     'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1629     'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1630     'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1631   modlist = document.get_module_list()
1632   if len(modlist) == 0:
1633     return
1634   newmodlist = []
1635   for mod in modlist:
1636     if modulemap.has_key(mod):
1637       newmodlist.append(modulemap[mod])
1638     else:
1639       document.warning("Can't find module %s in the module map!" % mod)
1640       newmodlist.append(mod)
1641   document.set_module_list(newmodlist)
1642
1643
1644 def revert_colsep(document):
1645     i = find_token(document.header, "\\columnsep", 0)
1646     if i == -1:
1647         return
1648     colsepline = document.header[i]
1649     r = re.compile(r'\\columnsep (.*)')
1650     m = r.match(colsepline)
1651     if not m:
1652         document.warning("Malformed column separation line!")
1653         return
1654     colsep = m.group(1)
1655     del document.header[i]
1656     #it seems to be safe to add the package even if it is already used
1657     pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1658
1659     add_to_preamble(document, pretext)
1660
1661
1662 def revert_framed_notes(document):
1663     "Revert framed boxes to notes. "
1664     i = 0
1665     while 1:
1666         i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1667
1668         if i == -1:
1669             return
1670         j = find_end_of_inset(document.body, i + 1)
1671         if j == -1:
1672             # should not happen
1673             document.warning("Malformed LyX document: Could not find end of Box inset.")
1674         k = find_token(document.body, "status", i + 1, j)
1675         if k == -1:
1676             document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1677             return
1678         status = document.body[k]
1679         l = find_default_layout(document, i + 1, j)
1680         if l == -1:
1681             document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1682             return
1683         m = find_token(document.body, "\\end_layout", i + 1, j)
1684         if m == -1:
1685             document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1686             return
1687         ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1688         pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1689         if ibox == -1 and pbox == -1:
1690             document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1691             del document.body[i+1:k]
1692         else:
1693             document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1694             subst1 = [document.body[l],
1695                       "\\begin_inset Note Shaded",
1696                       status,
1697                       '\\begin_layout Standard']
1698             document.body[l:l + 1] = subst1
1699             subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1700             document.body[m:m + 1] = subst2
1701         i = i + 1
1702
1703
1704 def revert_slash(document):
1705     'Revert \\SpecialChar \\slash{} to ERT'
1706     r = re.compile(r'\\SpecialChar \\slash{}')
1707     i = 0
1708     while i < len(document.body):
1709         m = r.match(document.body[i])
1710         if m:
1711           subst = ['\\begin_inset ERT',
1712                    'status collapsed', '',
1713                    '\\begin_layout Standard',
1714                    '', '', '\\backslash',
1715                    'slash{}',
1716                    '\\end_layout', '',
1717                    '\\end_inset', '']
1718           document.body[i: i+1] = subst
1719           i = i + len(subst)
1720         else:
1721           i = i + 1
1722
1723
1724 def revert_nobreakdash(document):
1725     'Revert \\SpecialChar \\nobreakdash- to ERT'
1726     i = 0
1727     while i < len(document.body):
1728         line = document.body[i]
1729         r = re.compile(r'\\SpecialChar \\nobreakdash-')
1730         m = r.match(line)
1731         if m:
1732             subst = ['\\begin_inset ERT',
1733                     'status collapsed', '',
1734                     '\\begin_layout Standard', '', '',
1735                     '\\backslash',
1736                     'nobreakdash-',
1737                     '\\end_layout', '',
1738                     '\\end_inset', '']
1739             document.body[i:i+1] = subst
1740             i = i + len(subst)
1741             j = find_token(document.header, "\\use_amsmath", 0)
1742             if j == -1:
1743                 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1744                 return
1745             document.header[j] = "\\use_amsmath 2"
1746         else:
1747             i = i + 1
1748
1749
1750 #Returns number of lines added/removed
1751 def revert_nocite_key(body, start, end):
1752     'key "..." -> \nocite{...}' 
1753     r = re.compile(r'^key "(.*)"')
1754     i = start
1755     j = end
1756     while i < j:
1757         m = r.match(body[i])
1758         if m:
1759             body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1760             j += 1     # because we added a line
1761             i += 2     # skip that line
1762         else:
1763             del body[i]
1764             j -= 1     # because we deleted a line
1765             # no need to change i, since it now points to the next line
1766     return j - end
1767
1768
1769 def revert_nocite(document):
1770     "Revert LatexCommand nocite to ERT"
1771     i = 0
1772     while 1:
1773         i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1774         if i == -1:
1775             return
1776         if (document.body[i+1] != "LatexCommand nocite"):
1777             # note that we already incremented i
1778             i = i + 1
1779             continue
1780         insetEnd = find_end_of_inset(document.body, i)
1781         if insetEnd == -1:
1782             #this should not happen
1783             document.warning("End of CommandInset citation not found in revert_nocite!")
1784             return
1785
1786         paramLocation = i + 2 #start of the inset's parameters
1787         addedLines = 0
1788         document.body[i:i+2] = \
1789             ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1790         # that added two lines
1791         paramLocation += 2
1792         insetEnd += 2
1793         #print insetEnd, document.body[i: insetEnd + 1]
1794         insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1795         #print insetEnd, document.body[i: insetEnd + 1]
1796         document.body.insert(insetEnd, "\\end_layout")
1797         document.body.insert(insetEnd + 1, "")
1798         i = insetEnd + 1
1799
1800
1801 def revert_btprintall(document):
1802     "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1803     i = find_token(document.header, '\\use_bibtopic', 0)
1804     if i == -1:
1805         document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1806         return
1807     if get_value(document.header, '\\use_bibtopic', 0) == "false":
1808         i = 0
1809         while i < len(document.body):
1810             i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1811             if i == -1:
1812                 return
1813             j = find_end_of_inset(document.body, i + 1)
1814             if j == -1:
1815                 #this should not happen
1816                 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1817                 j = len(document.body)
1818             # this range isn't really right, but it should be OK, since we shouldn't
1819             # see more than one matching line in each inset
1820             addedlines = 0
1821             for k in range(i, j):
1822                 if (document.body[k] == 'btprint "btPrintAll"'):
1823                     del document.body[k]
1824                     subst = ["\\begin_inset ERT",
1825                              "status collapsed", "",
1826                              "\\begin_layout Standard", "",
1827                              "\\backslash",
1828                              "nocite{*}",
1829                              "\\end_layout",
1830                              "\\end_inset"]
1831                     document.body[i:i] = subst
1832                     addlines = addedlines + len(subst) - 1
1833             i = j + addedlines
1834
1835
1836 def revert_bahasam(document):
1837     "Set language Bahasa Malaysia to Bahasa Indonesia"
1838     i = 0
1839     if document.language == "bahasam":
1840         document.language = "bahasa"
1841         i = find_token(document.header, "\\language", 0)
1842         if i != -1:
1843             document.header[i] = "\\language bahasa"
1844     j = 0
1845     while True:
1846         j = find_token(document.body, "\\lang bahasam", j)
1847         if j == -1:
1848             return
1849         document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1850         j = j + 1
1851
1852
1853 def revert_interlingua(document):
1854     "Set language Interlingua to English"
1855     i = 0
1856     if document.language == "interlingua":
1857         document.language = "english"
1858         i = find_token(document.header, "\\language", 0)
1859         if i != -1:
1860             document.header[i] = "\\language english"
1861     j = 0
1862     while True:
1863         j = find_token(document.body, "\\lang interlingua", j)
1864         if j == -1:
1865             return
1866         document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1867         j = j + 1
1868
1869
1870 def revert_serbianlatin(document):
1871     "Set language Serbian-Latin to Croatian"
1872     i = 0
1873     if document.language == "serbian-latin":
1874         document.language = "croatian"
1875         i = find_token(document.header, "\\language", 0)
1876         if i != -1:
1877             document.header[i] = "\\language croatian"
1878     j = 0
1879     while True:
1880         j = find_token(document.body, "\\lang serbian-latin", j)
1881         if j == -1:
1882             return
1883         document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
1884         j = j + 1
1885
1886
1887 def revert_rotfloat(document):
1888     " Revert sideways custom floats. "
1889     i = 0
1890     while 1:
1891         # whitespace intended (exclude \\begin_inset FloatList)
1892         i = find_token(document.body, "\\begin_inset Float ", i)
1893         if i == -1:
1894             return
1895         line = document.body[i]
1896         r = re.compile(r'\\begin_inset Float (.*)$')
1897         m = r.match(line)
1898         if m == None:
1899             document.warning("Unable to match line " + str(i) + " of body!")
1900             i += 1
1901             continue
1902         floattype = m.group(1)
1903         if floattype == "figure" or floattype == "table":
1904             i += 1
1905             continue
1906         j = find_end_of_inset(document.body, i)
1907         if j == -1:
1908             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
1909             i += 1
1910             continue
1911         addedLines = 0
1912         if get_value(document.body, 'sideways', i, j) == "false":
1913             i += 1
1914             continue
1915         l = find_default_layout(document, i + 1, j)
1916         if l == -1:
1917             document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1918             return
1919         subst = ['\\begin_layout Standard',
1920                   '\\begin_inset ERT',
1921                   'status collapsed', '',
1922                   '\\begin_layout Standard', '', '', 
1923                   '\\backslash', '',
1924                   'end{sideways' + floattype + '}',
1925                   '\\end_layout', '', '\\end_inset']
1926         document.body[j : j+1] = subst
1927         addedLines = len(subst) - 1
1928         del document.body[i+1 : l]
1929         addedLines -= (l-1) - (i+1) 
1930         subst = ['\\begin_inset ERT', 'status collapsed', '',
1931                   '\\begin_layout Standard', '', '', '\\backslash', 
1932                   'begin{sideways' + floattype + '}', 
1933                   '\\end_layout', '', '\\end_inset', '',
1934                   '\\end_layout', '']
1935         document.body[i : i+1] = subst
1936         addedLines += len(subst) - 1
1937         if floattype == "algorithm":
1938             add_to_preamble(document,
1939                             ['% Commands inserted by lyx2lyx for sideways algorithm float',
1940                               '\\usepackage{rotfloat}',
1941                               '\\floatstyle{ruled}',
1942                               '\\newfloat{algorithm}{tbp}{loa}',
1943                               '\\floatname{algorithm}{Algorithm}'])
1944         else:
1945             document.warning("Cannot create preamble definition for custom float" + floattype + ".")
1946         i += addedLines + 1
1947
1948
1949 def revert_widesideways(document):
1950     " Revert wide sideways floats. "
1951     i = 0
1952     while 1:
1953         # whitespace intended (exclude \\begin_inset FloatList)
1954         i = find_token(document.body, '\\begin_inset Float ', i)
1955         if i == -1:
1956             return
1957         line = document.body[i]
1958         r = re.compile(r'\\begin_inset Float (.*)$')
1959         m = r.match(line)
1960         if m == None:
1961             document.warning("Unable to match line " + str(i) + " of body!")
1962             i += 1
1963             continue
1964         floattype = m.group(1)
1965         if floattype != "figure" and floattype != "table":
1966             i += 1
1967             continue
1968         j = find_end_of_inset(document.body, i)
1969         if j == -1:
1970             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
1971             i += 1
1972             continue
1973         if get_value(document.body, 'sideways', i, j) == "false" or \
1974            get_value(document.body, 'wide', i, j) == "false":
1975              i += 1
1976              continue
1977         l = find_default_layout(document, i + 1, j)
1978         if l == -1:
1979             document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1980             return
1981         subst = ['\\begin_layout Standard', '\\begin_inset ERT', 
1982                   'status collapsed', '', 
1983                   '\\begin_layout Standard', '', '', '\\backslash',
1984                   'end{sideways' + floattype + '*}', 
1985                   '\\end_layout', '', '\\end_inset']
1986         document.body[j : j+1] = subst
1987         addedLines = len(subst) - 1
1988         del document.body[i+1:l-1]
1989         addedLines -= (l-1) - (i+1)
1990         subst = ['\\begin_inset ERT', 'status collapsed', '',
1991                  '\\begin_layout Standard', '', '', '\\backslash',
1992                  'begin{sideways' + floattype + '*}', '\\end_layout', '',
1993                  '\\end_inset', '', '\\end_layout', '']
1994         document.body[i : i+1] = subst
1995         addedLines += len(subst) - 1
1996         add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
1997         i += addedLines + 1
1998
1999
2000 def revert_inset_embedding(document, type):
2001     ' Remove embed tag from certain type of insets'
2002     i = 0
2003     while 1:
2004         i = find_token(document.body, "\\begin_inset %s" % type, i)
2005         if i == -1:
2006             return
2007         j = find_end_of_inset(document.body, i)
2008         if j == -1:
2009             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2010             i = i + 1
2011             continue
2012         k = find_token(document.body, "\tembed", i, j)
2013         if k == -1:
2014             k = find_token(document.body, "embed", i, j)
2015         if k != -1:
2016             del document.body[k]
2017         i = i + 1
2018
2019
2020 def revert_external_embedding(document):
2021     ' Remove embed tag from external inset '
2022     revert_inset_embedding(document, 'External')
2023
2024
2025 def convert_subfig(document):
2026     " Convert subfigures to subfloats. "
2027     i = 0
2028     while 1:
2029         i = find_token(document.body, '\\begin_inset Graphics', i)
2030         if i == -1:
2031             return
2032         endInset = find_end_of_inset(document.body, i)
2033         if endInset == -1:
2034             document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2035             i += 1
2036             continue
2037         k = find_token(document.body, '\tsubcaption', i, endInset)
2038         if k == -1:
2039             i = endInset
2040             continue
2041         l = find_token(document.body, '\tsubcaptionText', i, endInset)
2042         if l == -1:
2043             document.warning("Malformed lyx document: Can't find subcaptionText!")
2044             i = endInset
2045             continue
2046         caption = document.body[l][16:].strip('"')
2047         del document.body[l]
2048         del document.body[k]
2049         addedLines = -2
2050         subst = ['\\begin_inset Float figure', 'wide false', 'sideways false', 
2051                  'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption', 
2052                  '', '\\begin_layout Plain Layout'] + latex2lyx(caption) + \
2053                  [ '\\end_layout', '', '\\end_inset', '', 
2054                  '\\end_layout', '', '\\begin_layout Plain Layout']
2055         document.body[i : i] = subst
2056         addedLines += len(subst)
2057         endInset += addedLines
2058         subst = ['', '\\end_inset', '', '\\end_layout']
2059         document.body[endInset : endInset] = subst
2060         addedLines += len(subst)
2061         i += addedLines + 1
2062
2063
2064 def revert_subfig(document):
2065     " Revert subfloats. "
2066     i = 0
2067     while 1:
2068         # whitespace intended (exclude \\begin_inset FloatList)
2069         i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2070         if i == -1:
2071             return
2072         j = 0
2073         addedLines = 0
2074         while j != -1:
2075             j = find_end_of_inset(document.body, i)
2076             if j == -1:
2077                 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2078                 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2079                 i += 1
2080                 continue # this will get us back to the outer loop, since j == -1
2081             # look for embedded float (= subfloat)
2082             # whitespace intended (exclude \\begin_inset FloatList)
2083             k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2084             if k == -1:
2085                 break
2086             l = find_end_of_inset(document.body, k)
2087             if l == -1:
2088                 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2089                 i += 1
2090                 j == -1
2091                 continue # escape to the outer loop
2092             m = find_default_layout(document, k + 1, l)
2093             # caption?
2094             cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2095             caption = ''
2096             shortcap = ''
2097             capend = cap
2098             if cap != -1:
2099                 capend = find_end_of_inset(document.body, cap)
2100                 if capend == -1:
2101                     document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2102                     return
2103                 # label?
2104                 label = ''
2105                 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2106                 if lbl != -1:
2107                     lblend = find_end_of_inset(document.body, lbl + 1)
2108                     if lblend == -1:
2109                         document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2110                         return
2111                     for line in document.body[lbl:lblend + 1]:
2112                         if line.startswith('name '):
2113                             label = line.split()[1].strip('"')
2114                             break
2115                 else:
2116                     lbl = capend
2117                     lblend = capend
2118                     label = ''
2119                 # opt arg?
2120                 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2121                 if opt != -1:
2122                     optend = find_end_of_inset(document.body, opt)
2123                     if optend == -1:
2124                         document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
2125                         return
2126                     optc = find_default_layout(document, opt, optend)
2127                     if optc == -1:
2128                         document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2129                         return
2130                     optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2131                     for line in document.body[optc:optcend]:
2132                         if not line.startswith('\\'):
2133                             shortcap += line.strip()
2134                 else:
2135                     opt = capend
2136                     optend = capend
2137                 for line in document.body[cap:capend]:
2138                     if line in document.body[lbl:lblend]:
2139                         continue
2140                     elif line in document.body[opt:optend]:
2141                         continue
2142                     elif not line.startswith('\\'):
2143                         caption += line.strip()
2144                 if len(label) > 0:
2145                     caption += "\\backslash\nlabel{" + label + "}"
2146             subst = '\\begin_layout Plain Layout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2147                       '\\begin_layout Plain Layout\n\n}\n\\end_layout\n\n\\end_inset\n\n' \
2148                       '\\end_layout\n\n\\begin_layout Plain Layout\n'
2149             subst = subst.split('\n')
2150             document.body[l : l+1] = subst
2151             addedLines = len(subst) - 1
2152             # this is before l and so is unchanged by the multiline insertion
2153             if cap != capend:
2154                 del document.body[cap:capend+1]
2155                 addedLines -= (capend + 1 - cap)
2156             del document.body[k+1:m-1]
2157             addedLines -= (m - 1 - (k + 1))
2158             insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2159                         '\\begin_layout Plain Layout\n\n\\backslash\n' \
2160                         'subfloat'
2161             if len(shortcap) > 0:
2162                 insertion = insertion + "[" + shortcap + "]"
2163             if len(caption) > 0:
2164                 insertion = insertion + "[" + caption + "]"
2165             insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2166             insertion = insertion.split('\n')
2167             document.body[k : k + 1] = insertion
2168             addedLines += len(insertion) - 1
2169             add_to_preamble(document, ['\\usepackage{subfig}\n'])
2170         i += addedLines + 1
2171
2172
2173 def revert_wrapplacement(document):
2174     " Revert placement options wrap floats (wrapfig). "
2175     i = 0
2176     while True:
2177         i = find_token(document.body, "\\begin_inset Wrap figure", i)
2178         if i == -1:
2179             return
2180         e = find_end_of_inset(document.body, i)
2181         j = find_token(document.body, "placement", i + 1, e)
2182         if j == -1:
2183             document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2184             i += 1
2185             continue
2186         r = re.compile("placement (o|i|l|r)")
2187         m = r.match(document.body[j])
2188         if m == None:
2189             document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2190         document.body[j] = "placement " + m.group(1).lower()
2191         i = j
2192
2193
2194 def remove_extra_embedded_files(document):
2195     " Remove \extra_embedded_files from buffer params "
2196     i = find_token(document.header, '\\extra_embedded_files', 0)
2197     if i == -1:
2198         return
2199     document.header.pop(i)
2200
2201
2202 def convert_spaceinset(document):
2203     " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2204     i = 0
2205     while i < len(document.body):
2206         m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2207         if m:
2208             before = m.group(1)
2209             after = m.group(2)
2210             subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2211             document.body[i: i+1] = subst
2212             i = i + len(subst)
2213         else:
2214             i = i + 1
2215
2216
2217 def revert_spaceinset(document):
2218     " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2219     i = 0
2220     while True:
2221         i = find_token(document.body, "\\begin_inset Space", i)
2222         if i == -1:
2223             return
2224         j = find_end_of_inset(document.body, i)
2225         if j == -1:
2226             document.warning("Malformed LyX document: Could not find end of space inset.")
2227             continue
2228         document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2229         del document.body[j]
2230
2231
2232 def convert_hfill(document):
2233     " Convert hfill to space inset "
2234     i = 0
2235     while True:
2236         i = find_token(document.body, "\\hfill", i)
2237         if i == -1:
2238             return
2239         subst = document.body[i].replace('\\hfill', \
2240                   '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2241         subst = subst.split('\n')
2242         document.body[i : i+1] = subst
2243         i += len(subst)
2244
2245
2246 def revert_hfills(document):
2247     ' Revert \\hfill commands '
2248     hfill = re.compile(r'\\hfill')
2249     dotfill = re.compile(r'\\dotfill')
2250     hrulefill = re.compile(r'\\hrulefill')
2251     i = 0
2252     while True:
2253         i = find_token(document.body, "\\InsetSpace", i)
2254         if i == -1:
2255             return
2256         if hfill.search(document.body[i]):
2257             document.body[i] = \
2258               document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2259             i += 1
2260             continue
2261         if dotfill.search(document.body[i]):
2262             subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2263               '\\begin_inset ERT\nstatus collapsed\n\n' \
2264               '\\begin_layout Standard\n\n\n\\backslash\n' \
2265               'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2266             subst = subst.split('\n')
2267             document.body[i : i+1] = subst
2268             i += len(subst)
2269             continue
2270         if hrulefill.search(document.body[i]):
2271             subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2272               '\\begin_inset ERT\nstatus collapsed\n\n' \
2273               '\\begin_layout Standard\n\n\n\\backslash\n' \
2274               'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2275             subst = subst.split('\n')
2276             document.body[i : i+1] = subst
2277             i += len(subst)
2278             continue
2279         i += 1
2280
2281 def revert_hspace(document):
2282     ' Revert \\InsetSpace \\hspace{} to ERT '
2283     i = 0
2284     hspace = re.compile(r'\\hspace{}')
2285     hstar  = re.compile(r'\\hspace\*{}')
2286     while True:
2287         i = find_token(document.body, "\\InsetSpace \\hspace", i)
2288         if i == -1:
2289             return
2290         length = get_value(document.body, '\\length', i+1)
2291         if length == '':
2292             document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2293             return
2294         del document.body[i+1]
2295         addedLines = -1
2296         if hstar.search(document.body[i]):
2297             subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2298               '\\begin_inset ERT\nstatus collapsed\n\n' \
2299               '\\begin_layout Standard\n\n\n\\backslash\n' \
2300               'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2301             subst = subst.split('\n')
2302             document.body[i : i+1] = subst
2303             addedLines += len(subst) - 1
2304             i += addedLines + 1
2305             continue
2306         if hspace.search(document.body[i]):
2307             subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2308               '\\begin_inset ERT\nstatus collapsed\n\n' \
2309               '\\begin_layout Standard\n\n\n\\backslash\n' \
2310               'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2311             subst = subst.split('\n')
2312             document.body[i : i+1] = subst
2313             addedLines += len(subst) - 1
2314             i += addedLines + 1
2315             continue
2316         i += 1
2317
2318
2319 def revert_protected_hfill(document):
2320     ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2321     i = 0
2322     while True:
2323         i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2324         if i == -1:
2325             return
2326         j = find_end_of_inset(document.body, i)
2327         if j == -1:
2328             document.warning("Malformed LyX document: Could not find end of space inset.")
2329             continue
2330         del document.body[j]
2331         subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2332           '\\begin_inset ERT\nstatus collapsed\n\n' \
2333           '\\begin_layout Standard\n\n\n\\backslash\n' \
2334           'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2335         subst = subst.split('\n')
2336         document.body[i : i+1] = subst
2337         i += len(subst)
2338
2339
2340 def revert_leftarrowfill(document):
2341     ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2342     i = 0
2343     while True:
2344         i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2345         if i == -1:
2346             return
2347         j = find_end_of_inset(document.body, i)
2348         if j == -1:
2349             document.warning("Malformed LyX document: Could not find end of space inset.")
2350             continue
2351         del document.body[j]
2352         subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2353           '\\begin_inset ERT\nstatus collapsed\n\n' \
2354           '\\begin_layout Standard\n\n\n\\backslash\n' \
2355           'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2356         subst = subst.split('\n')
2357         document.body[i : i+1] = subst
2358         i += len(subst)
2359
2360
2361 def revert_rightarrowfill(document):
2362     ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2363     i = 0
2364     while True:
2365         i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2366         if i == -1:
2367             return
2368         j = find_end_of_inset(document.body, i)
2369         if j == -1:
2370             document.warning("Malformed LyX document: Could not find end of space inset.")
2371             continue
2372         del document.body[j]
2373         subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2374           '\\begin_inset ERT\nstatus collapsed\n\n' \
2375           '\\begin_layout Standard\n\n\n\\backslash\n' \
2376           'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2377         subst = subst.split('\n')
2378         document.body[i : i+1] = subst
2379         i += len(subst)
2380
2381
2382 def revert_upbracefill(document):
2383     ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2384     i = 0
2385     while True:
2386         i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2387         if i == -1:
2388             return
2389         j = find_end_of_inset(document.body, i)
2390         if j == -1:
2391             document.warning("Malformed LyX document: Could not find end of space inset.")
2392             continue
2393         del document.body[j]
2394         subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2395           '\\begin_inset ERT\nstatus collapsed\n\n' \
2396           '\\begin_layout Standard\n\n\n\\backslash\n' \
2397           'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2398         subst = subst.split('\n')
2399         document.body[i : i+1] = subst
2400         i += len(subst)
2401
2402
2403 def revert_downbracefill(document):
2404     ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2405     i = 0
2406     while True:
2407         i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2408         if i == -1:
2409             return
2410         j = find_end_of_inset(document.body, i)
2411         if j == -1:
2412             document.warning("Malformed LyX document: Could not find end of space inset.")
2413             continue
2414         del document.body[j]
2415         subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2416           '\\begin_inset ERT\nstatus collapsed\n\n' \
2417           '\\begin_layout Standard\n\n\n\\backslash\n' \
2418           'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2419         subst = subst.split('\n')
2420         document.body[i : i+1] = subst
2421         i += len(subst)
2422
2423
2424 def revert_local_layout(document):
2425     ' Revert local layout headers.'
2426     i = 0
2427     while True:
2428         i = find_token(document.header, "\\begin_local_layout", i)
2429         if i == -1:
2430             return
2431         j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2432         if j == -1:
2433             # this should not happen
2434             break
2435         document.header[i : j + 1] = []
2436
2437
2438 def convert_pagebreaks(document):
2439     ' Convert inline Newpage insets to new format '
2440     i = 0
2441     while True:
2442         i = find_token(document.body, '\\newpage', i)
2443         if i == -1:
2444             break
2445         document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2446                                 '\\end_inset']
2447     i = 0
2448     while True:
2449         i = find_token(document.body, '\\pagebreak', i)
2450         if i == -1:
2451             break
2452         document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2453                                 '\\end_inset']
2454     i = 0
2455     while True:
2456         i = find_token(document.body, '\\clearpage', i)
2457         if i == -1:
2458             break
2459         document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2460                                 '\\end_inset']
2461     i = 0
2462     while True:
2463         i = find_token(document.body, '\\cleardoublepage', i)
2464         if i == -1:
2465             break
2466         document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2467                                 '\\end_inset']
2468
2469
2470 def revert_pagebreaks(document):
2471     ' Revert \\begin_inset Newpage to previous inline format '
2472     i = 0
2473     while True:
2474         i = find_token(document.body, '\\begin_inset Newpage', i)
2475         if i == -1:
2476             return
2477         j = find_end_of_inset(document.body, i)
2478         if j == -1:
2479             document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2480             continue
2481         del document.body[j]
2482         document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2483         document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2484         document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2485         document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2486
2487
2488 def convert_linebreaks(document):
2489     ' Convert inline Newline insets to new format '
2490     i = 0
2491     while True:
2492         i = find_token(document.body, '\\newline', i)
2493         if i == -1:
2494             break
2495         document.body[i:i+1] = ['\\begin_inset Newline newline',
2496                                 '\\end_inset']
2497     i = 0
2498     while True:
2499         i = find_token(document.body, '\\linebreak', i)
2500         if i == -1:
2501             break
2502         document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2503                                 '\\end_inset']
2504
2505
2506 def revert_linebreaks(document):
2507     ' Revert \\begin_inset Newline to previous inline format '
2508     i = 0
2509     while True:
2510         i = find_token(document.body, '\\begin_inset Newline', i)
2511         if i == -1:
2512             return
2513         j = find_end_of_inset(document.body, i)
2514         if j == -1:
2515             document.warning("Malformed LyX document: Could not find end of Newline inset.")
2516             continue
2517         del document.body[j]
2518         document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2519         document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2520
2521
2522 def convert_japanese_plain(document):
2523     ' Set language japanese-plain to japanese '
2524     i = 0
2525     if document.language == "japanese-plain":
2526         document.language = "japanese"
2527         i = find_token(document.header, "\\language", 0)
2528         if i != -1:
2529             document.header[i] = "\\language japanese"
2530     j = 0
2531     while True:
2532         j = find_token(document.body, "\\lang japanese-plain", j)
2533         if j == -1:
2534             return
2535         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2536         j = j + 1
2537
2538
2539 def revert_pdfpages(document):
2540     ' Revert pdfpages external inset to ERT '
2541     i = 0
2542     while 1:
2543         i = find_token(document.body, "\\begin_inset External", i)
2544         if i == -1:
2545             return
2546         j = find_end_of_inset(document.body, i)
2547         if j == -1:
2548             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2549             i = i + 1
2550             continue
2551         if get_value(document.body, 'template', i, j) == "PDFPages":
2552             filename = get_value(document.body, 'filename', i, j)
2553             extra = ''
2554             r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2555             for k in range(i, j):
2556                 m = r.match(document.body[k])
2557                 if m:
2558                     extra = m.group(1)
2559             angle = get_value(document.body, 'rotateAngle', i, j)
2560             width = get_value(document.body, 'width', i, j)
2561             height = get_value(document.body, 'height', i, j)
2562             scale = get_value(document.body, 'scale', i, j)
2563             keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2564             options = extra
2565             if angle != '':
2566                  if options != '':
2567                      options += ",angle=" + angle
2568                  else:
2569                      options += "angle=" + angle
2570             if width != '':
2571                  if options != '':
2572                      options += ",width=" + convert_len(width)
2573                  else:
2574                      options += "width=" + convert_len(width)
2575             if height != '':
2576                  if options != '':
2577                      options += ",height=" + convert_len(height)
2578                  else:
2579                      options += "height=" + convert_len(height)
2580             if scale != '':
2581                  if options != '':
2582                      options += ",scale=" + scale
2583                  else:
2584                      options += "scale=" + scale
2585             if keepAspectRatio != '':
2586                  if options != '':
2587                      options += ",keepaspectratio"
2588                  else:
2589                      options += "keepaspectratio"
2590             if options != '':
2591                      options = '[' + options + ']'
2592             del document.body[i+1:j+1]
2593             document.body[i:i+1] = ['\\begin_inset ERT',
2594                                 'status collapsed',
2595                                 '',
2596                                 '\\begin_layout Standard',
2597                                 '',
2598                                 '\\backslash',
2599                                 'includepdf' + options + '{' + filename + '}',
2600                                 '\\end_layout',
2601                                 '',
2602                                 '\\end_inset']
2603             add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2604             i = i + 1
2605             continue
2606         i = i + 1
2607
2608
2609 def revert_mexican(document):
2610     ' Set language Spanish(Mexico) to Spanish '
2611     i = 0
2612     if document.language == "spanish-mexico":
2613         document.language = "spanish"
2614         i = find_token(document.header, "\\language", 0)
2615         if i != -1:
2616             document.header[i] = "\\language spanish"
2617     j = 0
2618     while True:
2619         j = find_token(document.body, "\\lang spanish-mexico", j)
2620         if j == -1:
2621             return
2622         document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2623         j = j + 1
2624
2625
2626 def remove_embedding(document):
2627     ' Remove embed tag from all insets '
2628     revert_inset_embedding(document, 'Graphics')
2629     revert_inset_embedding(document, 'External')
2630     revert_inset_embedding(document, 'CommandInset include')
2631     revert_inset_embedding(document, 'CommandInset bibtex')
2632
2633
2634 def revert_master(document):
2635     ' Remove master param '
2636     i = find_token(document.header, "\\master", 0)
2637     if i != -1:
2638         del document.header[i]
2639
2640
2641 def revert_graphics_group(document):
2642     ' Revert group information from graphics insets '
2643     i = 0
2644     while 1:
2645         i = find_token(document.body, "\\begin_inset Graphics", i)
2646         if i == -1:
2647             return
2648         j = find_end_of_inset(document.body, i)
2649         if j == -1:
2650             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2651             i = i + 1
2652             continue
2653         k = find_token(document.body, " groupId", i, j)
2654         if k == -1:
2655             i = i + 1
2656             continue
2657         del document.body[k]
2658         i = i + 1
2659
2660
2661 def update_apa_styles(document):
2662     ' Replace obsolete styles '
2663
2664     if document.textclass != "apa":
2665         return
2666
2667     obsoletedby = { "Acknowledgments": "Acknowledgements",
2668                     "Section*":        "Section",
2669                     "Subsection*":     "Subsection",
2670                     "Subsubsection*":  "Subsubsection",
2671                     "Paragraph*":      "Paragraph",
2672                     "Subparagraph*":   "Subparagraph"}
2673     i = 0
2674     while 1:
2675         i = find_token(document.body, "\\begin_layout", i)
2676         if i == -1:
2677             return
2678
2679         layout = document.body[i][14:]
2680         if layout in obsoletedby:
2681             document.body[i] = "\\begin_layout " + obsoletedby[layout]
2682
2683         i += 1
2684
2685
2686 def convert_paper_sizes(document):
2687     ' exchange size options legalpaper and executivepaper to correct order '
2688     # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2689     i = 0
2690     j = 0
2691     i = find_token(document.header, "\\papersize executivepaper", 0)
2692     if i != -1:
2693         document.header[i] = "\\papersize legalpaper"
2694         return
2695     j = find_token(document.header, "\\papersize legalpaper", 0)
2696     if j != -1:
2697         document.header[j] = "\\papersize executivepaper"
2698
2699
2700 def revert_paper_sizes(document):
2701     ' exchange size options legalpaper and executivepaper to correct order '
2702     i = 0
2703     j = 0
2704     i = find_token(document.header, "\\papersize executivepaper", 0)
2705     if i != -1:
2706         document.header[i] = "\\papersize legalpaper"
2707         return
2708     j = find_token(document.header, "\\papersize legalpaper", 0)
2709     if j != -1:
2710         document.header[j] = "\\papersize executivepaper"
2711
2712
2713 def convert_InsetSpace(document):
2714     " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2715     i = 0
2716     while True:
2717         i = find_token(document.body, "\\begin_inset Space", i)
2718         if i == -1:
2719             return
2720         document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2721
2722
2723 def revert_InsetSpace(document):
2724     " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2725     i = 0
2726     while True:
2727         i = find_token(document.body, "\\begin_inset space", i)
2728         if i == -1:
2729             return
2730         document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2731
2732
2733 def convert_display_enum(document):
2734     " Convert 'display foo' to 'display false/true'"
2735     i = 0
2736     while True:
2737         i = find_token(document.body, "\tdisplay", i)
2738         if i == -1:
2739             return
2740         val = get_value(document.body, 'display', i)
2741         if val == "none":
2742             document.body[i] = document.body[i].replace('none', 'false')
2743         if val == "default":
2744             document.body[i] = document.body[i].replace('default', 'true')
2745         if val == "monochrome":
2746             document.body[i] = document.body[i].replace('monochrome', 'true')
2747         if val == "grayscale":
2748             document.body[i] = document.body[i].replace('grayscale', 'true')
2749         if val == "color":
2750             document.body[i] = document.body[i].replace('color', 'true')
2751         if val == "preview":
2752             document.body[i] = document.body[i].replace('preview', 'true')
2753         i += 1
2754
2755
2756 def revert_display_enum(document):
2757     " Revert 'display false/true' to 'display none/color'"
2758     i = 0
2759     while True:
2760         i = find_token(document.body, "\tdisplay", i)
2761         if i == -1:
2762             return
2763         val = get_value(document.body, 'display', i)
2764         if val == "false":
2765             document.body[i] = document.body[i].replace('false', 'none')
2766         if val == "true":
2767             document.body[i] = document.body[i].replace('true', 'default')
2768         i += 1
2769
2770
2771 def remove_fontsCJK(document):
2772     ' Remove font_cjk param '
2773     i = find_token(document.header, "\\font_cjk", 0)
2774     if i != -1:
2775         del document.header[i]
2776
2777
2778 def convert_plain_layout(document):
2779     " Convert 'PlainLayout' to 'Plain Layout'" 
2780     i = 0
2781     while True:
2782         i = find_token(document.body, '\\begin_layout PlainLayout', i)
2783         if i == -1:
2784             return
2785         document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2786           '\\begin_layout Plain Layout')
2787         i += 1
2788
2789
2790 def revert_plain_layout(document):
2791     " Convert 'PlainLayout' to 'Plain Layout'" 
2792     i = 0
2793     while True:
2794         i = find_token(document.body, '\\begin_layout Plain Layout', i)
2795         if i == -1:
2796             return
2797         document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2798           '\\begin_layout PlainLayout')
2799         i += 1
2800
2801
2802 def revert_plainlayout(document):
2803     " Convert 'PlainLayout' to 'Plain Layout'" 
2804     i = 0
2805     while True:
2806         i = find_token(document.body, '\\begin_layout PlainLayout', i)
2807         if i == -1:
2808             return
2809         # This will be incorrect for some document classes, since Standard is not always
2810         # the default. But (a) it is probably the best we can do and (b) it will actually
2811         # work, in fact, since an unknown layout will be converted to default.
2812         document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2813           '\\begin_layout Standard')
2814         i += 1
2815
2816
2817 def revert_polytonicgreek(document):
2818     "Set language polytonic Greek to Greek"
2819     i = 0
2820     if document.language == "polutonikogreek":
2821         document.language = "greek"
2822         i = find_token(document.header, "\\language", 0)
2823         if i != -1:
2824             document.header[i] = "\\language greek"
2825     j = 0
2826     while True:
2827         j = find_token(document.body, "\\lang polutonikogreek", j)
2828         if j == -1:
2829             return
2830         document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2831         j = j + 1
2832
2833
2834 ##
2835 # Conversion hub
2836 #
2837
2838 supported_versions = ["1.6.0","1.6"]
2839 convert = [[277, [fix_wrong_tables]],
2840            [278, [close_begin_deeper]],
2841            [279, [long_charstyle_names]],
2842            [280, [axe_show_label]],
2843            [281, []],
2844            [282, []],
2845            [283, [convert_flex]],
2846            [284, []],
2847            [285, []],
2848            [286, []],
2849            [287, [convert_wrapfig_options]],
2850            [288, [convert_inset_command]],
2851            [289, [convert_latexcommand_index]],
2852            [290, []],
2853            [291, []],
2854            [292, [convert_japanese_cjk]],
2855            [293, []],
2856            [294, [convert_pdf_options]],
2857            [295, [convert_htmlurl, convert_url]],
2858            [296, [convert_include]],
2859            [297, [convert_usorbian]],
2860            [298, []],
2861            [299, []],
2862            [300, []],
2863            [301, []],
2864            [302, []],
2865            [303, [convert_serbocroatian]],
2866            [304, [convert_framed_notes]],
2867            [305, []],
2868            [306, []],
2869            [307, []],
2870            [308, []],
2871            [309, []],
2872            [310, []],
2873            [311, [convert_ams_classes]],
2874            [312, []],
2875            [313, [convert_module_names]],
2876            [314, []],
2877            [315, []],
2878            [316, [convert_subfig]],
2879            [317, []],
2880            [318, []],
2881            [319, [convert_spaceinset, convert_hfill]],
2882            [320, []],
2883            [321, [convert_tablines]],
2884            [322, [convert_plain_layout]],
2885            [323, [convert_pagebreaks]],
2886            [324, [convert_linebreaks]],
2887            [325, [convert_japanese_plain]],
2888            [326, []],
2889            [327, []],
2890            [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
2891            [329, []],
2892            [330, []],
2893            [331, [convert_ltcaption]],
2894            [332, []],
2895            [333, [update_apa_styles]],
2896            [334, [convert_paper_sizes]],
2897            [335, [convert_InsetSpace]],
2898            [336, []],
2899            [337, [convert_display_enum]],
2900            [338, []],
2901           ]
2902
2903 revert =  [[337, [revert_polytonicgreek]],
2904            [336, [revert_display_enum]],
2905            [335, [remove_fontsCJK]],
2906            [334, [revert_InsetSpace]],
2907            [333, [revert_paper_sizes]],
2908            [332, []],
2909            [331, [revert_graphics_group]],
2910            [330, [revert_ltcaption]],
2911            [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
2912            [328, [revert_master]],
2913            [327, []],
2914            [326, [revert_mexican]],
2915            [325, [revert_pdfpages]],
2916            [324, []],
2917            [323, [revert_linebreaks]],
2918            [322, [revert_pagebreaks]],
2919            [321, [revert_local_layout, revert_plain_layout]],
2920            [320, [revert_tablines]],
2921            [319, [revert_protected_hfill]],
2922            [318, [revert_spaceinset, revert_hfills, revert_hspace]],
2923            [317, [remove_extra_embedded_files]],
2924            [316, [revert_wrapplacement]],
2925            [315, [revert_subfig]],
2926            [314, [revert_colsep, revert_plainlayout]],
2927            [313, []],
2928            [312, [revert_module_names]],
2929            [311, [revert_rotfloat, revert_widesideways]],
2930            [310, [revert_external_embedding]],
2931            [309, [revert_btprintall]],
2932            [308, [revert_nocite]],
2933            [307, [revert_serbianlatin]],
2934            [306, [revert_slash, revert_nobreakdash]],
2935            [305, [revert_interlingua]],
2936            [304, [revert_bahasam]],
2937            [303, [revert_framed_notes]],
2938            [302, []],
2939            [301, [revert_latin, revert_samin]],
2940            [300, [revert_linebreak]],
2941            [299, [revert_pagebreak]],
2942            [298, [revert_hyperlinktype]],
2943            [297, [revert_macro_optional_params]],
2944            [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
2945            [295, [revert_include]],
2946            [294, [revert_href, revert_url]],
2947            [293, [revert_pdf_options_2]],
2948            [292, [revert_inset_info]],
2949            [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
2950            [290, [revert_vietnamese]],
2951            [289, [revert_wraptable]],
2952            [288, [revert_latexcommand_index]],
2953            [287, [revert_inset_command]],
2954            [286, [revert_wrapfig_options]],
2955            [285, [revert_pdf_options]],
2956            [284, [remove_inzip_options]],
2957            [283, []],
2958            [282, [revert_flex]],
2959            [281, []],
2960            [280, [revert_begin_modules]],
2961            [279, [revert_show_label]],
2962            [278, [revert_long_charstyle_names]],
2963            [277, []],
2964            [276, []]
2965           ]
2966
2967
2968 if __name__ == "__main__":
2969     pass