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