]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_0.py
* po/*.po: remerge.
[lyx.git] / lib / lyx2lyx / lyx_2_0.py
1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2008 José Matos  <jamatos@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 2.0"""
20
21 import re, string
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
35 def add_to_preamble(document, text):
36     """ Add text to the preamble if it is not already there.
37     Only the first line is checked!"""
38
39     if find_token(document.preamble, text[0], 0) != -1:
40         return
41
42     document.preamble.extend(text)
43
44
45 def insert_to_preamble(index, document, text):
46     """ Insert text to the preamble at a given line"""
47
48     document.preamble.insert(index, text)
49
50
51 def read_unicodesymbols():
52     " Read the unicodesymbols list of unicode characters and corresponding commands."
53     pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
54     fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
55     spec_chars = []
56     # Two backslashes, followed by some non-word character, and then a character
57     # in brackets. The idea is to check for constructs like: \"{u}, which is how
58     # they are written in the unicodesymbols file; but they can also be written
59     # as: \"u or even \" u.
60     r = re.compile(r'\\\\(\W)\{(\w)\}')
61     for line in fp.readlines():
62         if line[0] != '#' and line.strip() != "":
63             line=line.replace(' "',' ') # remove all quotation marks with spaces before
64             line=line.replace('" ',' ') # remove all quotation marks with spaces after
65             line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
66             try:
67                 [ucs4,command,dead] = line.split(None,2)
68                 if command[0:1] != "\\":
69                     continue
70                 spec_chars.append([command, unichr(eval(ucs4))])
71             except:
72                 continue
73             m = r.match(command)
74             if m != None:
75                 command = "\\\\"
76                 # If the character is a double-quote, then we need to escape it, too,
77                 # since it is done that way in the LyX file.
78                 if m.group(1) == "\"":
79                     command += "\\"
80                 commandbl = command
81                 command += m.group(1) + m.group(2)
82                 commandbl += m.group(1) + ' ' + m.group(2)
83                 spec_chars.append([command, unichr(eval(ucs4))])
84                 spec_chars.append([commandbl, unichr(eval(ucs4))])
85     fp.close()
86     return spec_chars
87
88
89 unicode_reps = read_unicodesymbols()
90
91
92 def put_cmd_in_ert(string):
93     for rep in unicode_reps:
94         string = string.replace(rep[1], rep[0].replace('\\\\', '\\'))
95     string = string.replace('\\', "\\backslash\n")
96     string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Plain Layout\n" \
97       + string + "\n\\end_layout\n\\end_inset"
98     return string
99
100
101 def lyx2latex(document, lines):
102     'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
103     # clean up multiline stuff
104     content = ""
105     ert_end = 0
106
107     for curline in range(len(lines)):
108       line = lines[curline]
109       if line.startswith("\\begin_inset ERT"):
110           # We don't want to replace things inside ERT, so figure out
111           # where the end of the inset is.
112           ert_end = find_end_of_inset(lines, curline + 1)
113           continue
114       elif line.startswith("\\begin_inset Formula"):
115           line = line[20:]
116       elif line.startswith("\\begin_inset Quotes"):
117           # For now, we do a very basic reversion. Someone who understands
118           # quotes is welcome to fix it up.
119           qtype = line[20:].strip()
120           # lang = qtype[0]
121           side = qtype[1]
122           dbls = qtype[2]
123           if side == "l":
124               if dbls == "d":
125                   line = "``"
126               else:
127                   line = "`"
128           else:
129               if dbls == "d":
130                   line = "''"
131               else:
132                   line = "'"
133       elif line.isspace() or \
134             line.startswith("\\begin_layout") or \
135             line.startswith("\\end_layout") or \
136             line.startswith("\\begin_inset") or \
137             line.startswith("\\end_inset") or \
138             line.startswith("\\lang") or \
139             line.strip() == "status collapsed" or \
140             line.strip() == "status open":
141           #skip all that stuff
142           continue
143
144       # this needs to be added to the preamble because of cases like
145       # \textmu, \textbackslash, etc.
146       add_to_preamble(document, ['% added by lyx2lyx for converted index entries',
147                                  '\\@ifundefined{textmu}',
148                                  ' {\\usepackage{textcomp}}{}'])
149       # a lossless reversion is not possible
150       # try at least to handle some common insets and settings
151       if ert_end >= curline:
152           line = line.replace(r'\backslash', r'\\')
153       else:
154           line = line.replace('&', '\\&{}')
155           line = line.replace('#', '\\#{}')
156           line = line.replace('^', '\\^{}')
157           line = line.replace('%', '\\%{}')
158           line = line.replace('_', '\\_{}')
159           line = line.replace('$', '\\${}')
160
161           # Do the LyX text --> LaTeX conversion
162           for rep in unicode_reps:
163             line = line.replace(rep[1], rep[0] + "{}")
164           line = line.replace(r'\backslash', r'\textbackslash{}')
165           line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
166           line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
167           line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
168           line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
169           line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
170           line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
171           line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
172           line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
173           line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
174       content += line
175     return content
176
177
178 def latex_length(string):
179     'Convert lengths to their LaTeX representation.'
180     i = 0
181     percent = False
182     i = string.find("text%")
183     if i > -1:
184         percent = True
185         value = string[:i]
186         value = str(float(value)/100)
187         return "True," + value + "\\textwidth"
188     i = string.find("col%")
189     if i > -1:
190         percent = True
191         value = string[:i]
192         value = str(float(value)/100)
193         return "True," + value + "\\columnwidth"
194     i = string.find("page%")
195     if i > -1:
196         percent = True
197         value = string[:i]
198         value = str(float(value)/100)
199         return "True," + value + "\\paperwidth"
200     i = string.find("line%")
201     if i > -1:
202         percent = True
203         value = string[:i]
204         value = str(float(value)/100)
205         return "True," + value + "\\linewidth"
206     i = string.find("theight%")
207     if i > -1:
208         percent = True
209         value = string[:i]
210         value = str(float(value)/100)
211         return "True," + value + "\\textheight"
212     i = string.find("pheight%")
213     if i > -1:
214         percent = True
215         value = string[:i]
216         value = str(float(value)/100)
217         return "True," + value + "\\paperheight"
218     if percent ==  False:
219         return "False," +  string
220
221
222 ####################################################################
223
224
225 def revert_swiss(document):
226     " Set language german-ch to ngerman "
227     i = 0
228     if document.language == "german-ch":
229         document.language = "ngerman"
230         i = find_token(document.header, "\\language", 0)
231         if i != -1:
232             document.header[i] = "\\language ngerman"
233     j = 0
234     while True:
235         j = find_token(document.body, "\\lang german-ch", j)
236         if j == -1:
237             return
238         document.body[j] = document.body[j].replace("\\lang german-ch", "\\lang ngerman")
239         j = j + 1
240
241
242 def revert_tabularvalign(document):
243    " Revert the tabular valign option "
244    i = 0
245    while True:
246        i = find_token(document.body, "\\begin_inset Tabular", i)
247        if i == -1:
248            return
249        j = find_end_of_inset(document.body, i)
250        if j == -1:
251            document.warning("Malformed LyX document: Could not find end of tabular.")
252            i = j
253            continue
254        # don't set a box for longtables, only delete tabularvalignment
255        # the alignment is 2 lines below \\begin_inset Tabular
256        p = document.body[i+2].find("islongtable")
257        if p > -1:
258            q = document.body[i+2].find("tabularvalignment")
259            if q > -1:
260                document.body[i+2] = document.body[i+2][:q-1]
261                document.body[i+2] = document.body[i+2] + '>'
262            i = i + 1
263
264        # when no longtable
265        if p == -1:
266          tabularvalignment = 'c'
267          # which valignment is specified?
268          m = document.body[i+2].find('tabularvalignment="top"')
269          if m > -1:
270              tabularvalignment = 't'
271          m = document.body[i+2].find('tabularvalignment="bottom"')
272          if m > -1:
273              tabularvalignment = 'b'
274          # delete tabularvalignment
275          q = document.body[i+2].find("tabularvalignment")
276          if q > -1:
277              document.body[i+2] = document.body[i+2][:q-1]
278              document.body[i+2] = document.body[i+2] + '>'
279
280          # don't add a box when centered
281          if tabularvalignment == 'c':
282              i = j
283              continue
284          subst = ['\\end_layout', '\\end_inset']
285          document.body[j+1:j+1] = subst # just inserts those lines
286          subst = ['\\begin_inset Box Frameless',
287              'position "' + tabularvalignment +'"',
288              'hor_pos "c"',
289              'has_inner_box 1',
290              'inner_pos "c"',
291              'use_parbox 0',
292              # we don't know the width, assume 50%
293              'width "50col%"',
294              'special "none"',
295              'height "1in"',
296              'height_special "totalheight"',
297              'status open',
298              '',
299              '\\begin_layout Plain Layout']
300          document.body[i:i] = subst # this just inserts the array at i
301          i += len(subst) + 2 # adjust i to save a few cycles
302
303
304 def revert_phantom(document):
305     " Reverts phantom to ERT "
306     i = 0
307     j = 0
308     while True:
309       i = find_token(document.body, "\\begin_inset Phantom Phantom", i)
310       if i == -1:
311           return
312       substi = document.body[i].replace('\\begin_inset Phantom Phantom', \
313                 '\\begin_inset ERT\nstatus collapsed\n\n' \
314                 '\\begin_layout Plain Layout\n\n\n\\backslash\n' \
315                 'phantom{\n\\end_layout\n\n\\end_inset\n')
316       substi = substi.split('\n')
317       document.body[i : i+4] = substi
318       i += len(substi)
319       j = find_token(document.body, "\\end_layout", i)
320       if j == -1:
321           document.warning("Malformed LyX document: Could not find end of Phantom inset.")
322           return
323       substj = document.body[j].replace('\\end_layout', \
324                 '\\size default\n\n\\begin_inset ERT\nstatus collapsed\n\n' \
325                 '\\begin_layout Plain Layout\n\n' \
326                 '}\n\\end_layout\n\n\\end_inset\n')
327       substj = substj.split('\n')
328       document.body[j : j+4] = substj
329       i += len(substj)
330
331
332 def revert_hphantom(document):
333     " Reverts hphantom to ERT "
334     i = 0
335     j = 0
336     while True:
337       i = find_token(document.body, "\\begin_inset Phantom HPhantom", i)
338       if i == -1:
339           return
340       substi = document.body[i].replace('\\begin_inset Phantom HPhantom', \
341                 '\\begin_inset ERT\nstatus collapsed\n\n' \
342                 '\\begin_layout Plain Layout\n\n\n\\backslash\n' \
343                 'hphantom{\n\\end_layout\n\n\\end_inset\n')
344       substi = substi.split('\n')
345       document.body[i : i+4] = substi
346       i += len(substi)
347       j = find_token(document.body, "\\end_layout", i)
348       if j == -1:
349           document.warning("Malformed LyX document: Could not find end of HPhantom inset.")
350           return
351       substj = document.body[j].replace('\\end_layout', \
352                 '\\size default\n\n\\begin_inset ERT\nstatus collapsed\n\n' \
353                 '\\begin_layout Plain Layout\n\n' \
354                 '}\n\\end_layout\n\n\\end_inset\n')
355       substj = substj.split('\n')
356       document.body[j : j+4] = substj
357       i += len(substj)
358
359
360 def revert_vphantom(document):
361     " Reverts vphantom to ERT "
362     i = 0
363     j = 0
364     while True:
365       i = find_token(document.body, "\\begin_inset Phantom VPhantom", i)
366       if i == -1:
367           return
368       substi = document.body[i].replace('\\begin_inset Phantom VPhantom', \
369                 '\\begin_inset ERT\nstatus collapsed\n\n' \
370                 '\\begin_layout Plain Layout\n\n\n\\backslash\n' \
371                 'vphantom{\n\\end_layout\n\n\\end_inset\n')
372       substi = substi.split('\n')
373       document.body[i : i+4] = substi
374       i += len(substi)
375       j = find_token(document.body, "\\end_layout", i)
376       if j == -1:
377           document.warning("Malformed LyX document: Could not find end of VPhantom inset.")
378           return
379       substj = document.body[j].replace('\\end_layout', \
380                 '\\size default\n\n\\begin_inset ERT\nstatus collapsed\n\n' \
381                 '\\begin_layout Plain Layout\n\n' \
382                 '}\n\\end_layout\n\n\\end_inset\n')
383       substj = substj.split('\n')
384       document.body[j : j+4] = substj
385       i += len(substj)
386
387
388 def revert_xetex(document):
389     " Reverts documents that use XeTeX "
390     i = find_token(document.header, '\\use_xetex', 0)
391     if i == -1:
392         document.warning("Malformed LyX document: Missing \\use_xetex.")
393         return
394     if get_value(document.header, "\\use_xetex", i) == 'false':
395         del document.header[i]
396         return
397     del document.header[i]
398     # 1.) set doc encoding to utf8-plain
399     i = find_token(document.header, "\\inputencoding", 0)
400     if i == -1:
401         document.warning("Malformed LyX document: Missing \\inputencoding.")
402     document.header[i] = "\\inputencoding utf8-plain"
403     # 2.) check font settings
404     l = find_token(document.header, "\\font_roman", 0)
405     if l == -1:
406         document.warning("Malformed LyX document: Missing \\font_roman.")
407     line = document.header[l]
408     l = re.compile(r'\\font_roman (.*)$')
409     m = l.match(line)
410     roman = m.group(1)
411     l = find_token(document.header, "\\font_sans", 0)
412     if l == -1:
413         document.warning("Malformed LyX document: Missing \\font_sans.")
414     line = document.header[l]
415     l = re.compile(r'\\font_sans (.*)$')
416     m = l.match(line)
417     sans = m.group(1)
418     l = find_token(document.header, "\\font_typewriter", 0)
419     if l == -1:
420         document.warning("Malformed LyX document: Missing \\font_typewriter.")
421     line = document.header[l]
422     l = re.compile(r'\\font_typewriter (.*)$')
423     m = l.match(line)
424     typewriter = m.group(1)
425     osf = get_value(document.header, '\\font_osf', 0) == "true"
426     sf_scale = float(get_value(document.header, '\\font_sf_scale', 0))
427     tt_scale = float(get_value(document.header, '\\font_tt_scale', 0))
428     # 3.) set preamble stuff
429     pretext = '%% This document must be processed with xelatex!\n'
430     pretext += '\\usepackage{fontspec}\n'
431     if roman != "default":
432         pretext += '\\setmainfont[Mapping=tex-text]{' + roman + '}\n'
433     if sans != "default":
434         pretext += '\\setsansfont['
435         if sf_scale != 100:
436             pretext += 'Scale=' + str(sf_scale / 100) + ','
437         pretext += 'Mapping=tex-text]{' + sans + '}\n'
438     if typewriter != "default":
439         pretext += '\\setmonofont'
440         if tt_scale != 100:
441             pretext += '[Scale=' + str(tt_scale / 100) + ']'
442         pretext += '{' + typewriter + '}\n'
443     if osf:
444         pretext += '\\defaultfontfeatures{Numbers=OldStyle}\n'
445     pretext += '\usepackage{xunicode}\n'
446     pretext += '\usepackage{xltxtra}\n'
447     insert_to_preamble(0, document, pretext)
448     # 4.) reset font settings
449     i = find_token(document.header, "\\font_roman", 0)
450     if i == -1:
451         document.warning("Malformed LyX document: Missing \\font_roman.")
452     document.header[i] = "\\font_roman default"
453     i = find_token(document.header, "\\font_sans", 0)
454     if i == -1:
455         document.warning("Malformed LyX document: Missing \\font_sans.")
456     document.header[i] = "\\font_sans default"
457     i = find_token(document.header, "\\font_typewriter", 0)
458     if i == -1:
459         document.warning("Malformed LyX document: Missing \\font_typewriter.")
460     document.header[i] = "\\font_typewriter default"
461     i = find_token(document.header, "\\font_osf", 0)
462     if i == -1:
463         document.warning("Malformed LyX document: Missing \\font_osf.")
464     document.header[i] = "\\font_osf false"
465     i = find_token(document.header, "\\font_sc", 0)
466     if i == -1:
467         document.warning("Malformed LyX document: Missing \\font_sc.")
468     document.header[i] = "\\font_sc false"
469     i = find_token(document.header, "\\font_sf_scale", 0)
470     if i == -1:
471         document.warning("Malformed LyX document: Missing \\font_sf_scale.")
472     document.header[i] = "\\font_sf_scale 100"
473     i = find_token(document.header, "\\font_tt_scale", 0)
474     if i == -1:
475         document.warning("Malformed LyX document: Missing \\font_tt_scale.")
476     document.header[i] = "\\font_tt_scale 100"
477
478
479 def revert_outputformat(document):
480     " Remove default output format param "
481     i = find_token(document.header, '\\default_output_format', 0)
482     if i == -1:
483         document.warning("Malformed LyX document: Missing \\default_output_format.")
484         return
485     del document.header[i]
486
487
488 def revert_backgroundcolor(document):
489     " Reverts background color to preamble code "
490     i = 0
491     colorcode = ""
492     while True:
493       i = find_token(document.header, "\\backgroundcolor", i)
494       if i == -1:
495           return
496       colorcode = get_value(document.header, '\\backgroundcolor', 0)
497       del document.header[i]
498       # don't clutter the preamble if backgroundcolor is not set
499       if colorcode == "#ffffff":
500           continue
501       # the color code is in the form #rrggbb where every character denotes a hex number
502       # convert the string to an int
503       red = string.atoi(colorcode[1:3],16)
504       # we want the output "0.5" for the value "127" therefore add here
505       if red != 0:
506           red = red + 1
507       redout = float(red) / 256
508       green = string.atoi(colorcode[3:5],16)
509       if green != 0:
510           green = green + 1
511       greenout = float(green) / 256
512       blue = string.atoi(colorcode[5:7],16)
513       if blue != 0:
514           blue = blue + 1
515       blueout = float(blue) / 256
516       # write the preamble
517       insert_to_preamble(0, document,
518                            '% Commands inserted by lyx2lyx to set the background color\n'
519                            + '\\@ifundefined{definecolor}{\\usepackage{color}}{}\n'
520                            + '\\definecolor{page_backgroundcolor}{rgb}{'
521                            + str(redout) + ', ' + str(greenout)
522                            + ', ' + str(blueout) + '}\n'
523                            + '\\pagecolor{page_backgroundcolor}\n')
524
525
526 def revert_splitindex(document):
527     " Reverts splitindex-aware documents "
528     i = find_token(document.header, '\\use_indices', 0)
529     if i == -1:
530         document.warning("Malformed LyX document: Missing \\use_indices.")
531         return
532     indices = get_value(document.header, "\\use_indices", i)
533     preamble = ""
534     if indices == "true":
535          preamble += "\\usepackage{splitidx}\n"
536     del document.header[i]
537     i = 0
538     while True:
539         i = find_token(document.header, "\\index", i)
540         if i == -1:
541             break
542         k = find_token(document.header, "\\end_index", i)
543         if k == -1:
544             document.warning("Malformed LyX document: Missing \\end_index.")
545             return
546         line = document.header[i]
547         l = re.compile(r'\\index (.*)$')
548         m = l.match(line)
549         iname = m.group(1)
550         ishortcut = get_value(document.header, '\\shortcut', i, k)
551         if ishortcut != "" and indices == "true":
552             preamble += "\\newindex[" + iname + "]{" + ishortcut + "}\n"
553         del document.header[i:k+1]
554         i = 0
555     if preamble != "":
556         insert_to_preamble(0, document, preamble)
557     i = 0
558     while True:
559         i = find_token(document.body, "\\begin_inset Index", i)
560         if i == -1:
561             break
562         line = document.body[i]
563         l = re.compile(r'\\begin_inset Index (.*)$')
564         m = l.match(line)
565         itype = m.group(1)
566         if itype == "idx" or indices == "false":
567             document.body[i] = "\\begin_inset Index"
568         else:
569             k = find_end_of_inset(document.body, i)
570             if k == -1:
571                  return
572             content = lyx2latex(document, document.body[i:k])
573             # escape quotes
574             content = content.replace('"', r'\"')
575             subst = [put_cmd_in_ert("\\sindex[" + itype + "]{" + content + "}")]
576             document.body[i:k+1] = subst
577         i = i + 1
578     i = 0
579     while True:
580         i = find_token(document.body, "\\begin_inset CommandInset index_print", i)
581         if i == -1:
582             return
583         k = find_end_of_inset(document.body, i)
584         ptype = get_value(document.body, 'type', i, k).strip('"')
585         if ptype == "idx":
586             j = find_token(document.body, "type", i, k)
587             del document.body[j]
588         elif indices == "false":
589             del document.body[i:k+1]
590         else:
591             subst = [put_cmd_in_ert("\\printindex[" + ptype + "]{}")]
592             document.body[i:k+1] = subst
593         i = i + 1
594
595
596 def convert_splitindex(document):
597     " Converts index and printindex insets to splitindex-aware format "
598     i = 0
599     while True:
600         i = find_token(document.body, "\\begin_inset Index", i)
601         if i == -1:
602             break
603         document.body[i] = document.body[i].replace("\\begin_inset Index",
604             "\\begin_inset Index idx")
605         i = i + 1
606     i = 0
607     while True:
608         i = find_token(document.body, "\\begin_inset CommandInset index_print", i)
609         if i == -1:
610             return
611         if document.body[i + 1].find('LatexCommand printindex') == -1:
612             document.warning("Malformed LyX document: Incomplete printindex inset.")
613             return
614         subst = ["LatexCommand printindex", 
615             "type \"idx\""]
616         document.body[i + 1:i + 2] = subst
617         i = i + 1
618
619
620 def revert_subindex(document):
621     " Reverts \\printsubindex CommandInset types "
622     i = find_token(document.header, '\\use_indices', 0)
623     if i == -1:
624         document.warning("Malformed LyX document: Missing \\use_indices.")
625         return
626     indices = get_value(document.header, "\\use_indices", i)
627     i = 0
628     while True:
629         i = find_token(document.body, "\\begin_inset CommandInset index_print", i)
630         if i == -1:
631             return
632         k = find_end_of_inset(document.body, i)
633         ctype = get_value(document.body, 'LatexCommand', i, k)
634         if ctype != "printsubindex":
635             i = i + 1
636             continue
637         ptype = get_value(document.body, 'type', i, k).strip('"')
638         if indices == "false":
639             del document.body[i:k+1]
640         else:
641             subst = [put_cmd_in_ert("\\printsubindex[" + ptype + "]{}")]
642             document.body[i:k+1] = subst
643         i = i + 1
644
645
646 def revert_printindexall(document):
647     " Reverts \\print[sub]index* CommandInset types "
648     i = find_token(document.header, '\\use_indices', 0)
649     if i == -1:
650         document.warning("Malformed LyX document: Missing \\use_indices.")
651         return
652     indices = get_value(document.header, "\\use_indices", i)
653     i = 0
654     while True:
655         i = find_token(document.body, "\\begin_inset CommandInset index_print", i)
656         if i == -1:
657             return
658         k = find_end_of_inset(document.body, i)
659         ctype = get_value(document.body, 'LatexCommand', i, k)
660         if ctype != "printindex*" and ctype != "printsubindex*":
661             i = i + 1
662             continue
663         if indices == "false":
664             del document.body[i:k+1]
665         else:
666             subst = [put_cmd_in_ert("\\" + ctype + "{}")]
667             document.body[i:k+1] = subst
668         i = i + 1
669
670
671 def revert_strikeout(document):
672     " Reverts \\strikeout character style "
673     while True:
674         i = find_token(document.body, '\\strikeout', 0)
675         if i == -1:
676             return
677         del document.body[i]
678
679
680 def revert_uulinewave(document):
681     " Reverts \\uuline, and \\uwave character styles "
682     while True:
683         i = find_token(document.body, '\\uuline', 0)
684         if i == -1:
685             break
686         del document.body[i]
687     while True:
688         i = find_token(document.body, '\\uwave', 0)
689         if i == -1:
690             return
691         del document.body[i]
692
693
694 def revert_ulinelatex(document):
695     " Reverts \\uline character style "
696     i = find_token(document.body, '\\bar under', 0)
697     if i == -1:
698         return
699     insert_to_preamble(0, document,
700             '% Commands inserted by lyx2lyx for proper underlining\n'
701             + '\\PassOptionsToPackage{normalem}{ulem}\n'
702             + '\\usepackage{ulem}\n'
703             + '\\let\\cite@rig\\cite\n'
704             + '\\newcommand{\\b@xcite}[2][\\%]{\\def\\def@pt{\\%}\\def\\pas@pt{#1}\n'
705             + '  \\mbox{\\ifx\\def@pt\\pas@pt\\cite@rig{#2}\\else\\cite@rig[#1]{#2}\\fi}}\n'
706             + '\\renewcommand{\\underbar}[1]{{\\let\\cite\\b@xcite\\uline{#1}}}\n')
707
708
709 def revert_custom_processors(document):
710     " Remove bibtex_command and index_command params "
711     i = find_token(document.header, '\\bibtex_command', 0)
712     if i == -1:
713         document.warning("Malformed LyX document: Missing \\bibtex_command.")
714         return
715     del document.header[i]
716     i = find_token(document.header, '\\index_command', 0)
717     if i == -1:
718         document.warning("Malformed LyX document: Missing \\index_command.")
719         return
720     del document.header[i]
721
722
723 def convert_nomencl_width(document):
724     " Add set_width param to nomencl_print "
725     i = 0
726     while True:
727       i = find_token(document.body, "\\begin_inset CommandInset nomencl_print", i)
728       if i == -1:
729         break
730       document.body.insert(i + 2, "set_width \"none\"")
731       i = i + 1
732
733
734 def revert_nomencl_width(document):
735     " Remove set_width param from nomencl_print "
736     i = 0
737     while True:
738       i = find_token(document.body, "\\begin_inset CommandInset nomencl_print", i)
739       if i == -1:
740         break
741       j = find_end_of_inset(document.body, i)
742       l = find_token(document.body, "set_width", i, j)
743       if l == -1:
744             document.warning("Can't find set_width option for nomencl_print!")
745             i = j
746             continue
747       del document.body[l]
748       i = i + 1
749
750
751 def revert_nomencl_cwidth(document):
752     " Remove width param from nomencl_print "
753     i = 0
754     while True:
755       i = find_token(document.body, "\\begin_inset CommandInset nomencl_print", i)
756       if i == -1:
757         break
758       j = find_end_of_inset(document.body, i)
759       l = find_token(document.body, "width", i, j)
760       if l == -1:
761             document.warning("Can't find width option for nomencl_print!")
762             i = j
763             continue
764       width = get_value(document.body, "width", i, j).strip('"')
765       del document.body[l]
766       add_to_preamble(document, ["\\setlength{\\nomlabelwidth}{" + width + "}"])
767       i = i + 1
768
769
770 def revert_applemac(document):
771     " Revert applemac encoding to auto "
772     i = 0
773     if document.encoding == "applemac":
774         document.encoding = "auto"
775         i = find_token(document.header, "\\encoding", 0)
776         if i != -1:
777             document.header[i] = "\\encoding auto"
778
779
780 def revert_longtable_align(document):
781     " Remove longtable alignment setting "
782     i = 0
783     j = 0
784     while True:
785       i = find_token(document.body, "\\begin_inset Tabular", i)
786       if i == -1:
787           break
788       # the alignment is 2 lines below \\begin_inset Tabular
789       j = document.body[i+2].find("longtabularalignment")
790       if j == -1:
791           break
792       document.body[i+2] = document.body[i+2][:j-1]
793       document.body[i+2] = document.body[i+2] + '>'
794       i = i + 1
795
796
797 def revert_branch_filename(document):
798     " Remove \\filename_suffix parameter from branches "
799     i = 0
800     while True:
801         i = find_token(document.header, "\\filename_suffix", i)
802         if i == -1:
803             return
804         del document.header[i]
805
806
807 def revert_paragraph_indentation(document):
808     " Revert custom paragraph indentation to preamble code "
809     i = 0
810     while True:
811       i = find_token(document.header, "\\paragraph_indentation", i)
812       if i == -1:
813           break
814       # only remove the preamble line when default
815       # otherwise also write the value to the preamble  
816       j = document.header[i].find("default")
817       if j > -1:
818           del document.header[i]
819           break
820       else:
821           # search for the beginning of the value via the space
822           j = document.header[i].find(" ")
823           length = document.header[i][j+1:]
824           # handle percent lengths
825           length = latex_length(length)
826           # latex_length returns "bool,length"
827           k = length.find(",")
828           length = length[k+1:]
829           add_to_preamble(document, ["% this command was inserted by lyx2lyx"])
830           add_to_preamble(document, ["\\setlength{\\parindent}{" + length + "}"])
831           del document.header[i]
832       i = i + 1
833
834
835 def revert_percent_skip_lengths(document):
836     " Revert relative lengths for paragraph skip separation to preamble code "
837     i = 0
838     while True:
839       i = find_token(document.header, "\\defskip", i)
840       if i == -1:
841           break
842       # only revert when a custom length was set and when
843       # it used a percent length
844       j = document.header[i].find("smallskip")
845       k = document.header[i].find("medskip")
846       l = document.header[i].find("bigskip")
847       if (j > -1) or (k > -1) or (l > -1):
848           break
849       else:
850           # search for the beginning of the value via the space
851           j = document.header[i].find(" ")
852           length = document.header[i][j+1:]
853           # handle percent lengths
854           length = latex_length(length)
855           # latex_length returns "bool,length"
856           l = length.find(",")
857           percent = length[:l]
858           length = length[l+1:]
859           if percent == "True":
860               add_to_preamble(document, ["% this command was inserted by lyx2lyx"])
861               add_to_preamble(document, ["\\setlength{\\parskip}{" + length + "}"])
862               # set defskip to medskip as default
863               document.header[i] = "\\defskip medskip"
864       i = i + 1
865
866
867 def revert_percent_vspace_lengths(document):
868     " Revert relative VSpace lengths to ERT "
869     i = 0
870     while True:
871       i = find_token(document.body, "\\begin_inset VSpace", i)
872       if i == -1:
873           break
874       # only revert when a custom length was set and when
875       # it used a percent length
876       j = document.body[i].find("defskip")
877       k = document.body[i].find("smallskip")
878       l = document.body[i].find("medskip")
879       m = document.body[i].find("bigskip")
880       n = document.body[i].find("vfill")
881       if (j > -1) or (k > -1) or (l > -1) or (m > -1) or (n > -1):
882           break
883       else:
884           # search for the beginning of the value via the last space
885           o = document.body[i].rfind(" ")
886           length = document.body[i][o+1:]
887           # check if the space has a star (protected space)
888           p = document.body[i].rfind("*")
889           if p > -1:
890               length = length[:-1]
891           # handle percent lengths
892           length = latex_length(length)
893           # latex_length returns "bool,length"
894           q = length.find(",")
895           percent = length[:q]
896           length = length[q+1:]
897           # revert the VSpace inset to ERT
898           if percent == "True":
899               if p > -1:
900                   subst = [put_cmd_in_ert("\\vspace*{" + length + "}")]
901               else:
902                   subst = [put_cmd_in_ert("\\vspace{" + length + "}")]
903               document.body[i:i+2] = subst
904       i = i + 1
905
906
907 def revert_percent_hspace_lengths(document):
908     " Revert relative HSpace lengths to ERT "
909     i = 0
910     j = 0
911     while True:
912       i = find_token(document.body, "\\begin_inset space \hspace{}", i)
913       if i == -1:
914           j = find_token(document.body, "\\begin_inset space \hspace*{}", j)
915           if j == -1:
916               break
917           else:
918               star = True
919               i = j
920       else:
921           star = False
922       # only revert when a custom length was set and when
923       # it used a percent length
924       o = document.body[i+1].find("\\length")
925       if o == -1:
926           document.warning("Error: Cannot find lenght for \\hspace!")
927           break
928       # search for the beginning of the value via the space
929       k = document.body[i+1].find(" ")
930       length = document.body[i+1][k+1:]
931       # handle percent lengths
932       length = latex_length(length)
933       # latex_length returns "bool,length"
934       m = length.find(",")
935       percent = length[:m]
936       length = length[m+1:]
937       # revert the HSpace inset to ERT
938       if percent == "True":
939           if star == True:
940               subst = [put_cmd_in_ert("\\hspace*{" + length + "}")]
941           else:
942               subst = [put_cmd_in_ert("\\hspace{" + length + "}")]
943           document.body[i:i+3] = subst
944       i = i + 2
945       j = i
946
947
948 ##
949 # Conversion hub
950 #
951
952 supported_versions = ["2.0.0","2.0"]
953 convert = [[346, []],
954            [347, []],
955            [348, []],
956            [349, []],
957            [350, []],
958            [351, []],
959            [352, [convert_splitindex]],
960            [353, []],
961            [354, []],
962            [355, []],
963            [356, []],
964            [357, []],
965            [358, []],
966            [359, [convert_nomencl_width]],
967            [360, []],
968            [361, []],
969            [362, []],
970            [363, []],
971            [364, []],
972            [365, []],
973            [366, []],
974            [367, []]
975           ]
976
977 revert =  [[366, [revert_percent_vspace_lengths, revert_percent_hspace_lengths]],
978            [365, [revert_percent_skip_lengths]],
979            [364, [revert_paragraph_indentation]],
980            [363, [revert_branch_filename]],
981            [362, [revert_longtable_align]],
982            [361, [revert_applemac]],
983            [360, []],
984            [359, [revert_nomencl_cwidth]],
985            [358, [revert_nomencl_width]],
986            [357, [revert_custom_processors]],
987            [356, [revert_ulinelatex]],
988            [355, [revert_uulinewave]],
989            [354, [revert_strikeout]],
990            [353, [revert_printindexall]],
991            [352, [revert_subindex]],
992            [351, [revert_splitindex]],
993            [350, [revert_backgroundcolor]],
994            [349, [revert_outputformat]],
995            [348, [revert_xetex]],
996            [347, [revert_phantom, revert_hphantom, revert_vphantom]],
997            [346, [revert_tabularvalign]],
998            [345, [revert_swiss]]
999           ]
1000
1001
1002 if __name__ == "__main__":
1003     pass