]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_1_6.py
Fileformat change.
[lyx.git] / lib / lyx2lyx / lyx_1_6.py
1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2008 The LyX Team <lyx-devel@lists.lyx.org>
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 """ Convert files to the file format generated by lyx 1.6"""
20
21 import re
22 import unicodedata
23 import sys, os
24
25 from parser_tools import find_token, find_end_of, find_tokens, get_value
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 def wrap_into_ert(string, src, dst):
35     " Wrap a something into an ERT"
36     return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
37       + dst + '\n\\end_layout\n\\end_inset\n')
38
39 def add_to_preamble(document, text):
40     """ Add text to the preamble if it is not already there.
41     Only the first line is checked!"""
42
43     if find_token(document.preamble, text[0], 0) != -1:
44         return
45
46     document.preamble.extend(text)
47
48 ####################################################################
49
50 def get_option(document, m, option, default):
51     l = document.body[m].find(option)
52     val = default
53     if l != -1:
54         val = document.body[m][l:].split('"')[1]
55     return val
56
57 def remove_option(document, m, option):
58     l = document.body[m].find(option)
59     if l != -1:
60         val = document.body[m][l:].split('"')[1]
61         document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
62     return l
63
64 def set_option(document, m, option, value):
65     l = document.body[m].find(option)
66     if l != -1:
67         oldval = document.body[m][l:].split('"')[1]
68         l = l + len(option + '="')
69         document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
70     else:
71         document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
72     return l
73
74 def convert_tablines(document):
75     i = 0
76     while True:
77         i = find_token(document.body, "\\begin_inset Tabular", i)
78         if i == -1:
79             # LyX 1.3 inserted an extra space between \begin_inset
80             # and Tabular so let us try if this is the case and fix it.
81             i = find_token(document.body, "\\begin_inset  Tabular", i)
82             if i == -1:
83                 return
84             else:
85                 document.body[i] = "\\begin_inset Tabular"
86         j = find_end_of_inset(document.body, i + 1)
87         if j == -1:
88             document.warning("Malformed LyX document: Could not find end of tabular.")
89             continue
90
91         m = i + 1
92         nrows = int(document.body[i+1].split('"')[3])
93         ncols = int(document.body[i+1].split('"')[5])
94
95         col_info = []
96         for k in range(ncols):
97             m = find_token(document.body, "<column", m)
98             left = get_option(document, m, 'leftline', 'false')
99             right = get_option(document, m, 'rightline', 'false')
100             col_info.append([left, right])
101             remove_option(document, m, 'leftline')
102             remove_option(document, m, 'rightline')
103             m = m + 1
104
105         row_info = []
106         for k in range(nrows):
107             m = find_token(document.body, "<row", m)
108             top = get_option(document, m, 'topline', 'false')
109             bottom = get_option(document, m, 'bottomline', 'false')
110             row_info.append([top, bottom])
111             remove_option(document, m, 'topline')
112             remove_option(document, m, 'bottomline')
113             m = m + 1
114
115         m = i + 1
116         mc_info = []
117         for k in range(nrows*ncols):
118             m = find_token(document.body, "<cell", m)
119             mc_info.append(get_option(document, m, 'multicolumn', '0'))
120             m = m + 1
121         m = i + 1
122         for l in range(nrows):
123             for k in range(ncols):
124                 m = find_token(document.body, '<cell', m)
125                 if mc_info[l*ncols + k] == '0':
126                     r = set_option(document, m, 'topline', row_info[l][0])
127                     r = set_option(document, m, 'bottomline', row_info[l][1])
128                     r = set_option(document, m, 'leftline', col_info[k][0])
129                     r = set_option(document, m, 'rightline', col_info[k][1])
130                 elif mc_info[l*ncols + k] == '1':
131                     s = k + 1
132                     while s < ncols and mc_info[l*ncols + s] == '2':
133                         s = s + 1
134                     if s < ncols and mc_info[l*ncols + s] != '1':
135                         r = set_option(document, m, 'rightline', col_info[k][1])
136                     if k > 0 and mc_info[l*ncols + k - 1] == '0':
137                         r = set_option(document, m, 'leftline', col_info[k][0])
138                 m = m + 1
139         i = j + 1
140
141
142 def revert_tablines(document):
143     i = 0
144     while True:
145         i = find_token(document.body, "\\begin_inset Tabular", i)
146         if i == -1:
147             return
148         j = find_end_of_inset(document.body, i + 1)
149         if j == -1:
150             document.warning("Malformed LyX document: Could not find end of tabular.")
151             continue
152
153         m = i + 1
154         nrows = int(document.body[i+1].split('"')[3])
155         ncols = int(document.body[i+1].split('"')[5])
156
157         lines = []
158         for k in range(nrows*ncols):
159             m = find_token(document.body, "<cell", m)
160             top = get_option(document, m, 'topline', 'false')
161             bottom = get_option(document, m, 'bottomline', 'false')
162             left = get_option(document, m, 'leftline', 'false')
163             right = get_option(document, m, 'rightline', 'false')
164             lines.append([top, bottom, left, right])
165             m = m + 1
166
167         m = i + 1
168         col_info = []
169         for k in range(ncols):
170             m = find_token(document.body, "<column", m)
171             left = 'true'
172             for l in range(nrows):
173                 left = lines[k*ncols + k][2]
174                 if left == 'false':
175                     break
176             set_option(document, m, 'leftline', left)
177             right = 'true'
178             for l in range(nrows):
179                 right = lines[k*ncols + k][3]
180                 if right == 'false':
181                     break
182             set_option(document, m, 'rightline', right)
183             m = m + 1
184
185         row_info = []
186         for k in range(nrows):
187             m = find_token(document.body, "<row", m)
188             top = 'true'
189             for l in range(ncols):
190                 top = lines[k*ncols + l][0]
191                 if top == 'false':
192                     break
193             set_option(document, m, 'topline', top)
194             bottom = 'true'
195             for l in range(ncols):
196                 bottom = lines[k*ncols + l][1]
197                 if bottom == 'false':
198                     break
199             set_option(document, m, 'bottomline', bottom)
200             m = m + 1
201
202         i = j + 1
203
204
205 def fix_wrong_tables(document):
206     i = 0
207     while True:
208         i = find_token(document.body, "\\begin_inset Tabular", i)
209         if i == -1:
210             return
211         j = find_end_of_inset(document.body, i + 1)
212         if j == -1:
213             document.warning("Malformed LyX document: Could not find end of tabular.")
214             continue
215
216         m = i + 1
217         nrows = int(document.body[i+1].split('"')[3])
218         ncols = int(document.body[i+1].split('"')[5])
219
220         for l in range(nrows):
221             prev_multicolumn = 0
222             for k in range(ncols):
223                 m = find_token(document.body, '<cell', m)
224
225                 if document.body[m].find('multicolumn') != -1:
226                     multicol_cont = int(document.body[m].split('"')[1])
227
228                     if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
229                         document.body[m] = document.body[m][:5] + document.body[m][21:]
230                         prev_multicolumn = 0
231                     else:
232                         prev_multicolumn = multicol_cont
233                 else:
234                     prev_multicolumn = 0
235
236         i = j + 1
237
238
239 def close_begin_deeper(document):
240     i = 0
241     depth = 0
242     while True:
243         i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
244
245         if i == -1:
246             break
247
248         if document.body[i][:13] == "\\begin_deeper":
249             depth += 1
250         else:
251             depth -= 1
252
253         i += 1
254
255     document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
256
257
258 def long_charstyle_names(document):
259     i = 0
260     while True:
261         i = find_token(document.body, "\\begin_inset CharStyle", i)
262         if i == -1:
263             return
264         document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
265         i += 1
266
267 def revert_long_charstyle_names(document):
268     i = 0
269     while True:
270         i = find_token(document.body, "\\begin_inset CharStyle", i)
271         if i == -1:
272             return
273         document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle")
274         i += 1
275
276
277 def axe_show_label(document):
278     i = 0
279     while True:
280         i = find_token(document.body, "\\begin_inset CharStyle", i)
281         if i == -1:
282             return
283         if document.body[i + 1].find("show_label") != -1:
284             if document.body[i + 1].find("true") != -1:
285                 document.body[i + 1] = "status open"
286                 del document.body[ i + 2]
287             else:
288                 if document.body[i + 1].find("false") != -1:
289                     document.body[i + 1] = "status collapsed"
290                     del document.body[ i + 2]
291                 else:
292                     document.warning("Malformed LyX document: show_label neither false nor true.")
293         else:
294             document.warning("Malformed LyX document: show_label missing in CharStyle.")
295
296         i += 1
297
298
299 def revert_show_label(document):
300     i = 0
301     while True:
302         i = find_token(document.body, "\\begin_inset CharStyle", i)
303         if i == -1:
304             return
305         if document.body[i + 1].find("status open") != -1:
306             document.body.insert(i + 1, "show_label true")
307         else:
308             if document.body[i + 1].find("status collapsed") != -1:
309                 document.body.insert(i + 1, "show_label false")
310             else:
311                 document.warning("Malformed LyX document: no legal status line in CharStyle.")
312         i += 1
313
314 def revert_begin_modules(document):
315     i = 0
316     while True:
317         i = find_token(document.header, "\\begin_modules", i)
318         if i == -1:
319             return
320         j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
321         if j == -1:
322             # this should not happen
323             break
324         document.header[i : j + 1] = []
325
326 def convert_flex(document):
327     "Convert CharStyle to Flex"
328     i = 0
329     while True:
330         i = find_token(document.body, "\\begin_inset CharStyle", i)
331         if i == -1:
332             return
333         document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
334
335 def revert_flex(document):
336     "Convert Flex to CharStyle"
337     i = 0
338     while True:
339         i = find_token(document.body, "\\begin_inset Flex", i)
340         if i == -1:
341             return
342         document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
343
344
345 #  Discard PDF options for hyperref
346 def revert_pdf_options(document):
347         "Revert PDF options for hyperref."
348         i = 0
349         i = find_token(document.header, "\\use_hyperref", i)
350         if i != -1:
351             del document.header[i]
352         i = find_token(document.header, "\\pdf_store_options", i)
353         if i != -1:
354             del document.header[i]
355         i = find_token(document.header, "\\pdf_title", 0)
356         if i != -1:
357             del document.header[i]
358         i = find_token(document.header, "\\pdf_author", 0)
359         if i != -1:
360             del document.header[i]
361         i = find_token(document.header, "\\pdf_subject", 0)
362         if i != -1:
363             del document.header[i]
364         i = find_token(document.header, "\\pdf_keywords", 0)
365         if i != -1:
366             del document.header[i]
367         i = find_token(document.header, "\\pdf_bookmarks", 0)
368         if i != -1:
369             del document.header[i]
370         i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
371         if i != -1:
372             del document.header[i]
373         i = find_token(document.header, "\\pdf_bookmarksopen", i)
374         if i != -1:
375             del document.header[i]
376         i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
377         if i != -1:
378             del document.header[i]
379         i = find_token(document.header, "\\pdf_breaklinks", i)
380         if i != -1:
381             del document.header[i]
382         i = find_token(document.header, "\\pdf_pdfborder", i)
383         if i != -1:
384             del document.header[i]
385         i = find_token(document.header, "\\pdf_colorlinks", i)
386         if i != -1:
387             del document.header[i]
388         i = find_token(document.header, "\\pdf_backref", i)
389         if i != -1:
390             del document.header[i]
391         i = find_token(document.header, "\\pdf_pagebackref", i)
392         if i != -1:
393             del document.header[i]
394         i = find_token(document.header, "\\pdf_pagemode", 0)
395         if i != -1:
396             del document.header[i]
397         i = find_token(document.header, "\\pdf_quoted_options", 0)
398         if i != -1:
399             del document.header[i]
400
401
402 def remove_inzip_options(document):
403     "Remove inzipName and embed options from the Graphics inset"
404     i = 0
405     while 1:
406         i = find_token(document.body, "\\begin_inset Graphics", i)
407         if i == -1:
408             return
409         j = find_end_of_inset(document.body, i + 1)
410         if j == -1:
411             # should not happen
412             document.warning("Malformed LyX document: Could not find end of graphics inset.")
413         # If there's a inzip param, just remove that
414         k = find_token(document.body, "\tinzipName", i + 1, j)
415         if k != -1:
416             del document.body[k]
417             # embed option must follow the inzipName option
418             del document.body[k+1]
419         i = i + 1
420
421
422 def convert_inset_command(document):
423     """
424         Convert:
425             \begin_inset LatexCommand cmd
426         to
427             \begin_inset CommandInset InsetType
428             LatexCommand cmd
429     """
430     i = 0
431     while 1:
432         i = find_token(document.body, "\\begin_inset LatexCommand", i)
433         if i == -1:
434             return
435         line = document.body[i]
436         r = re.compile(r'\\begin_inset LatexCommand (.*)$')
437         m = r.match(line)
438         cmdName = m.group(1)
439         insetName = ""
440         #this is adapted from factory.cpp
441         if cmdName[0:4].lower() == "cite":
442             insetName = "citation"
443         elif cmdName == "url" or cmdName == "htmlurl":
444             insetName = "url"
445         elif cmdName[-3:] == "ref":
446             insetName = "ref"
447         elif cmdName == "tableofcontents":
448             insetName = "toc"
449         elif cmdName == "printnomenclature":
450             insetName = "nomencl_print"
451         elif cmdName == "printindex":
452             insetName = "index_print"
453         else:
454             insetName = cmdName
455         insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
456         document.body[i : i+1] = insertion
457
458
459 def revert_inset_command(document):
460     """
461         Convert:
462             \begin_inset CommandInset InsetType
463             LatexCommand cmd
464         to
465             \begin_inset LatexCommand cmd
466         Some insets may end up being converted to insets earlier versions of LyX
467         will not be able to recognize. Not sure what to do about that.
468     """
469     i = 0
470     while 1:
471         i = find_token(document.body, "\\begin_inset CommandInset", i)
472         if i == -1:
473             return
474         nextline = document.body[i+1]
475         r = re.compile(r'LatexCommand\s+(.*)$')
476         m = r.match(nextline)
477         if not m:
478             document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
479             continue
480         cmdName = m.group(1)
481         insertion = ["\\begin_inset LatexCommand " + cmdName]
482         document.body[i : i+2] = insertion
483
484
485 def convert_wrapfig_options(document):
486     "Convert optional options for wrap floats (wrapfig)."
487     # adds the tokens "lines", "placement", and "overhang"
488     i = 0
489     while True:
490         i = find_token(document.body, "\\begin_inset Wrap figure", i)
491         if i == -1:
492             return
493         document.body.insert(i + 1, "lines 0")
494         j = find_token(document.body, "placement", i)
495         # placement can be already set or not; if not, set it
496         if j == i+2:
497             document.body.insert(i + 3, "overhang 0col%")
498         else:
499            document.body.insert(i + 2, "placement o")
500            document.body.insert(i + 3, "overhang 0col%")
501         i = i + 1
502
503
504 def revert_wrapfig_options(document):
505     "Revert optional options for wrap floats (wrapfig)."
506     i = 0
507     while True:
508         i = find_token(document.body, "lines", i)
509         if i == -1:
510             return
511         j = find_token(document.body, "overhang", i+1)
512         if j != i + 2 and j != -1:
513             document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float.")
514         if j == -1:
515             return
516         del document.body[i]
517         del document.body[j-1]
518         i = i + 1
519
520
521 def convert_latexcommand_index(document):
522     "Convert from LatexCommand form to collapsable form."
523     i = 0
524     while True:
525         i = find_token(document.body, "\\begin_inset CommandInset index", i)
526         if i == -1:
527             return
528         if document.body[i + 1] != "LatexCommand index": # Might also be index_print
529             return
530         fullcontent = document.body[i + 2][6:].strip('"')
531         document.body[i:i + 2] = ["\\begin_inset Index",
532           "status collapsed",
533           "\\begin_layout Standard"]
534         # Put here the conversions needed from LaTeX string to LyXText.
535         # Here we do a minimal conversion to prevent crashes and data loss.
536         # Manual patch-up may be needed.
537         # Umlauted characters (most common ones, can be extended):
538         fullcontent = fullcontent.replace(r'\\\"a', u'ä').replace(r'\\\"o', u'ö').replace(r'\\\"u', u'ü')
539         # Generic, \" -> ":
540         fullcontent = wrap_into_ert(fullcontent, r'\"', '"')
541         #fullcontent = fullcontent.replace(r'\"', '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout standard\n"\n\\end_layout\n\\end_inset\n')
542         # Math:
543         r = re.compile('^(.*?)(\$.*?\$)(.*)')
544         g = fullcontent
545         while r.match(g):
546           m = r.match(g)
547           s = m.group(1)
548           f = m.group(2).replace('\\\\', '\\')
549           g = m.group(3)
550           if s:
551             # this is non-math!
552             s = wrap_into_ert(s, r'\\', '\\backslash')
553             s = wrap_into_ert(s, '{', '{')
554             s = wrap_into_ert(s, '}', '}')
555             document.body.insert(i + 3, s)
556             i += 1
557           document.body.insert(i + 3, "\\begin_inset Formula " + f)
558           document.body.insert(i + 4, "\\end_inset")
559           i += 2
560         # Generic, \\ -> \backslash:
561         g = wrap_into_ert(g, r'\\', '\\backslash{}')
562         g = wrap_into_ert(g, '{', '{')
563         g = wrap_into_ert(g, '}', '}')
564         document.body.insert(i + 3, g)
565         document.body[i + 4] = "\\end_layout"
566         i = i + 5
567
568
569 def revert_latexcommand_index(document):
570     "Revert from collapsable form to LatexCommand form."
571     i = 0
572     while True:
573         i = find_token(document.body, "\\begin_inset Index", i)
574         if i == -1:
575           return
576         j = find_end_of_inset(document.body, i + 1)
577         if j == -1:
578           return
579         del document.body[j - 1]
580         del document.body[j - 2] # \end_layout
581         document.body[i] =  "\\begin_inset CommandInset index"
582         document.body[i + 1] =  "LatexCommand index"
583         # clean up multiline stuff
584         content = ""
585         for k in range(i + 3, j - 2):
586           line = document.body[k]
587           if line.startswith("\\begin_inset ERT"):
588             line = line[16:]
589           if line.startswith("\\begin_inset Formula"):
590             line = line[20:]
591           if line.startswith("\\begin_layout Standard"):
592             line = line[22:]
593           if line.startswith("\\end_layout"):
594             line = line[11:]
595           if line.startswith("\\end_inset"):
596             line = line[10:]
597           if line.startswith("status collapsed"):
598             line = line[16:]
599           line = line.replace(u'ä', r'\\\"a').replace(u'ö', r'\\\"o').replace(u'ü', r'\\\"u')
600           content = content + line;
601         document.body[i + 3] = "name " + '"' + content + '"'
602         for k in range(i + 4, j - 2):
603           del document.body[i + 4]
604         document.body.insert(i + 4, "")
605         del document.body[i + 2] # \begin_layout standard
606         i = i + 5
607
608
609 def revert_wraptable(document):
610     "Revert wrap table to wrap figure."
611     i = 0
612     while True:
613         i = find_token(document.body, "\\begin_inset Wrap table", i)
614         if i == -1:
615             return
616         document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
617         i = i + 1
618
619
620 def revert_vietnamese(document):
621     "Set language Vietnamese to English"
622     # Set document language from Vietnamese to English
623     i = 0
624     if document.language == "vietnamese":
625         document.language = "english"
626         i = find_token(document.header, "\\language", 0)
627         if i != -1:
628             document.header[i] = "\\language english"
629     j = 0
630     while True:
631         j = find_token(document.body, "\\lang vietnamese", j)
632         if j == -1:
633             return
634         document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
635         j = j + 1
636
637
638 def revert_japanese(document):
639     "Set language japanese-plain to japanese"
640     # Set document language from japanese-plain to japanese
641     i = 0
642     if document.language == "japanese-plain":
643         document.language = "japanese"
644         i = find_token(document.header, "\\language", 0)
645         if i != -1:
646             document.header[i] = "\\language japanese"
647     j = 0
648     while True:
649         j = find_token(document.body, "\\lang japanese-plain", j)
650         if j == -1:
651             return
652         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
653         j = j + 1
654
655
656 def revert_japanese_encoding(document):
657     "Set input encoding form EUC-JP-plain to EUC-JP etc."
658     # Set input encoding form EUC-JP-plain to EUC-JP etc.
659     i = 0
660     i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
661     if i != -1:
662         document.header[i] = "\\inputencoding EUC-JP"
663     j = 0
664     j = find_token(document.header, "\\inputencoding JIS-plain", 0)
665     if j != -1:
666         document.header[j] = "\\inputencoding JIS"
667     k = 0
668     k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
669     if k != -1: # convert to UTF8 since there is currently no SJIS encoding
670         document.header[k] = "\\inputencoding UTF8"
671
672
673 def revert_inset_info(document):
674     'Replace info inset with its content'
675     i = 0
676     while 1:
677         i = find_token(document.body, '\\begin_inset Info', i)
678         if i == -1:
679             return
680         j = find_end_of_inset(document.body, i + 1)
681         if j == -1:
682             # should not happen
683             document.warning("Malformed LyX document: Could not find end of Info inset.")
684         type = 'unknown'
685         arg = ''
686         for k in range(i, j+1):
687             if document.body[k].startswith("arg"):
688                 arg = document.body[k][3:].strip().strip('"')
689             if document.body[k].startswith("type"):
690                 type = document.body[k][4:].strip().strip('"')
691         # I think there is a newline after \\end_inset, which should be removed.
692         if document.body[j + 1].strip() == "":
693             document.body[i : (j + 2)] = [type + ':' + arg]
694         else:
695             document.body[i : (j + 1)] = [type + ':' + arg]
696
697
698 def convert_pdf_options(document):
699     # Set the pdfusetitle tag, delete the pdf_store_options,
700     # set quotes for bookmarksopenlevel"
701     has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
702     if has_hr == "1":
703         k = find_token(document.header, "\\use_hyperref", 0)
704         document.header.insert(k + 1, "\\pdf_pdfusetitle true")
705     k = find_token(document.header, "\\pdf_store_options", 0)
706     if k != -1:
707         del document.header[k]
708     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
709     if i == -1: return
710     document.header[i] = document.header[i].replace('"', '')
711
712
713 def revert_pdf_options_2(document):
714     # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
715     k = find_token(document.header, "\\use_hyperref", 0)
716     i = find_token(document.header, "\\pdf_pdfusetitle", k)
717     if i != -1:
718         del document.header[i]
719     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
720     if i == -1: return
721     values = document.header[i].split()
722     values[1] = ' "' + values[1] + '"'
723     document.header[i] = ''.join(values)
724
725
726 def convert_htmlurl(document):
727     'Convert "htmlurl" to "href" insets for docbook'
728     if document.backend != "docbook":
729       return
730     i = 0
731     while True:
732       i = find_token(document.body, "\\begin_inset CommandInset url", i)
733       if i == -1:
734         return
735       document.body[i] = "\\begin_inset CommandInset href"
736       document.body[i + 1] = "LatexCommand href"
737       i = i + 1
738
739
740 def convert_url(document):
741     'Convert url insets to url charstyles'
742     if document.backend == "docbook":
743       return
744     i = 0
745     while True:
746       i = find_token(document.body, "\\begin_inset CommandInset url", i)
747       if i == -1:
748         break
749       n = find_token(document.body, "name", i)
750       if n == i + 2:
751         # place the URL name in typewriter before the new URL insert
752         # grab the name 'bla' from the e.g. the line 'name "bla"',
753         # therefore start with the 6th character
754         name = document.body[n][6:-1]
755         newname = [name + " "]
756         document.body[i:i] = newname
757         i = i + 1
758       j = find_token(document.body, "target", i)
759       if j == -1:
760         document.warning("Malformed LyX document: Can't find target for url inset")
761         i = j
762         continue
763       target = document.body[j][8:-1]
764       k = find_token(document.body, "\\end_inset", j)
765       if k == -1:
766         document.warning("Malformed LyX document: Can't find end of url inset")
767         i = k
768         continue
769       newstuff = ["\\begin_inset Flex URL",
770         "status collapsed", "",
771         "\\begin_layout Standard",
772         "",
773         target,
774         "\\end_layout",
775         ""]
776       document.body[i:k] = newstuff
777       i = k
778
779 def convert_ams_classes(document):
780   tc = document.textclass
781   if (tc != "amsart" and tc != "amsart-plain" and
782       tc != "amsart-seq" and tc != "amsbook"):
783     return
784   if tc == "amsart-plain":
785     document.textclass = "amsart"
786     document.set_textclass()
787     document.add_module("Theorems (Starred)")
788     return
789   if tc == "amsart-seq":
790     document.textclass = "amsart"
791     document.set_textclass()
792   document.add_module("Theorems (AMS)")
793
794   #Now we want to see if any of the environments in the extended theorems
795   #module were used in this document. If so, we'll add that module, too.
796   layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note",  \
797     "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
798     "Assumption"]
799
800   r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
801   i = 0
802   while True:
803     i = find_token(document.body, "\\begin_layout", i)
804     if i == -1:
805       return
806     m = r.match(document.body[i])
807     if m == None:
808       document.warning("Weirdly formed \\begin_layout at line " + i + " of body!")
809       i += 1
810       continue
811     m = m.group(1)
812     if layouts.count(m) != 0:
813       document.add_module("Theorems (AMS-Extended)")
814       return
815     i += 1
816
817 def revert_href(document):
818     'Reverts hyperlink insets (href) to url insets (url)'
819     i = 0
820     while True:
821       i = find_token(document.body, "\\begin_inset CommandInset href", i)
822       if i == -1:
823           return
824       document.body[i : i + 2] = \
825         ["\\begin_inset CommandInset url", "LatexCommand url"]
826       i = i + 2
827
828
829 def convert_include(document):
830   'Converts include insets to new format.'
831   i = 0
832   r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
833   while True:
834     i = find_token(document.body, "\\begin_inset Include", i)
835     if i == -1:
836       return
837     line = document.body[i]
838     previewline = document.body[i + 1]
839     m = r.match(line)
840     if m == None:
841       document.warning("Unable to match line " + str(i) + " of body!")
842       i += 1
843       continue
844     cmd = m.group(1)
845     fn  = m.group(2)
846     opt = m.group(3)
847     insertion = ["\\begin_inset CommandInset include",
848        "LatexCommand " + cmd, previewline,
849        "filename \"" + fn + "\""]
850     newlines = 2
851     if opt:
852       insertion.append("lstparams " + '"' + opt + '"')
853       newlines += 1
854     document.body[i : i + 2] = insertion
855     i += newlines
856
857
858 def revert_include(document):
859   'Reverts include insets to old format.'
860   i = 0
861   r1 = re.compile('LatexCommand (.+)')
862   r2 = re.compile('filename (.+)')
863   r3 = re.compile('options (.*)')
864   while True:
865     i = find_token(document.body, "\\begin_inset CommandInset include", i)
866     if i == -1:
867       return
868     previewline = document.body[i + 1]
869     m = r1.match(document.body[i + 2])
870     if m == None:
871       document.warning("Malformed LyX document: No LatexCommand line for `" +
872         document.body[i] + "' on line " + str(i) + ".")
873       i += 1
874       continue
875     cmd = m.group(1)
876     m = r2.match(document.body[i + 3])
877     if m == None:
878       document.warning("Malformed LyX document: No filename line for `" + \
879         document.body[i] + "' on line " + str(i) + ".")
880       i += 2
881       continue
882     fn = m.group(1)
883     options = ""
884     numlines = 4
885     if (cmd == "lstinputlisting"):
886       m = r3.match(document.body[i + 4])
887       if m != None:
888         options = m.group(1)
889         numlines = 5
890     newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
891     if options:
892       newline += ("[" + options + "]")
893     insertion = [newline, previewline]
894     document.body[i : i + numlines] = insertion
895     i += 2
896
897
898 def revert_albanian(document):
899     "Set language Albanian to English"
900     i = 0
901     if document.language == "albanian":
902         document.language = "english"
903         i = find_token(document.header, "\\language", 0)
904         if i != -1:
905             document.header[i] = "\\language english"
906     j = 0
907     while True:
908         j = find_token(document.body, "\\lang albanian", j)
909         if j == -1:
910             return
911         document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
912         j = j + 1
913
914
915 def revert_lowersorbian(document):
916     "Set language lower Sorbian to English"
917     i = 0
918     if document.language == "lowersorbian":
919         document.language = "english"
920         i = find_token(document.header, "\\language", 0)
921         if i != -1:
922             document.header[i] = "\\language english"
923     j = 0
924     while True:
925         j = find_token(document.body, "\\lang lowersorbian", j)
926         if j == -1:
927             return
928         document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
929         j = j + 1
930
931
932 def revert_uppersorbian(document):
933     "Set language uppersorbian to usorbian as this was used in LyX 1.5"
934     i = 0
935     if document.language == "uppersorbian":
936         document.language = "usorbian"
937         i = find_token(document.header, "\\language", 0)
938         if i != -1:
939             document.header[i] = "\\language usorbian"
940     j = 0
941     while True:
942         j = find_token(document.body, "\\lang uppersorbian", j)
943         if j == -1:
944             return
945         document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
946         j = j + 1
947
948
949 def convert_usorbian(document):
950     "Set language usorbian to uppersorbian"
951     i = 0
952     if document.language == "usorbian":
953         document.language = "uppersorbian"
954         i = find_token(document.header, "\\language", 0)
955         if i != -1:
956             document.header[i] = "\\language uppersorbian"
957     j = 0
958     while True:
959         j = find_token(document.body, "\\lang usorbian", j)
960         if j == -1:
961             return
962         document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
963         j = j + 1
964
965
966 def revert_macro_optional_params(document):
967     "Convert macro definitions with optional parameters into ERTs"
968     # Stub to convert macro definitions with one or more optional parameters
969     # into uninterpreted ERT insets
970
971
972 def revert_hyperlinktype(document):
973     'Reverts hyperlink type'
974     i = 0
975     j = 0
976     while True:
977       i = find_token(document.body, "target", i)
978       if i == -1:
979           return
980       j = find_token(document.body, "type", i)
981       if j == -1:
982           return
983       if j == i + 1:
984           del document.body[j]
985       i = i + 1
986
987
988 def revert_pagebreak(document):
989     'Reverts pagebreak to ERT'
990     i = 0
991     while True:
992       i = find_token(document.body, "\\pagebreak", i)
993       if i == -1:
994           return
995       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
996       '\\begin_layout Standard\n\n\n\\backslash\n' \
997       'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
998       i = i + 1
999
1000
1001 def revert_linebreak(document):
1002     'Reverts linebreak to ERT'
1003     i = 0
1004     while True:
1005       i = find_token(document.body, "\\linebreak", i)
1006       if i == -1:
1007           return
1008       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1009       '\\begin_layout Standard\n\n\n\\backslash\n' \
1010       'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1011       i = i + 1
1012
1013
1014 def revert_latin(document):
1015     "Set language Latin to English"
1016     i = 0
1017     if document.language == "latin":
1018         document.language = "english"
1019         i = find_token(document.header, "\\language", 0)
1020         if i != -1:
1021             document.header[i] = "\\language english"
1022     j = 0
1023     while True:
1024         j = find_token(document.body, "\\lang latin", j)
1025         if j == -1:
1026             return
1027         document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1028         j = j + 1
1029
1030
1031 def revert_samin(document):
1032     "Set language North Sami to English"
1033     i = 0
1034     if document.language == "samin":
1035         document.language = "english"
1036         i = find_token(document.header, "\\language", 0)
1037         if i != -1:
1038             document.header[i] = "\\language english"
1039     j = 0
1040     while True:
1041         j = find_token(document.body, "\\lang samin", j)
1042         if j == -1:
1043             return
1044         document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1045         j = j + 1
1046
1047
1048 def convert_serbocroatian(document):
1049     "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1050     i = 0
1051     if document.language == "serbocroatian":
1052         document.language = "croatian"
1053         i = find_token(document.header, "\\language", 0)
1054         if i != -1:
1055             document.header[i] = "\\language croatian"
1056     j = 0
1057     while True:
1058         j = find_token(document.body, "\\lang serbocroatian", j)
1059         if j == -1:
1060             return
1061         document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1062         j = j + 1
1063
1064
1065 def convert_framed_notes(document):
1066     "Convert framed notes to boxes. "
1067     i = 0
1068     while 1:
1069         i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1070
1071         if i == -1:
1072             return
1073         document.body[i] = document.body[i].replace("\\begin_inset Note", "\\begin_inset Box")
1074         document.body.insert(i + 1, 'position "t"\nhor_pos "c"\nhas_inner_box 0\ninner_pos "t"\n' \
1075         'use_parbox 0\nwidth "100col%"\nspecial "none"\nheight "1in"\n' \
1076         'height_special "totalheight"')
1077         i = i + 1
1078
1079
1080 def convert_module_names(document):
1081   modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1082     'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1083     'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1084     'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1085     'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1086   modlist = document.get_module_list()
1087   if len(modlist) == 0:
1088     return
1089   newmodlist = []
1090   for mod in modlist:
1091     if modulemap.has_key(mod):
1092       newmodlist.append(modulemap[mod])
1093     else:
1094       document.warning("Can't find module %s in the module map!" % mod)
1095       newmodlist.append(mod)
1096   document.set_module_list(newmodlist)
1097
1098
1099 def revert_module_names(document):
1100   modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1101     'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1102     'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1103     'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1104     'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1105   modlist = document.get_module_list()
1106   if len(modlist) == 0:
1107     return
1108   newmodlist = []
1109   for mod in modlist:
1110     if modulemap.has_key(mod):
1111       newmodlist.append(modulemap[mod])
1112     else:
1113       document.warning("Can't find module %s in the module map!" % mod)
1114       newmodlist.append(mod)
1115   document.set_module_list(newmodlist)
1116
1117
1118 def revert_colsep(document):
1119     i = find_token(document.header, "\\columnsep", 0)
1120     if i == -1:
1121         return
1122     colsepline = document.header[i]
1123     r = re.compile(r'\\columnsep (.*)')
1124     m = r.match(colsepline)
1125     if not m:
1126         document.warning("Malformed column separation line!")
1127         return
1128     colsep = m.group(1)
1129     del document.header[i]
1130     #it seems to be safe to add the package even if it is already used
1131     pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1132
1133     add_to_preamble(document, pretext)
1134
1135
1136 def revert_framed_notes(document):
1137     "Revert framed boxes to notes. "
1138     i = 0
1139     while 1:
1140         i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1141
1142         if i == -1:
1143             return
1144         j = find_end_of_inset(document.body, i + 1)
1145         if j == -1:
1146             # should not happen
1147             document.warning("Malformed LyX document: Could not find end of Box inset.")
1148         k = find_token(document.body, "status", i + 1, j)
1149         if k == -1:
1150             document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1151             return
1152         status = document.body[k]
1153         l = find_token(document.body, "\\begin_layout Standard", i + 1, j)
1154         if l == -1:
1155             document.warning("Malformed LyX document: Missing `\\begin_layout Standard' in Box inset.")
1156             return
1157         m = find_token(document.body, "\\end_layout", i + 1, j)
1158         if m == -1:
1159             document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1160             return
1161         ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1162         pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1163         if ibox == -1 and pbox == -1:
1164             document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1165             del document.body[i+1:k]
1166         else:
1167             document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1168             document.body.insert(l + 1, "\\begin_inset Note Shaded\n" + status + "\n\\begin_layout Standard\n")
1169             document.body.insert(m + 1, "\\end_layout\n\\end_inset")
1170         i = i + 1
1171
1172
1173 def revert_slash(document):
1174     'Revert \\SpecialChar \\slash{} to ERT'
1175     for i in range(len(document.body)):
1176         document.body[i] = document.body[i].replace('\\SpecialChar \\slash{}', \
1177         '\\begin_inset ERT\nstatus collapsed\n\n' \
1178         '\\begin_layout Standard\n\n\n\\backslash\n' \
1179         'slash{}\n\\end_layout\n\n\\end_inset\n\n')
1180
1181
1182 def revert_nobreakdash(document):
1183     'Revert \\SpecialChar \\nobreakdash- to ERT'
1184     found = 0
1185     for i in range(len(document.body)):
1186         line = document.body[i]
1187         r = re.compile(r'\\SpecialChar \\nobreakdash-')
1188         m = r.match(line)
1189         if m:
1190             found = 1
1191         document.body[i] = document.body[i].replace('\\SpecialChar \\nobreakdash-', \
1192         '\\begin_inset ERT\nstatus collapsed\n\n' \
1193         '\\begin_layout Standard\n\n\n\\backslash\n' \
1194         'nobreakdash-\n\\end_layout\n\n\\end_inset\n\n')
1195     if not found:
1196         return
1197     j = find_token(document.header, "\\use_amsmath", 0)
1198     if j == -1:
1199         document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1200         return
1201     document.header[j] = "\\use_amsmath 2"
1202
1203
1204 def revert_nocite_key(body, start, end):
1205     'key "..." -> \nocite{...}'
1206     for i in range(start, end):
1207         if (body[i][0:5] == 'key "'):
1208             body[i] = body[i].replace('key "', "\\backslash\nnocite{")
1209             body[i] = body[i].replace('"', "}")
1210         else:
1211             body[i] = ""
1212
1213
1214 def revert_nocite(document):
1215     "Revert LatexCommand nocite to ERT"
1216     i = 0
1217     while 1:
1218         i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1219         if i == -1:
1220             return
1221         i = i + 1
1222         if (document.body[i] == "LatexCommand nocite"):
1223             j = find_end_of_inset(document.body, i + 1)
1224             if j == -1:
1225                 #this should not happen
1226                 document.warning("End of CommandInset citation not found in revert_nocite!")
1227                 revert_nocite_key(document.body, i + 1, len(document.body))
1228                 return
1229             revert_nocite_key(document.body, i + 1, j)
1230             document.body[i-1] = "\\begin_inset ERT"
1231             document.body[i] = "status collapsed\n\n" \
1232             "\\begin_layout Standard"
1233             document.body.insert(j, "\\end_layout\n");
1234             i = j
1235
1236
1237 def revert_btprintall(document):
1238     "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1239     i = find_token(document.header, '\\use_bibtopic', 0)
1240     if i == -1:
1241         document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1242         return
1243     if get_value(document.header, '\\use_bibtopic', 0) == "false":
1244         i = 0
1245         while i < len(document.body):
1246             i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1247             if i == -1:
1248                 return
1249             j = find_end_of_inset(document.body, i + 1)
1250             if j == -1:
1251                 #this should not happen
1252                 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1253                 j = len(document.body)
1254             for k in range(i, j):
1255                 if (document.body[k] == 'btprint "btPrintAll"'):
1256                     del document.body[k]
1257                     document.body.insert(i, "\\begin_inset ERT\n" \
1258                     "status collapsed\n\n\\begin_layout Standard\n\n" \
1259                     "\\backslash\nnocite{*}\n" \
1260                     "\\end_layout\n\\end_inset\n")
1261             i = j
1262
1263
1264 def revert_bahasam(document):
1265     "Set language Bahasa Malaysia to Bahasa Indonesia"
1266     i = 0
1267     if document.language == "bahasam":
1268         document.language = "bahasa"
1269         i = find_token(document.header, "\\language", 0)
1270         if i != -1:
1271             document.header[i] = "\\language bahasa"
1272     j = 0
1273     while True:
1274         j = find_token(document.body, "\\lang bahasam", j)
1275         if j == -1:
1276             return
1277         document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1278         j = j + 1
1279
1280
1281 def revert_interlingua(document):
1282     "Set language Interlingua to English"
1283     i = 0
1284     if document.language == "interlingua":
1285         document.language = "english"
1286         i = find_token(document.header, "\\language", 0)
1287         if i != -1:
1288             document.header[i] = "\\language english"
1289     j = 0
1290     while True:
1291         j = find_token(document.body, "\\lang interlingua", j)
1292         if j == -1:
1293             return
1294         document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1295         j = j + 1
1296
1297
1298 def revert_serbianlatin(document):
1299     "Set language Serbian-Latin to Croatian"
1300     i = 0
1301     if document.language == "serbian-latin":
1302         document.language = "croatian"
1303         i = find_token(document.header, "\\language", 0)
1304         if i != -1:
1305             document.header[i] = "\\language croatian"
1306     j = 0
1307     while True:
1308         j = find_token(document.body, "\\lang serbian-latin", j)
1309         if j == -1:
1310             return
1311         document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
1312         j = j + 1
1313
1314
1315 def revert_rotfloat(document):
1316     " Revert sideways custom floats. "
1317     i = 0
1318     while 1:
1319         i = find_token(document.body, "\\begin_inset Float", i)
1320         if i == -1:
1321             return
1322         line = document.body[i]
1323         r = re.compile(r'\\begin_inset Float (.*)$')
1324         m = r.match(line)
1325         floattype = m.group(1)
1326         if floattype == "figure" or floattype == "table":
1327             i = i + 1
1328             continue
1329         j = find_end_of_inset(document.body, i)
1330         if j == -1:
1331             document.warning("Malformed lyx document: Missing '\\end_inset'.")
1332             i = i + 1
1333             continue
1334         if get_value(document.body, 'sideways', i, j) != "false":
1335             l = find_token(document.body, "\\begin_layout Standard", i + 1, j)
1336             if l == -1:
1337                 document.warning("Malformed LyX document: Missing `\\begin_layout Standard' in Float inset.")
1338                 return
1339             document.body[j] = '\\begin_layout Standard\n\\begin_inset ERT\nstatus collapsed\n\n' \
1340             '\\begin_layout Standard\n\n\n\\backslash\n' \
1341             'end{sideways' + floattype + '}\n\\end_layout\n\n\\end_inset\n'
1342             del document.body[i+1:l-1]
1343             document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1344             '\\begin_layout Standard\n\n\n\\backslash\n' \
1345             'begin{sideways' + floattype + '}\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n\n'
1346             if floattype == "algorithm":
1347                 add_to_preamble(document,
1348                                 ['% Commands inserted by lyx2lyx for sideways algorithm float',
1349                                  '\\usepackage{rotfloat}\n'
1350                                  '\\floatstyle{ruled}\n'
1351                                  '\\newfloat{algorithm}{tbp}{loa}\n'
1352                                  '\\floatname{algorithm}{Algorithm}\n'])
1353             else:
1354                 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
1355             i = i + 1
1356             continue
1357         i = i + 1
1358
1359
1360 def revert_widesideways(document):
1361     " Revert wide sideways floats. "
1362     i = 0
1363     while 1:
1364         i = find_token(document.body, '\\begin_inset Float', i)
1365         if i == -1:
1366             return
1367         line = document.body[i]
1368         r = re.compile(r'\\begin_inset Float (.*)$')
1369         m = r.match(line)
1370         floattype = m.group(1)
1371         if floattype != "figure" and floattype != "table":
1372             i = i + 1
1373             continue
1374         j = find_end_of_inset(document.body, i)
1375         if j == -1:
1376             document.warning("Malformed lyx document: Missing '\\end_inset'.")
1377             i = i + 1
1378             continue
1379         if get_value(document.body, 'sideways', i, j) != "false":
1380             if get_value(document.body, 'wide', i, j) != "false":
1381                 l = find_token(document.body, "\\begin_layout Standard", i + 1, j)
1382                 if l == -1:
1383                     document.warning("Malformed LyX document: Missing `\\begin_layout Standard' in Float inset.")
1384                     return
1385                 document.body[j] = '\\begin_layout Standard\n\\begin_inset ERT\nstatus collapsed\n\n' \
1386                 '\\begin_layout Standard\n\n\n\\backslash\n' \
1387                 'end{sideways' + floattype + '*}\n\\end_layout\n\n\\end_inset\n'
1388                 del document.body[i+1:l-1]
1389                 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1390                 '\\begin_layout Standard\n\n\n\\backslash\n' \
1391                 'begin{sideways' + floattype + '*}\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n\n'
1392                 add_to_preamble(document,
1393                                 ['\\usepackage{rotfloat}\n'])
1394                 i = i + 1
1395                 continue
1396         i = i + 1
1397
1398
1399 def convert_subfig(document):
1400     " Convert subfigures to subfloats. "
1401     i = 0
1402     while 1:
1403         i = find_token(document.body, '\\begin_inset Graphics', i)
1404         if i == -1:
1405             return
1406         j = find_end_of_inset(document.body, i)
1407         if j == -1:
1408             document.warning("Malformed lyx document: Missing '\\end_inset'.")
1409             i = i + 1
1410             continue
1411         k = find_token(document.body, '\tsubcaption', i, j)
1412         if k == -1:
1413             i = i + 1
1414             continue
1415         l = find_token(document.body, '\tsubcaptionText', i, j)
1416         caption = document.body[l][16:].strip('"')
1417         savestr = document.body[i]
1418         del document.body[l]
1419         del document.body[k]
1420         document.body[i] = '\\begin_inset Float figure\nwide false\nsideways false\n' \
1421         'status open\n\n\\begin_layout PlainLayout\n\\begin_inset Caption\n\n\\begin_layout PlainLayout\n' \
1422         + caption + '\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n\n\\begin_layout PlainLayout\n' + savestr
1423         savestr = document.body[j]
1424         document.body[j] = '\n\\end_layout\n\n\\end_inset\n' + savestr
1425
1426
1427 def revert_subfig(document):
1428     " Revert subfloats. "
1429     i = 0
1430     while 1:
1431         i = find_token(document.body, '\\begin_inset Float', i)
1432         if i == -1:
1433             return
1434         while 1:
1435             j = find_end_of_inset(document.body, i)
1436             if j == -1:
1437                 document.warning("Malformed lyx document: Missing '\\end_inset' (float).")
1438                 i = i + 1
1439                 continue
1440             # look for embedded float (= subfloat)
1441             k = find_token(document.body, '\\begin_inset Float', i + 1, j)
1442             if k == -1:
1443                 break
1444             l = find_end_of_inset(document.body, k)
1445             if l == -1:
1446                 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
1447                 i = i + 1
1448                 continue
1449             m = find_token(document.body, "\\begin_layout PlainLayout", k + 1, l)
1450             # caption?
1451             cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
1452             caption = ''
1453             shortcap = ''
1454             if cap != -1:
1455                 capend = find_end_of_inset(document.body, cap)
1456                 if capend == -1:
1457                     document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
1458                     return
1459                 # label?
1460                 label = ''
1461                 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
1462                 if lbl != -1:
1463                     lblend = find_end_of_inset(document.body, lbl + 1)
1464                     if lblend == -1:
1465                         document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
1466                         return
1467                     for line in document.body[lbl:lblend + 1]:
1468                         if line.startswith('name '):
1469                             label = line.split()[1].strip('"')
1470                             break
1471                 else:
1472                     lbl = capend
1473                     lblend = capend
1474                     label = ''
1475                 # opt arg?
1476                 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
1477                 if opt != -1:
1478                     optend = find_end_of_inset(document.body, opt)
1479                     if optend == -1:
1480                         document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
1481                         return
1482                     optc = find_token(document.body, "\\begin_layout PlainLayout", opt, optend)
1483                     if optc == -1:
1484                         document.warning("Malformed LyX document: Missing `\\begin_layout PlainLayout' in Float inset.")
1485                         return
1486                     optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
1487                     for line in document.body[optc:optcend]:
1488                         if not line.startswith('\\'):
1489                             shortcap += line.strip()
1490                 else:
1491                     opt = capend
1492                     optend = capend
1493                 for line in document.body[cap:capend]:
1494                     if line in document.body[lbl:lblend]:
1495                         continue
1496                     elif line in document.body[opt:optend]:
1497                         continue
1498                     elif not line.startswith('\\'):
1499                         caption += line.strip()
1500                 if len(label) > 0:
1501                     caption += "\\backslash\nlabel{" + label + "}"
1502             document.body[l] = '\\begin_layout PlainLayout\n\\begin_inset ERT\nstatus collapsed\n\n' \
1503             '\\begin_layout PlainLayout\n\n}\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n\n\\begin_layout PlainLayout\n'
1504             del document.body[cap:capend+1]
1505             del document.body[k+1:m-1]
1506             insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
1507             '\\begin_layout PlainLayout\n\n\\backslash\n' \
1508             'subfloat'
1509             if len(shortcap) > 0:
1510                 insertion = insertion + "[" + shortcap + "]"
1511             if len(caption) > 0:
1512                 insertion = insertion + "[" + caption + "]"
1513             insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
1514             document.body[k] = insertion
1515             add_to_preamble(document,
1516                             ['\\usepackage{subfig}\n'])
1517         i = i + 1
1518
1519
1520 def revert_wrapplacement(document):
1521     " Revert placement options wrap floats (wrapfig). "
1522     i = 0
1523     while True:
1524         i = find_token(document.body, "lines", i)
1525         if i == -1:
1526             return
1527         j = find_token(document.body, "placement", i+1)
1528         if j != i + 1:
1529             document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
1530             return
1531         document.body[j] = document.body[j].replace("placement O", "placement o")
1532         document.body[j] = document.body[j].replace("placement I", "placement i")
1533         document.body[j] = document.body[j].replace("placement L", "placement l")
1534         document.body[j] = document.body[j].replace("placement R", "placement r")
1535         i = i + 1
1536
1537
1538 def remove_extra_embedded_files(document):
1539     " Remove \extra_embedded_files from buffer params "
1540     i = find_token(document.header, '\\extra_embedded_files', 0)
1541     if i == -1:
1542         document.warning("Malformed lyx document: Missing '\\extra_embedded_files'.")
1543         return
1544     document.header.pop(i)
1545
1546
1547 def convert_spaceinset(document):
1548     " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
1549     for i in range(len(document.body)):
1550         if re.search(r'\InsetSpace', document.body[i]):
1551             document.body[i] = document.body[i].replace('\\InsetSpace', '\n\\begin_inset Space')
1552             document.body[i] = document.body[i] + "\n\\end_inset"
1553
1554
1555 def revert_spaceinset(document):
1556     " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
1557     i = 0
1558     while True:
1559         i = find_token(document.body, "\\begin_inset Space", i)
1560         if i == -1:
1561             return
1562         j = find_end_of_inset(document.body, i)
1563         if j == -1:
1564             document.warning("Malformed LyX document: Could not find end of space inset.")
1565             continue
1566         document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
1567         del document.body[j]
1568
1569
1570 def convert_hfill(document):
1571     " Convert hfill to space inset "
1572     i = 0
1573     while True:
1574         i = find_token(document.body, "\\hfill", i)
1575         if i == -1:
1576             return
1577         document.body[i] = document.body[i].replace('\\hfill', '\n\\begin_inset Space \\hfill{}\n\\end_inset')
1578
1579
1580 def revert_hfills(document):
1581     ' Revert \\hfill commands '
1582     for i in range(len(document.body)):
1583         document.body[i] = document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
1584         document.body[i] = document.body[i].replace('\\InsetSpace \\dotfill{}', \
1585         '\\begin_inset ERT\nstatus collapsed\n\n' \
1586         '\\begin_layout Standard\n\n\n\\backslash\n' \
1587         'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
1588         document.body[i] = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
1589         '\\begin_inset ERT\nstatus collapsed\n\n' \
1590         '\\begin_layout Standard\n\n\n\\backslash\n' \
1591         'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
1592
1593
1594 def revert_hspace(document):
1595     ' Revert \\InsetSpace \\hspace{} to ERT '
1596     i = 0
1597     while True:
1598         i = find_token(document.body, "\\InsetSpace \\hspace", i)
1599         if i == -1:
1600             return
1601         length = get_value(document.body, '\\length', i+1)
1602         if length == '':
1603             document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
1604             return
1605         del document.body[i+1]
1606         document.body[i] = document.body[i].replace('\\InsetSpace \\hspace*{}', \
1607         '\\begin_inset ERT\nstatus collapsed\n\n' \
1608         '\\begin_layout Standard\n\n\n\\backslash\n' \
1609         'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
1610         document.body[i] = document.body[i].replace('\\InsetSpace \\hspace{}', \
1611         '\\begin_inset ERT\nstatus collapsed\n\n' \
1612         '\\begin_layout Standard\n\n\n\\backslash\n' \
1613         'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
1614
1615
1616 def revert_protected_hfill(document):
1617     ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
1618     i = 0
1619     while True:
1620         i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
1621         if i == -1:
1622             return
1623         j = find_end_of_inset(document.body, i)
1624         if j == -1:
1625             document.warning("Malformed LyX document: Could not find end of space inset.")
1626             continue
1627         del document.body[j]
1628         document.body[i] = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
1629         '\\begin_inset ERT\nstatus collapsed\n\n' \
1630         '\\begin_layout Standard\n\n\n\\backslash\n' \
1631         'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
1632
1633
1634 def revert_local_layout(document):
1635     ' Revert local layout headers.'
1636     i = 0
1637     while True:
1638         i = find_token(document.header, "\\begin_local_layout", i)
1639         if i == -1:
1640             return
1641         j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
1642         if j == -1:
1643             # this should not happen
1644             break
1645         document.header[i : j + 1] = []
1646
1647
1648 def convert_pagebreaks(document):
1649     ' Convert inline Newpage insets to new format '
1650     i = 0
1651     while True:
1652         i = find_token(document.body, '\\newpage', i)
1653         if i == -1:
1654             break
1655         document.body[i:i+1] = ['\\begin_inset Newpage newpage',
1656                              '\\end_inset']
1657     i = 0
1658     while True:
1659         i = find_token(document.body, '\\pagebreak', i)
1660         if i == -1:
1661             break
1662         document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
1663                              '\\end_inset']
1664     i = 0
1665     while True:
1666         i = find_token(document.body, '\\clearpage', i)
1667         if i == -1:
1668             break
1669         document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
1670                              '\\end_inset']
1671     i = 0
1672     while True:
1673         i = find_token(document.body, '\\cleardoublepage', i)
1674         if i == -1:
1675             break
1676         document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
1677                              '\\end_inset']
1678
1679
1680 def revert_pagebreaks(document):
1681     ' Revert \\begin_inset Newpage to previous inline format '
1682     i = 0
1683     while True:
1684         i = find_token(document.body, '\\begin_inset Newpage', i)
1685         if i == -1:
1686             return
1687         j = find_end_of_inset(document.body, i)
1688         if j == -1:
1689             document.warning("Malformed LyX document: Could not find end of Newpage inset.")
1690             continue
1691         del document.body[j]
1692         document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
1693         document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
1694         document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
1695         document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
1696
1697
1698 def convert_linebreaks(document):
1699     ' Convert inline Newline insets to new format '
1700     i = 0
1701     while True:
1702         i = find_token(document.body, '\\newline', i)
1703         if i == -1:
1704             break
1705         document.body[i:i+1] = ['\\begin_inset Newline newline',
1706                              '\\end_inset']
1707     i = 0
1708     while True:
1709         i = find_token(document.body, '\\linebreak', i)
1710         if i == -1:
1711             break
1712         document.body[i:i+1] = ['\\begin_inset Newline linebreak',
1713                              '\\end_inset']
1714
1715
1716 def revert_linebreaks(document):
1717     ' Revert \\begin_inset Newline to previous inline format '
1718     i = 0
1719     while True:
1720         i = find_token(document.body, '\\begin_inset Newline', i)
1721         if i == -1:
1722             return
1723         j = find_end_of_inset(document.body, i)
1724         if j == -1:
1725             document.warning("Malformed LyX document: Could not find end of Newline inset.")
1726             continue
1727         del document.body[j]
1728         document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
1729         document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
1730
1731
1732 def convert_japanese_plain(document):
1733     "Set language japanese-plain to japanese"
1734     i = 0
1735     if document.language == "japanese-plain":
1736         document.language = "japanese"
1737         i = find_token(document.header, "\\language", 0)
1738         if i != -1:
1739             document.header[i] = "\\language japanese"
1740     j = 0
1741     while True:
1742         j = find_token(document.body, "\\lang japanese-plain", j)
1743         if j == -1:
1744             return
1745         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1746         j = j + 1
1747
1748
1749 ##
1750 # Conversion hub
1751 #
1752
1753 supported_versions = ["1.6.0","1.6"]
1754 convert = [[277, [fix_wrong_tables]],
1755            [278, [close_begin_deeper]],
1756            [279, [long_charstyle_names]],
1757            [280, [axe_show_label]],
1758            [281, []],
1759            [282, []],
1760            [283, [convert_flex]],
1761            [284, []],
1762            [285, []],
1763            [286, []],
1764            [287, [convert_wrapfig_options]],
1765            [288, [convert_inset_command]],
1766            [289, [convert_latexcommand_index]],
1767            [290, []],
1768            [291, []],
1769            [292, []],
1770            [293, []],
1771            [294, [convert_pdf_options]],
1772            [295, [convert_htmlurl, convert_url]],
1773            [296, [convert_include]],
1774            [297, [convert_usorbian]],
1775            [298, []],
1776            [299, []],
1777            [300, []],
1778            [301, []],
1779            [302, []],
1780            [303, [convert_serbocroatian]],
1781            [304, [convert_framed_notes]],
1782            [305, []],
1783            [306, []],
1784            [307, []],
1785            [308, []],
1786            [309, []],
1787            [310, []],
1788            [311, [convert_ams_classes]],
1789            [312, []],
1790            [313, [convert_module_names]],
1791            [314, []],
1792            [315, []],
1793            [316, [convert_subfig]],
1794            [317, []],
1795            [318, []],
1796            [319, [convert_spaceinset, convert_hfill]],
1797            [320, []],
1798            [321, [convert_tablines]],
1799            [322, []],
1800            [323, [convert_pagebreaks]],
1801            [324, [convert_linebreaks]],
1802            [325, [convert_japanese_plain]],
1803           ]
1804
1805 revert =  [[324, []],
1806            [323, [revert_linebreaks]],
1807            [322, [revert_pagebreaks]],
1808            [321, [revert_local_layout]],
1809            [320, [revert_tablines]],
1810            [319, [revert_protected_hfill]],
1811            [318, [revert_spaceinset, revert_hfills, revert_hspace]],
1812            [317, [remove_extra_embedded_files]],
1813            [316, [revert_wrapplacement]],
1814            [315, [revert_subfig]],
1815            [314, [revert_colsep]],
1816            [313, []],
1817            [312, [revert_module_names]],
1818            [311, [revert_rotfloat, revert_widesideways]],
1819            [310, []],
1820            [309, [revert_btprintall]],
1821            [308, [revert_nocite]],
1822            [307, [revert_serbianlatin]],
1823            [306, [revert_slash, revert_nobreakdash]],
1824            [305, [revert_interlingua]],
1825            [304, [revert_bahasam]],
1826            [303, [revert_framed_notes]],
1827            [302, []],
1828            [301, [revert_latin, revert_samin]],
1829            [300, [revert_linebreak]],
1830            [299, [revert_pagebreak]],
1831            [298, [revert_hyperlinktype]],
1832            [297, [revert_macro_optional_params]],
1833            [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
1834            [295, [revert_include]],
1835            [294, [revert_href]],
1836            [293, [revert_pdf_options_2]],
1837            [292, [revert_inset_info]],
1838            [291, [revert_japanese, revert_japanese_encoding]],
1839            [290, [revert_vietnamese]],
1840            [289, [revert_wraptable]],
1841            [288, [revert_latexcommand_index]],
1842            [287, [revert_inset_command]],
1843            [286, [revert_wrapfig_options]],
1844            [285, [revert_pdf_options]],
1845            [284, [remove_inzip_options]],
1846            [283, []],
1847            [282, [revert_flex]],
1848            [281, []],
1849            [280, [revert_begin_modules]],
1850            [279, [revert_show_label]],
1851            [278, [revert_long_charstyle_names]],
1852            [277, []],
1853            [276, []]
1854           ]
1855
1856
1857 if __name__ == "__main__":
1858     pass