]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_1_6.py
Add support for column separation in page margins. Fixes bug 3337.
[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 fix_wrong_tables(document):
51     i = 0
52     while True:
53         i = find_token(document.body, "\\begin_inset Tabular", i)
54         if i == -1:
55             return
56         j = find_end_of_inset(document.body, i + 1)
57         if j == -1:
58             document.warning("Malformed LyX document: Could not find end of tabular.")
59             continue
60
61         m = i + 1
62         nrows = int(document.body[i+1].split('"')[3])
63         ncols = int(document.body[i+1].split('"')[5])
64
65         for l in range(nrows):
66             prev_multicolumn = 0
67             for k in range(ncols):
68                 m = find_token(document.body, '<cell', m)
69
70                 if document.body[m].find('multicolumn') != -1:
71                     multicol_cont = int(document.body[m].split('"')[1])
72
73                     if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
74                         document.body[m] = document.body[m][:5] + document.body[m][21:]
75                         prev_multicolumn = 0
76                     else:
77                         prev_multicolumn = multicol_cont
78                 else:
79                     prev_multicolumn = 0
80
81         i = j + 1
82
83
84 def close_begin_deeper(document):
85     i = 0
86     depth = 0
87     while True:
88         i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
89
90         if i == -1:
91             break
92
93         if document.body[i][:13] == "\\begin_deeper":
94             depth += 1
95         else:
96             depth -= 1
97
98         i += 1
99
100     document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
101
102
103 def long_charstyle_names(document):
104     i = 0
105     while True:
106         i = find_token(document.body, "\\begin_inset CharStyle", i)
107         if i == -1:
108             return
109         document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
110         i += 1
111
112 def revert_long_charstyle_names(document):
113     i = 0
114     while True:
115         i = find_token(document.body, "\\begin_inset CharStyle", i)
116         if i == -1:
117             return
118         document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle")
119         i += 1
120
121
122 def axe_show_label(document):
123     i = 0
124     while True:
125         i = find_token(document.body, "\\begin_inset CharStyle", i)
126         if i == -1:
127             return
128         if document.body[i + 1].find("show_label") != -1:
129             if document.body[i + 1].find("true") != -1:
130                 document.body[i + 1] = "status open"
131                 del document.body[ i + 2]
132             else:
133                 if document.body[i + 1].find("false") != -1:
134                     document.body[i + 1] = "status collapsed"
135                     del document.body[ i + 2]
136                 else:
137                     document.warning("Malformed LyX document: show_label neither false nor true.")
138         else:
139             document.warning("Malformed LyX document: show_label missing in CharStyle.")
140             
141         i += 1
142
143
144 def revert_show_label(document):
145     i = 0
146     while True:
147         i = find_token(document.body, "\\begin_inset CharStyle", i)
148         if i == -1:
149             return
150         if document.body[i + 1].find("status open") != -1:
151             document.body.insert(i + 1, "show_label true")
152         else:
153             if document.body[i + 1].find("status collapsed") != -1:
154                 document.body.insert(i + 1, "show_label false")
155             else:
156                 document.warning("Malformed LyX document: no legal status line in CharStyle.")
157         i += 1
158
159 def revert_begin_modules(document):
160     i = 0
161     while True:
162         i = find_token(document.header, "\\begin_modules", i)
163         if i == -1:
164             return
165         j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
166         if j == -1:
167             # this should not happen
168             break
169         document.header[i : j + 1] = []
170
171 def convert_flex(document):
172     "Convert CharStyle to Flex"
173     i = 0
174     while True:
175         i = find_token(document.body, "\\begin_inset CharStyle", i)
176         if i == -1:
177             return
178         document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
179
180 def revert_flex(document):
181     "Convert Flex to CharStyle"
182     i = 0
183     while True:
184         i = find_token(document.body, "\\begin_inset Flex", i)
185         if i == -1:
186             return
187         document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
188
189
190 #  Discard PDF options for hyperref
191 def revert_pdf_options(document):
192         "Revert PDF options for hyperref."
193         i = 0
194         i = find_token(document.header, "\\use_hyperref", i)
195         if i != -1:
196             del document.header[i]
197         i = find_token(document.header, "\\pdf_store_options", i)
198         if i != -1:
199             del document.header[i]
200         i = find_token(document.header, "\\pdf_title", 0)
201         if i != -1:
202             del document.header[i]
203         i = find_token(document.header, "\\pdf_author", 0)
204         if i != -1:
205             del document.header[i]
206         i = find_token(document.header, "\\pdf_subject", 0)
207         if i != -1:
208             del document.header[i]
209         i = find_token(document.header, "\\pdf_keywords", 0)
210         if i != -1:
211             del document.header[i]
212         i = find_token(document.header, "\\pdf_bookmarks", 0)
213         if i != -1:
214             del document.header[i]
215         i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
216         if i != -1:
217             del document.header[i]
218         i = find_token(document.header, "\\pdf_bookmarksopen", i)
219         if i != -1:
220             del document.header[i]
221         i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
222         if i != -1:
223             del document.header[i]
224         i = find_token(document.header, "\\pdf_breaklinks", i)
225         if i != -1:
226             del document.header[i]
227         i = find_token(document.header, "\\pdf_pdfborder", i)
228         if i != -1:
229             del document.header[i]
230         i = find_token(document.header, "\\pdf_colorlinks", i)
231         if i != -1:
232             del document.header[i]
233         i = find_token(document.header, "\\pdf_backref", i)
234         if i != -1:
235             del document.header[i]
236         i = find_token(document.header, "\\pdf_pagebackref", i)
237         if i != -1:
238             del document.header[i]
239         i = find_token(document.header, "\\pdf_pagemode", 0)
240         if i != -1:
241             del document.header[i]
242         i = find_token(document.header, "\\pdf_quoted_options", 0)
243         if i != -1:
244             del document.header[i]
245
246
247 def remove_inzip_options(document):
248     "Remove inzipName and embed options from the Graphics inset"
249     i = 0
250     while 1:
251         i = find_token(document.body, "\\begin_inset Graphics", i)
252         if i == -1:
253             return
254         j = find_end_of_inset(document.body, i + 1)
255         if j == -1:
256             # should not happen
257             document.warning("Malformed LyX document: Could not find end of graphics inset.")
258         # If there's a inzip param, just remove that
259         k = find_token(document.body, "\tinzipName", i + 1, j)
260         if k != -1:
261             del document.body[k]
262             # embed option must follow the inzipName option
263             del document.body[k+1]
264         i = i + 1
265
266
267 def convert_inset_command(document):
268     """
269         Convert:
270             \begin_inset LatexCommand cmd 
271         to 
272             \begin_inset CommandInset InsetType
273             LatexCommand cmd
274     """
275     i = 0
276     while 1:
277         i = find_token(document.body, "\\begin_inset LatexCommand", i)
278         if i == -1:
279             return
280         line = document.body[i]
281         r = re.compile(r'\\begin_inset LatexCommand (.*)$')
282         m = r.match(line)
283         cmdName = m.group(1)
284         insetName = ""
285         #this is adapted from factory.cpp
286         if cmdName[0:4].lower() == "cite":
287             insetName = "citation"
288         elif cmdName == "url" or cmdName == "htmlurl":
289             insetName = "url"
290         elif cmdName[-3:] == "ref":
291             insetName = "ref"
292         elif cmdName == "tableofcontents":
293             insetName = "toc"
294         elif cmdName == "printnomenclature":
295             insetName = "nomencl_print"
296         elif cmdName == "printindex":
297             insetName = "index_print"
298         else:
299             insetName = cmdName
300         insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
301         document.body[i : i+1] = insertion
302
303
304 def revert_inset_command(document):
305     """
306         Convert:
307             \begin_inset CommandInset InsetType
308             LatexCommand cmd
309         to 
310             \begin_inset LatexCommand cmd 
311         Some insets may end up being converted to insets earlier versions of LyX
312         will not be able to recognize. Not sure what to do about that.
313     """
314     i = 0
315     while 1:
316         i = find_token(document.body, "\\begin_inset CommandInset", i)
317         if i == -1:
318             return
319         nextline = document.body[i+1]
320         r = re.compile(r'LatexCommand\s+(.*)$')
321         m = r.match(nextline)
322         if not m:
323             document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
324             continue
325         cmdName = m.group(1)
326         insertion = ["\\begin_inset LatexCommand " + cmdName]
327         document.body[i : i+2] = insertion
328
329
330 def convert_wrapfig_options(document):
331     "Convert optional options for wrap floats (wrapfig)."
332     # adds the tokens "lines", "placement", and "overhang"
333     i = 0
334     while True:
335         i = find_token(document.body, "\\begin_inset Wrap figure", i)
336         if i == -1:
337             return
338         document.body.insert(i + 1, "lines 0")
339         j = find_token(document.body, "placement", i)
340         # placement can be already set or not; if not, set it
341         if j == i+2:
342             document.body.insert(i + 3, "overhang 0col%")
343         else:
344            document.body.insert(i + 2, "placement o")
345            document.body.insert(i + 3, "overhang 0col%")
346         i = i + 1
347
348
349 def revert_wrapfig_options(document):
350     "Revert optional options for wrap floats (wrapfig)."
351     i = 0
352     while True:
353         i = find_token(document.body, "lines", i)
354         if i == -1:
355             return
356         j = find_token(document.body, "overhang", i+1)
357         if j != i + 2 and j != -1:
358             document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float.")
359         if j == -1:
360             return
361         del document.body[i]
362         del document.body[j-1]
363         i = i + 1
364
365
366 def convert_latexcommand_index(document):
367     "Convert from LatexCommand form to collapsable form."
368     i = 0 
369     while True:
370         i = find_token(document.body, "\\begin_inset CommandInset index", i)
371         if i == -1:
372             return
373         if document.body[i + 1] != "LatexCommand index": # Might also be index_print
374             return
375         fullcontent = document.body[i + 2][6:].strip('"')
376         document.body[i:i + 2] = ["\\begin_inset Index",
377           "status collapsed",
378           "\\begin_layout Standard"]
379         # Put here the conversions needed from LaTeX string to LyXText.
380         # Here we do a minimal conversion to prevent crashes and data loss.
381         # Manual patch-up may be needed.
382         # Umlauted characters (most common ones, can be extended):
383         fullcontent = fullcontent.replace(r'\\\"a', u'ä').replace(r'\\\"o', u'ö').replace(r'\\\"u', u'ü')
384         # Generic, \" -> ":
385         fullcontent = wrap_into_ert(fullcontent, r'\"', '"')
386         #fullcontent = fullcontent.replace(r'\"', '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout standard\n"\n\\end_layout\n\\end_inset\n')
387         # Math:
388         r = re.compile('^(.*?)(\$.*?\$)(.*)')
389         g = fullcontent
390         while r.match(g):
391           m = r.match(g)
392           s = m.group(1)
393           f = m.group(2).replace('\\\\', '\\')
394           g = m.group(3)
395           if s:
396             # this is non-math!
397             s = wrap_into_ert(s, r'\\', '\\backslash')
398             s = wrap_into_ert(s, '{', '{')
399             s = wrap_into_ert(s, '}', '}')
400             document.body.insert(i + 3, s)
401             i += 1
402           document.body.insert(i + 3, "\\begin_inset Formula " + f)
403           document.body.insert(i + 4, "\\end_inset")
404           i += 2
405         # Generic, \\ -> \backslash:
406         g = wrap_into_ert(g, r'\\', '\\backslash{}')
407         g = wrap_into_ert(g, '{', '{')
408         g = wrap_into_ert(g, '}', '}')
409         document.body.insert(i + 3, g)
410         document.body[i + 4] = "\\end_layout"
411         i = i + 5
412
413
414 def revert_latexcommand_index(document):
415     "Revert from collapsable form to LatexCommand form."
416     i = 0
417     while True:
418         i = find_token(document.body, "\\begin_inset Index", i)
419         if i == -1:
420           return
421         j = find_end_of_inset(document.body, i + 1)
422         if j == -1:
423           return
424         del document.body[j - 1]
425         del document.body[j - 2] # \end_layout
426         document.body[i] =  "\\begin_inset CommandInset index"
427         document.body[i + 1] =  "LatexCommand index"
428         # clean up multiline stuff
429         content = ""
430         for k in range(i + 3, j - 2):
431           line = document.body[k]
432           if line.startswith("\\begin_inset ERT"):
433             line = line[16:]
434           if line.startswith("\\begin_inset Formula"):
435             line = line[20:]
436           if line.startswith("\\begin_layout Standard"):
437             line = line[22:]
438           if line.startswith("\\end_layout"):
439             line = line[11:]
440           if line.startswith("\\end_inset"):
441             line = line[10:]
442           if line.startswith("status collapsed"):
443             line = line[16:]
444           line = line.replace(u'ä', r'\\\"a').replace(u'ö', r'\\\"o').replace(u'ü', r'\\\"u')
445           content = content + line;
446         document.body[i + 3] = "name " + '"' + content + '"'
447         for k in range(i + 4, j - 2):
448           del document.body[i + 4]
449         document.body.insert(i + 4, "")
450         del document.body[i + 2] # \begin_layout standard
451         i = i + 5
452
453
454 def revert_wraptable(document):
455     "Revert wrap table to wrap figure."
456     i = 0
457     while True:
458         i = find_token(document.body, "\\begin_inset Wrap table", i)
459         if i == -1:
460             return
461         document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
462         i = i + 1
463
464
465 def revert_vietnamese(document):
466     "Set language Vietnamese to English"
467     # Set document language from Vietnamese to English
468     i = 0
469     if document.language == "vietnamese":
470         document.language = "english"
471         i = find_token(document.header, "\\language", 0)
472         if i != -1:
473             document.header[i] = "\\language english"
474     j = 0
475     while True:
476         j = find_token(document.body, "\\lang vietnamese", j)
477         if j == -1:
478             return
479         document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
480         j = j + 1
481
482
483 def revert_japanese(document):
484     "Set language japanese-plain to japanese"
485     # Set document language from japanese-plain to japanese
486     i = 0
487     if document.language == "japanese-plain":
488         document.language = "japanese"
489         i = find_token(document.header, "\\language", 0)
490         if i != -1:
491             document.header[i] = "\\language japanese"
492     j = 0
493     while True:
494         j = find_token(document.body, "\\lang japanese-plain", j)
495         if j == -1:
496             return
497         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
498         j = j + 1
499
500
501 def revert_japanese_encoding(document):
502     "Set input encoding form EUC-JP-plain to EUC-JP etc."
503     # Set input encoding form EUC-JP-plain to EUC-JP etc.
504     i = 0
505     i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
506     if i != -1:
507         document.header[i] = "\\inputencoding EUC-JP"
508     j = 0
509     j = find_token(document.header, "\\inputencoding JIS-plain", 0)
510     if j != -1:
511         document.header[j] = "\\inputencoding JIS"
512     k = 0
513     k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
514     if k != -1: # convert to UTF8 since there is currently no SJIS encoding 
515         document.header[k] = "\\inputencoding UTF8"
516
517
518 def revert_inset_info(document):
519     'Replace info inset with its content'
520     i = 0
521     while 1:
522         i = find_token(document.body, '\\begin_inset Info', i)
523         if i == -1:
524             return
525         j = find_end_of_inset(document.body, i + 1)
526         if j == -1:
527             # should not happen
528             document.warning("Malformed LyX document: Could not find end of Info inset.")
529         type = 'unknown'
530         arg = ''
531         for k in range(i, j+1):
532             if document.body[k].startswith("arg"):
533                 arg = document.body[k][3:].strip().strip('"')
534             if document.body[k].startswith("type"):
535                 type = document.body[k][4:].strip().strip('"')
536         # I think there is a newline after \\end_inset, which should be removed.
537         if document.body[j + 1].strip() == "":
538             document.body[i : (j + 2)] = [type + ':' + arg]
539         else:
540             document.body[i : (j + 1)] = [type + ':' + arg]
541
542
543 def convert_pdf_options(document):
544     # Set the pdfusetitle tag, delete the pdf_store_options,
545     # set quotes for bookmarksopenlevel"
546     has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
547     if has_hr == "1":
548         k = find_token(document.header, "\\use_hyperref", 0)
549         document.header.insert(k + 1, "\\pdf_pdfusetitle true")
550     k = find_token(document.header, "\\pdf_store_options", 0)
551     if k != -1:
552         del document.header[k]
553     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
554     if i == -1: return
555     document.header[i] = document.header[i].replace('"', '')
556
557
558 def revert_pdf_options_2(document):
559     # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
560     k = find_token(document.header, "\\use_hyperref", 0)
561     i = find_token(document.header, "\\pdf_pdfusetitle", k)
562     if i != -1:
563         del document.header[i]
564     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
565     if i == -1: return
566     values = document.header[i].split()
567     values[1] = ' "' + values[1] + '"'
568     document.header[i] = ''.join(values)
569
570
571 def convert_htmlurl(document):
572     'Convert "htmlurl" to "href" insets for docbook'
573     if document.backend != "docbook":
574       return
575     i = 0
576     while True:
577       i = find_token(document.body, "\\begin_inset CommandInset url", i)
578       if i == -1:
579         return
580       document.body[i] = "\\begin_inset CommandInset href"
581       document.body[i + 1] = "LatexCommand href"
582       i = i + 1
583
584
585 def convert_url(document):
586     'Convert url insets to url charstyles'
587     if document.backend == "docbook":
588       return
589     i = 0
590     while True:
591       i = find_token(document.body, "\\begin_inset CommandInset url", i)
592       if i == -1:
593         break
594       n = find_token(document.body, "name", i)
595       if n == i + 2:
596         # place the URL name in typewriter before the new URL insert
597         # grab the name 'bla' from the e.g. the line 'name "bla"',
598         # therefore start with the 6th character
599         name = document.body[n][6:-1]
600         newname = [name + " "]
601         document.body[i:i] = newname
602         i = i + 1
603       j = find_token(document.body, "target", i)
604       if j == -1:
605         document.warning("Malformed LyX document: Can't find target for url inset")
606         i = j
607         continue
608       target = document.body[j][8:-1]
609       k = find_token(document.body, "\\end_inset", j)
610       if k == -1:
611         document.warning("Malformed LyX document: Can't find end of url inset")
612         i = k
613         continue
614       newstuff = ["\\begin_inset Flex URL",
615         "status collapsed", "", 
616         "\\begin_layout Standard",
617         "",
618         target,
619         "\\end_layout",
620         ""]
621       document.body[i:k] = newstuff
622       i = k
623
624 def convert_ams_classes(document):
625   tc = document.textclass
626   if (tc != "amsart" and tc != "amsart-plain" and
627       tc != "amsart-seq" and tc != "amsbook"):
628     return
629   if tc == "amsart-plain":
630     document.textclass = "amsart"
631     document.set_textclass()
632     document.add_module("Theorems (Starred)")
633     return
634   if tc == "amsart-seq":
635     document.textclass = "amsart"
636     document.set_textclass()
637   document.add_module("Theorems (AMS)")
638
639   #Now we want to see if any of the environments in the extended theorems
640   #module were used in this document. If so, we'll add that module, too.
641   layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note",  \
642     "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
643     "Assumption"]
644
645   r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
646   i = 0
647   while True:
648     i = find_token(document.body, "\\begin_layout", i)
649     if i == -1:
650       return
651     m = r.match(document.body[i])
652     if m == None:
653       document.warning("Weirdly formed \\begin_layout at line " + i + " of body!")
654       i += 1
655       continue
656     m = m.group(1)
657     if layouts.count(m) != 0:
658       document.add_module("Theorems (AMS-Extended)")
659       return
660     i += 1
661
662 def revert_href(document):
663     'Reverts hyperlink insets (href) to url insets (url)'
664     i = 0
665     while True:
666       i = find_token(document.body, "\\begin_inset CommandInset href", i)
667       if i == -1:
668           return
669       document.body[i : i + 2] = \
670         ["\\begin_inset CommandInset url", "LatexCommand url"]
671       i = i + 2
672
673
674 def convert_include(document):
675   'Converts include insets to new format.'
676   i = 0
677   r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
678   while True:
679     i = find_token(document.body, "\\begin_inset Include", i)
680     if i == -1:
681       return
682     line = document.body[i]
683     previewline = document.body[i + 1]
684     m = r.match(line)
685     if m == None:
686       document.warning("Unable to match line " + str(i) + " of body!")
687       i += 1
688       continue
689     cmd = m.group(1)
690     fn  = m.group(2)
691     opt = m.group(3)
692     insertion = ["\\begin_inset CommandInset include", 
693        "LatexCommand " + cmd, previewline,
694        "filename \"" + fn + "\""]
695     newlines = 2
696     if opt:
697       insertion.append("lstparams " + '"' + opt + '"')
698       newlines += 1
699     document.body[i : i + 2] = insertion
700     i += newlines
701
702
703 def revert_include(document):
704   'Reverts include insets to old format.'
705   i = 0
706   r1 = re.compile('LatexCommand (.+)')
707   r2 = re.compile('filename (.+)')
708   r3 = re.compile('options (.*)')
709   while True:
710     i = find_token(document.body, "\\begin_inset CommandInset include", i)
711     if i == -1:
712       return
713     previewline = document.body[i + 1]
714     m = r1.match(document.body[i + 2])
715     if m == None:
716       document.warning("Malformed LyX document: No LatexCommand line for `" +
717         document.body[i] + "' on line " + str(i) + ".")
718       i += 1
719       continue
720     cmd = m.group(1)
721     m = r2.match(document.body[i + 3])
722     if m == None:
723       document.warning("Malformed LyX document: No filename line for `" + \
724         document.body[i] + "' on line " + str(i) + ".")
725       i += 2
726       continue
727     fn = m.group(1)
728     options = ""
729     numlines = 4
730     if (cmd == "lstinputlisting"):
731       m = r3.match(document.body[i + 4])
732       if m != None:
733         options = m.group(1)
734         numlines = 5
735     newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
736     if options:
737       newline += ("[" + options + "]")
738     insertion = [newline, previewline]
739     document.body[i : i + numlines] = insertion
740     i += 2
741
742
743 def revert_albanian(document):
744     "Set language Albanian to English"
745     i = 0
746     if document.language == "albanian":
747         document.language = "english"
748         i = find_token(document.header, "\\language", 0)
749         if i != -1:
750             document.header[i] = "\\language english"
751     j = 0
752     while True:
753         j = find_token(document.body, "\\lang albanian", j)
754         if j == -1:
755             return
756         document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
757         j = j + 1
758
759
760 def revert_lowersorbian(document):
761     "Set language lower Sorbian to English"
762     i = 0
763     if document.language == "lowersorbian":
764         document.language = "english"
765         i = find_token(document.header, "\\language", 0)
766         if i != -1:
767             document.header[i] = "\\language english"
768     j = 0
769     while True:
770         j = find_token(document.body, "\\lang lowersorbian", j)
771         if j == -1:
772             return
773         document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
774         j = j + 1
775
776
777 def revert_uppersorbian(document):
778     "Set language uppersorbian to usorbian as this was used in LyX 1.5"
779     i = 0
780     if document.language == "uppersorbian":
781         document.language = "usorbian"
782         i = find_token(document.header, "\\language", 0)
783         if i != -1:
784             document.header[i] = "\\language usorbian"
785     j = 0
786     while True:
787         j = find_token(document.body, "\\lang uppersorbian", j)
788         if j == -1:
789             return
790         document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
791         j = j + 1
792
793
794 def convert_usorbian(document):
795     "Set language usorbian to uppersorbian"
796     i = 0
797     if document.language == "usorbian":
798         document.language = "uppersorbian"
799         i = find_token(document.header, "\\language", 0)
800         if i != -1:
801             document.header[i] = "\\language uppersorbian"
802     j = 0
803     while True:
804         j = find_token(document.body, "\\lang usorbian", j)
805         if j == -1:
806             return
807         document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
808         j = j + 1
809
810
811 def revert_macro_optional_params(document):
812     "Convert macro definitions with optional parameters into ERTs"
813     # Stub to convert macro definitions with one or more optional parameters
814     # into uninterpreted ERT insets
815
816
817 def revert_hyperlinktype(document):
818     'Reverts hyperlink type'
819     i = 0
820     j = 0
821     while True:
822       i = find_token(document.body, "target", i)
823       if i == -1:
824           return
825       j = find_token(document.body, "type", i)
826       if j == -1:
827           return
828       if j == i + 1:
829           del document.body[j]
830       i = i + 1
831
832
833 def revert_pagebreak(document):
834     'Reverts pagebreak to ERT'
835     i = 0
836     while True:
837       i = find_token(document.body, "\\pagebreak", i)
838       if i == -1:
839           return
840       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
841       '\\begin_layout Standard\n\n\n\\backslash\n' \
842       'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
843       i = i + 1
844
845
846 def revert_linebreak(document):
847     'Reverts linebreak to ERT'
848     i = 0
849     while True:
850       i = find_token(document.body, "\\linebreak", i)
851       if i == -1:
852           return
853       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
854       '\\begin_layout Standard\n\n\n\\backslash\n' \
855       'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
856       i = i + 1
857
858
859 def revert_latin(document):
860     "Set language Latin to English"
861     i = 0
862     if document.language == "latin":
863         document.language = "english"
864         i = find_token(document.header, "\\language", 0)
865         if i != -1:
866             document.header[i] = "\\language english"
867     j = 0
868     while True:
869         j = find_token(document.body, "\\lang latin", j)
870         if j == -1:
871             return
872         document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
873         j = j + 1
874
875
876 def revert_samin(document):
877     "Set language North Sami to English"
878     i = 0
879     if document.language == "samin":
880         document.language = "english"
881         i = find_token(document.header, "\\language", 0)
882         if i != -1:
883             document.header[i] = "\\language english"
884     j = 0
885     while True:
886         j = find_token(document.body, "\\lang samin", j)
887         if j == -1:
888             return
889         document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
890         j = j + 1
891
892
893 def convert_serbocroatian(document):
894     "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
895     i = 0
896     if document.language == "serbocroatian":
897         document.language = "croatian"
898         i = find_token(document.header, "\\language", 0)
899         if i != -1:
900             document.header[i] = "\\language croatian"
901     j = 0
902     while True:
903         j = find_token(document.body, "\\lang serbocroatian", j)
904         if j == -1:
905             return
906         document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
907         j = j + 1
908
909
910 def convert_framed_notes(document):
911     "Convert framed notes to boxes. "
912     i = 0
913     while 1:
914         i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
915
916         if i == -1:
917             return
918         document.body[i] = document.body[i].replace("\\begin_inset Note", "\\begin_inset Box")
919         document.body.insert(i + 1, 'position "t"\nhor_pos "c"\nhas_inner_box 0\ninner_pos "t"\n' \
920         'use_parbox 0\nwidth "100col%"\nspecial "none"\nheight "1in"\n' \
921         'height_special "totalheight"')
922         i = i + 1
923
924
925 def convert_module_names(document):
926   modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
927     'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
928     'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
929     'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
930     'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
931   modlist = document.get_module_list()
932   if len(modlist) == 0:
933     return
934   newmodlist = []
935   for mod in modlist:
936     if modulemap.has_key(mod):
937       newmodlist.append(modulemap[mod])
938     else:
939       document.warning("Can't find module %s in the module map!" % mod)
940       newmodlist.append(mod)
941   document.set_module_list(newmodlist)
942
943
944 def revert_module_names(document):
945   modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
946     'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
947     'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
948     'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
949     'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
950   modlist = document.get_module_list()
951   if len(modlist) == 0:
952     return
953   newmodlist = []
954   for mod in modlist:
955     if modulemap.has_key(mod):
956       newmodlist.append(modulemap[mod])
957     else:
958       document.warning("Can't find module %s in the module map!" % mod)
959       newmodlist.append(mod)
960   document.set_module_list(newmodlist)
961
962
963 def revert_colsep(document):
964     i = find_token(document.header, "\\columnsep", 0)
965     if i == -1:
966         return
967     colsepline = document.header[i]
968     r = re.compile(r'\\columnsep (.*)')
969     m = r.match(colsepline)
970     if not m:
971         document.warning("Malformed column separation line!")
972         return
973     colsep = m.group(1)
974     del document.header[i]
975     #it seems to be safe to add the package even if it is already used
976     pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
977
978     add_to_preamble(document, pretext)
979
980
981 def revert_framed_notes(document):
982     "Revert framed boxes to notes. "
983     i = 0
984     while 1:
985         i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
986
987         if i == -1:
988             return
989         j = find_end_of_inset(document.body, i + 1)
990         if j == -1:
991             # should not happen
992             document.warning("Malformed LyX document: Could not find end of Box inset.")
993         k = find_token(document.body, "status", i + 1, j)
994         if k == -1:
995             document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
996             return
997         status = document.body[k]
998         l = find_token(document.body, "\\begin_layout Standard", i + 1, j)
999         if l == -1:
1000             document.warning("Malformed LyX document: Missing `\\begin_layout Standard' in Box inset.")
1001             return
1002         m = find_token(document.body, "\\end_layout", i + 1, j)
1003         if m == -1:
1004             document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1005             return
1006         ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1007         pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1008         if ibox == -1 and pbox == -1:
1009             document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1010             del document.body[i+1:k]
1011         else:
1012             document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1013             document.body.insert(l + 1, "\\begin_inset Note Shaded\n" + status + "\n\\begin_layout Standard\n")
1014             document.body.insert(m + 1, "\\end_layout\n\\end_inset")
1015         i = i + 1
1016
1017
1018 def revert_slash(document):
1019     'Revert \\SpecialChar \\slash{} to ERT'
1020     for i in range(len(document.body)):
1021         document.body[i] = document.body[i].replace('\\SpecialChar \\slash{}', \
1022         '\\begin_inset ERT\nstatus collapsed\n\n' \
1023         '\\begin_layout Standard\n\n\n\\backslash\n' \
1024         'slash{}\n\\end_layout\n\n\\end_inset\n\n')
1025
1026
1027 def revert_nobreakdash(document):
1028     'Revert \\SpecialChar \\nobreakdash- to ERT'
1029     found = 0
1030     for i in range(len(document.body)):
1031         line = document.body[i]
1032         r = re.compile(r'\\SpecialChar \\nobreakdash-')
1033         m = r.match(line)
1034         if m:
1035             found = 1
1036         document.body[i] = document.body[i].replace('\\SpecialChar \\nobreakdash-', \
1037         '\\begin_inset ERT\nstatus collapsed\n\n' \
1038         '\\begin_layout Standard\n\n\n\\backslash\n' \
1039         'nobreakdash-\n\\end_layout\n\n\\end_inset\n\n')
1040     if not found:
1041         return
1042     j = find_token(document.header, "\\use_amsmath", 0)
1043     if j == -1:
1044         document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1045         return
1046     document.header[j] = "\\use_amsmath 2"
1047
1048
1049 def revert_nocite_key(body, start, end):
1050     'key "..." -> \nocite{...}'
1051     for i in range(start, end):
1052         if (body[i][0:5] == 'key "'):
1053             body[i] = body[i].replace('key "', "\\backslash\nnocite{")
1054             body[i] = body[i].replace('"', "}")
1055         else:
1056             body[i] = ""
1057
1058
1059 def revert_nocite(document):
1060     "Revert LatexCommand nocite to ERT"
1061     i = 0
1062     while 1:
1063         i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1064         if i == -1:
1065             return
1066         i = i + 1
1067         if (document.body[i] == "LatexCommand nocite"):
1068             j = find_end_of_inset(document.body, i + 1)
1069             if j == -1:
1070                 #this should not happen
1071                 document.warning("End of CommandInset citation not found in revert_nocite!")
1072                 revert_nocite_key(document.body, i + 1, len(document.body))
1073                 return
1074             revert_nocite_key(document.body, i + 1, j)
1075             document.body[i-1] = "\\begin_inset ERT"
1076             document.body[i] = "status collapsed\n\n" \
1077             "\\begin_layout Standard"
1078             document.body.insert(j, "\\end_layout\n");
1079             i = j
1080
1081
1082 def revert_btprintall(document):
1083     "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1084     i = find_token(document.header, '\\use_bibtopic', 0)
1085     if i == -1:
1086         document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1087         return
1088     if get_value(document.header, '\\use_bibtopic', 0) == "false":
1089         i = 0
1090         while i < len(document.body):
1091             i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1092             if i == -1:
1093                 return
1094             j = find_end_of_inset(document.body, i + 1)
1095             if j == -1:
1096                 #this should not happen
1097                 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1098                 j = len(document.body)
1099             for k in range(i, j):
1100                 if (document.body[k] == 'btprint "btPrintAll"'):
1101                     del document.body[k]
1102                     document.body.insert(i, "\\begin_inset ERT\n" \
1103                     "status collapsed\n\n\\begin_layout Standard\n\n" \
1104                     "\\backslash\nnocite{*}\n" \
1105                     "\\end_layout\n\\end_inset\n")
1106             i = j
1107
1108
1109 def revert_bahasam(document):
1110     "Set language Bahasa Malaysia to Bahasa Indonesia"
1111     i = 0
1112     if document.language == "bahasam":
1113         document.language = "bahasa"
1114         i = find_token(document.header, "\\language", 0)
1115         if i != -1:
1116             document.header[i] = "\\language bahasa"
1117     j = 0
1118     while True:
1119         j = find_token(document.body, "\\lang bahasam", j)
1120         if j == -1:
1121             return
1122         document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1123         j = j + 1
1124
1125
1126 def revert_interlingua(document):
1127     "Set language Interlingua to English"
1128     i = 0
1129     if document.language == "interlingua":
1130         document.language = "english"
1131         i = find_token(document.header, "\\language", 0)
1132         if i != -1:
1133             document.header[i] = "\\language english"
1134     j = 0
1135     while True:
1136         j = find_token(document.body, "\\lang interlingua", j)
1137         if j == -1:
1138             return
1139         document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1140         j = j + 1
1141
1142
1143 def revert_serbianlatin(document):
1144     "Set language Serbian-Latin to Croatian"
1145     i = 0
1146     if document.language == "serbian-latin":
1147         document.language = "croatian"
1148         i = find_token(document.header, "\\language", 0)
1149         if i != -1:
1150             document.header[i] = "\\language croatian"
1151     j = 0
1152     while True:
1153         j = find_token(document.body, "\\lang serbian-latin", j)
1154         if j == -1:
1155             return
1156         document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
1157         j = j + 1
1158
1159
1160 def revert_rotfloat(document):
1161     " Revert sideways custom floats. "
1162     i = 0
1163     while 1:
1164         i = find_token(document.body, "\\begin_inset Float", i)
1165         if i == -1:
1166             return
1167         line = document.body[i]
1168         r = re.compile(r'\\begin_inset Float (.*)$')
1169         m = r.match(line)
1170         floattype = m.group(1)
1171         if floattype == "figure" or floattype == "table":
1172             i = i + 1
1173             continue
1174         j = find_end_of_inset(document.body, i)
1175         if j == -1:
1176             document.warning("Malformed lyx document: Missing '\\end_inset'.")
1177             i = i + 1
1178             continue
1179         if get_value(document.body, 'sideways', i, j) != "false":
1180             l = find_token(document.body, "\\begin_layout Standard", i + 1, j)
1181             if l == -1:
1182                 document.warning("Malformed LyX document: Missing `\\begin_layout Standard' in Float inset.")
1183                 return
1184             document.body[j] = '\\begin_layout Standard\n\\begin_inset ERT\nstatus collapsed\n\n' \
1185             '\\begin_layout Standard\n\n\n\\backslash\n' \
1186             'end{sideways' + floattype + '}\n\\end_layout\n\n\\end_inset\n'
1187             del document.body[i+1:l-1]
1188             document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1189             '\\begin_layout Standard\n\n\n\\backslash\n' \
1190             'begin{sideways' + floattype + '}\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n\n'
1191             if floattype == "algorithm":
1192                 add_to_preamble(document,
1193                                 ['% Commands inserted by lyx2lyx for sideways algorithm float',
1194                                  '\\usepackage{rotfloat}\n'
1195                                  '\\floatstyle{ruled}\n'
1196                                  '\\newfloat{algorithm}{tbp}{loa}\n'
1197                                  '\\floatname{algorithm}{Algorithm}\n'])
1198             else:
1199                 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
1200             i = i + 1
1201             continue
1202         i = i + 1
1203
1204
1205 def revert_widesideways(document):
1206     " Revert wide sideways floats. "
1207     i = 0
1208     while 1:
1209         i = find_token(document.body, '\\begin_inset Float', i)
1210         if i == -1:
1211             return
1212         line = document.body[i]
1213         r = re.compile(r'\\begin_inset Float (.*)$')
1214         m = r.match(line)
1215         floattype = m.group(1)
1216         if floattype != "figure" and floattype != "table":
1217             i = i + 1
1218             continue
1219         j = find_end_of_inset(document.body, i)
1220         if j == -1:
1221             document.warning("Malformed lyx document: Missing '\\end_inset'.")
1222             i = i + 1
1223             continue
1224         if get_value(document.body, 'sideways', i, j) != "false":
1225             if get_value(document.body, 'wide', i, j) != "false":
1226                 l = find_token(document.body, "\\begin_layout Standard", i + 1, j)
1227                 if l == -1:
1228                     document.warning("Malformed LyX document: Missing `\\begin_layout Standard' in Float inset.")
1229                     return
1230                 document.body[j] = '\\begin_layout Standard\n\\begin_inset ERT\nstatus collapsed\n\n' \
1231                 '\\begin_layout Standard\n\n\n\\backslash\n' \
1232                 'end{sideways' + floattype + '*}\n\\end_layout\n\n\\end_inset\n'
1233                 del document.body[i+1:l-1]
1234                 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1235                 '\\begin_layout Standard\n\n\n\\backslash\n' \
1236                 'begin{sideways' + floattype + '*}\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n\n'
1237                 add_to_preamble(document,
1238                                 ['\\usepackage{rotfloat}\n'])
1239                 i = i + 1
1240                 continue
1241         i = i + 1
1242
1243
1244 ##
1245 # Conversion hub
1246 #
1247
1248 supported_versions = ["1.6.0","1.6"]
1249 convert = [[277, [fix_wrong_tables]],
1250            [278, [close_begin_deeper]],
1251            [279, [long_charstyle_names]],
1252            [280, [axe_show_label]],
1253            [281, []],
1254            [282, []],
1255            [283, [convert_flex]],
1256            [284, []],
1257            [285, []],
1258            [286, []],
1259            [287, [convert_wrapfig_options]],
1260            [288, [convert_inset_command]],
1261            [289, [convert_latexcommand_index]],
1262            [290, []],
1263            [291, []],
1264            [292, []],
1265            [293, []],
1266            [294, [convert_pdf_options]],
1267            [295, [convert_htmlurl, convert_url]],
1268            [296, [convert_include]],
1269            [297, [convert_usorbian]],
1270            [298, []],
1271            [299, []],
1272            [300, []],
1273            [301, []],
1274            [302, []],
1275            [303, [convert_serbocroatian]],
1276            [304, [convert_framed_notes]],
1277            [305, []],
1278            [306, []],
1279            [307, []],
1280            [308, []],
1281            [309, []],
1282            [310, []],
1283            [311, [convert_ams_classes]],
1284            [312, []],
1285            [313, [convert_module_names]],
1286            [314, []],
1287            [315, []]
1288           ]
1289
1290 revert =  [[314, [revert_colsep]],
1291            [313, []],
1292            [312, [revert_module_names]],
1293            [311, [revert_rotfloat, revert_widesideways]],
1294            [310, []],
1295            [309, [revert_btprintall]],
1296            [308, [revert_nocite]],
1297            [307, [revert_serbianlatin]],
1298            [306, [revert_slash, revert_nobreakdash]],
1299            [305, [revert_interlingua]],
1300            [304, [revert_bahasam]],
1301            [303, [revert_framed_notes]],
1302            [302, []],
1303            [301, [revert_latin, revert_samin]],
1304            [300, [revert_linebreak]],
1305            [299, [revert_pagebreak]],
1306            [298, [revert_hyperlinktype]],
1307            [297, [revert_macro_optional_params]],
1308            [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
1309            [295, [revert_include]],
1310            [294, [revert_href]],
1311            [293, [revert_pdf_options_2]],
1312            [292, [revert_inset_info]],
1313            [291, [revert_japanese, revert_japanese_encoding]],
1314            [290, [revert_vietnamese]],
1315            [289, [revert_wraptable]],
1316            [288, [revert_latexcommand_index]],
1317            [287, [revert_inset_command]],
1318            [286, [revert_wrapfig_options]],
1319            [285, [revert_pdf_options]],
1320            [284, [remove_inzip_options]],
1321            [283, []],
1322            [282, [revert_flex]],
1323            [281, []],
1324            [280, [revert_begin_modules]],
1325            [279, [revert_show_label]],
1326            [278, [revert_long_charstyle_names]],
1327            [277, []],
1328            [276, []]
1329           ]
1330
1331
1332 if __name__ == "__main__":
1333     pass