1 # This file is part of lyx2lyx
2 # -*- coding: iso-8859-1 -*-
3 # Copyright (C) 2002 Dekel Tsur <dekel@lyx.org>
4 # Copyright (C) 2002-2004 José Matos <jamatos@lyx.org>
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 from os import access, F_OK
23 from parser_tools import find_token, find_end_of_inset, get_next_paragraph, \
24 get_paragraph, get_value, del_token, is_nonempty_line,\
25 find_tokens, find_end_of, find_token2
27 from string import replace, split, find, strip, join
29 from lyx_0_12 import update_latexaccents
32 # Remove \color default
34 def remove_color_default(file):
37 i = find_token(file.body, "\\color default", i)
40 file.body[i] = replace(file.body[i], "\\color default",
47 def add_end_header(file):
48 file.header.append("\\end_header");
51 def rm_end_header(file):
52 i = find_token(file.header, "\\end_header", 0)
59 # \SpecialChar ~ -> \InsetSpace ~
61 def convert_spaces(file):
62 for i in range(len(file.body)):
63 file.body[i] = replace(file.body[i],"\\SpecialChar ~","\\InsetSpace ~")
66 def revert_spaces(file):
67 for i in range(len(file.body)):
68 file.body[i] = replace(file.body[i],"\\InsetSpace ~", "\\SpecialChar ~")
74 def convert_bibtex(file):
75 for i in range(len(file.body)):
76 file.body[i] = replace(file.body[i],"\\begin_inset LatexCommand \\BibTeX",
77 "\\begin_inset LatexCommand \\bibtex")
80 def revert_bibtex(file):
81 for i in range(len(file.body)):
82 file.body[i] = replace(file.body[i], "\\begin_inset LatexCommand \\bibtex",
83 "\\begin_inset LatexCommand \\BibTeX")
89 def remove_insetparent(file):
92 i = find_token(file.body, "\\begin_inset LatexCommand \\lyxparent", i)
101 def convert_external(file):
102 external_rexp = re.compile(r'\\begin_inset External ([^,]*),"([^"]*)",')
103 external_header = "\\begin_inset External"
106 i = find_token(file.body, external_header, i)
109 look = external_rexp.search(file.body[i])
112 args[0] = look.group(1)
113 args[1] = look.group(2)
114 #FIXME: if the previous search fails then warn
116 if args[0] == "RasterImage":
117 # Convert a RasterImage External Inset to a Graphics Inset.
118 top = "\\begin_inset Graphics"
120 filename = "\tfilename " + args[1]
121 file.body[i:i+1] = [top, filename]
124 # Convert the old External Inset format to the new.
125 top = external_header
126 template = "\ttemplate " + args[0]
128 filename = "\tfilename " + args[1]
129 file.body[i:i+1] = [top, template, filename]
132 file.body[i:i+1] = [top, template]
136 def revert_external_1(file):
137 external_header = "\\begin_inset External"
140 i = find_token(file.body, external_header, i)
144 template = split(file.body[i+1])
148 filename = split(file.body[i+1])
152 params = split(file.body[i+1])
154 if file.body[i+1]: del file.body[i+1]
156 file.body[i] = file.body[i] + " " + template[0]+ ', "' + filename[0] + '", " '+ join(params[1:]) + '"'
160 def revert_external_2(file):
161 draft_token = '\tdraft'
164 i = find_token(file.body, '\\begin_inset External', i)
167 j = find_end_of_inset(file.body, i + 1)
169 #this should not happen
171 k = find_token(file.body, draft_token, i+1, j-1)
172 if (k != -1 and len(draft_token) == len(file.body[k])):
180 def convert_comment(file):
182 comment = "\\layout Comment"
184 i = find_token(file.body, comment, i)
188 file.body[i:i+1] = ["\\layout Standard","","",
189 "\\begin_inset Comment",
196 i = find_token(file.body, "\\layout", i)
198 i = len(file.body) - 1
199 file.body[i:i] = ["\\end_inset","",""]
202 j = find_token(file.body, '\\begin_deeper', old_i, i)
203 if j == -1: j = i + 1
204 k = find_token(file.body, '\\begin_inset', old_i, i)
205 if k == -1: k = i + 1
210 i = find_end_of( file.body, i, "\\begin_deeper","\\end_deeper")
212 #This case should not happen
213 #but if this happens deal with it greacefully adding
214 #the missing \end_deeper.
215 i = len(file.body) - 1
216 file.body[i:i] = ["\end_deeper",""]
224 i = find_end_of( file.body, i, "\\begin_inset","\\end_inset")
226 #This case should not happen
227 #but if this happens deal with it greacefully adding
228 #the missing \end_inset.
229 i = len(file.body) - 1
230 file.body[i:i] = ["\\end_inset","","","\\end_inset","",""]
236 if find(file.body[i], comment) == -1:
237 file.body[i:i] = ["\\end_inset"]
240 file.body[i:i+1] = ["\\layout Standard"]
244 def revert_comment(file):
247 i = find_tokens(file.body, ["\\begin_inset Comment", "\\begin_inset Greyedout"], i)
251 file.body[i] = "\\begin_inset Note"
258 def add_end_layout(file):
259 i = find_token(file.body, '\\layout', 0)
265 struct_stack = ["\\layout"]
268 i = find_tokens(file.body, ["\\begin_inset", "\\end_inset", "\\layout",
269 "\\begin_deeper", "\\end_deeper", "\\the_end"], i)
271 token = split(file.body[i])[0]
273 if token == "\\begin_inset":
274 struct_stack.append(token)
278 if token == "\\end_inset":
279 tail = struct_stack.pop()
280 if tail == "\\layout":
281 file.body.insert(i,"")
282 file.body.insert(i,"\\end_layout")
284 #Check if it is the correct tag
289 if token == "\\layout":
290 tail = struct_stack.pop()
292 file.body.insert(i,"")
293 file.body.insert(i,"\\end_layout")
296 struct_stack.append(tail)
298 struct_stack.append(token)
301 if token == "\\begin_deeper":
302 file.body.insert(i,"")
303 file.body.insert(i,"\\end_layout")
305 struct_stack.append(token)
308 if token == "\\end_deeper":
309 if struct_stack[-1] == '\\layout':
310 file.body.insert(i, '\\end_layout')
317 file.body.insert(i, "")
318 file.body.insert(i, "\\end_layout")
322 def rm_end_layout(file):
325 i = find_token(file.body, '\\end_layout', i)
334 # Handle change tracking keywords
336 def insert_tracking_changes(file):
337 i = find_token(file.header, "\\tracking_changes", 0)
339 file.header.append("\\tracking_changes 0")
342 def rm_tracking_changes(file):
343 i = find_token(file.header, "\\author", 0)
347 i = find_token(file.header, "\\tracking_changes", 0)
353 def rm_body_changes(file):
356 i = find_token(file.body, "\\change_", i)
364 # \layout -> \begin_layout
366 def layout2begin_layout(file):
369 i = find_token(file.body, '\\layout', i)
373 file.body[i] = replace(file.body[i], '\\layout', '\\begin_layout')
377 def begin_layout2layout(file):
380 i = find_token(file.body, '\\begin_layout', i)
384 file.body[i] = replace(file.body[i], '\\begin_layout', '\\layout')
389 # valignment="center" -> valignment="middle"
391 def convert_valignment_middle(body, start, end):
392 for i in range(start, end):
393 if re.search('^<(column|cell) .*valignment="center".*>$', body[i]):
394 body[i] = replace(body[i], 'valignment="center"', 'valignment="middle"')
397 def convert_table_valignment_middle(file):
400 i = find_token(file.body, '\\begin_inset Tabular', i)
403 j = find_end_of_inset(file.body, i + 1)
405 #this should not happen
406 convert_valignment_middle(file.body, i + 1, len(file.body))
408 convert_valignment_middle(file.body, i + 1, j)
412 def revert_table_valignment_middle(body, start, end):
413 for i in range(start, end):
414 if re.search('^<(column|cell) .*valignment="middle".*>$', body[i]):
415 body[i] = replace(body[i], 'valignment="middle"', 'valignment="center"')
418 def revert_valignment_middle(file):
421 i = find_token(file.body, '\\begin_inset Tabular', i)
424 j = find_end_of_inset(file.body, i + 1)
426 #this should not happen
427 revert_table_valignment_middle(file.body, i + 1, len(file.body))
429 revert_table_valignment_middle(file.body, i + 1, j)
434 # \the_end -> \end_document
436 def convert_end_document(file):
437 i = find_token(file.body, "\\the_end", 0)
439 file.body.append("\\end_document")
441 file.body[i] = "\\end_document"
444 def revert_end_document(file):
445 i = find_token(file.body, "\\end_document", 0)
447 file.body.append("\\the_end")
449 file.body[i] = "\\the_end"
453 # Convert line and page breaks
456 #\line_top \line_bottom \pagebreak_top \pagebreak_bottom \added_space_top xxx \added_space_bottom yyy
460 #\begin layout Standard
465 #\begin_inset VSpace xxx
469 #\begin_layout Standard
473 #\begin_layout Standard
475 #\begin_inset VSpace xxx
482 def convert_breaks(file):
485 i = find_token(file.body, "\\begin_layout", i)
489 line_top = find(file.body[i],"\\line_top")
490 line_bot = find(file.body[i],"\\line_bottom")
491 pb_top = find(file.body[i],"\\pagebreak_top")
492 pb_bot = find(file.body[i],"\\pagebreak_bottom")
493 vspace_top = find(file.body[i],"\\added_space_top")
494 vspace_bot = find(file.body[i],"\\added_space_bottom")
496 if line_top == -1 and line_bot == -1 and pb_bot == -1 and pb_top == -1 and vspace_top == -1 and vspace_bot == -1:
499 for tag in "\\line_top", "\\line_bottom", "\\pagebreak_top", "\\pagebreak_bottom":
500 file.body[i] = replace(file.body[i], tag, "")
503 # the position could be change because of the removal of other
504 # paragraph properties above
505 vspace_top = find(file.body[i],"\\added_space_top")
506 tmp_list = split(file.body[i][vspace_top:])
507 vspace_top_value = tmp_list[1]
508 file.body[i] = file.body[i][:vspace_top] + join(tmp_list[2:])
511 # the position could be change because of the removal of other
512 # paragraph properties above
513 vspace_bot = find(file.body[i],"\\added_space_bottom")
514 tmp_list = split(file.body[i][vspace_bot:])
515 vspace_bot_value = tmp_list[1]
516 file.body[i] = file.body[i][:vspace_bot] + join(tmp_list[2:])
518 file.body[i] = strip(file.body[i])
521 # Create an empty paragraph for line and page break that belong
522 # above the paragraph
523 if pb_top !=-1 or line_top != -1 or vspace_bot != -1:
525 paragraph_above = ['','\\begin_layout Standard','','']
528 paragraph_above.extend(['\\newpage ',''])
531 paragraph_above.extend(['\\begin_inset VSpace ' + vspace_top_value,'\\end_inset','',''])
534 paragraph_above.extend(['\\lyxline ',''])
536 paragraph_above.extend(['\\end_layout',''])
538 #inset new paragraph above the current paragraph
539 file.body[i-2:i-2] = paragraph_above
540 i = i + len(paragraph_above)
542 # Ensure that nested style are converted later.
543 k = find_end_of(file.body, i, "\\begin_layout", "\\end_layout")
548 if pb_top !=-1 or line_top != -1 or vspace_bot != -1:
550 paragraph_bellow = ['','\\begin_layout Standard','','']
553 paragraph_bellow.extend(['\\lyxline ',''])
556 paragraph_bellow.extend(['\\begin_inset VSpace ' + vspace_bot_value,'\\end_inset','',''])
559 paragraph_bellow.extend(['\\newpage ',''])
561 paragraph_bellow.extend(['\\end_layout',''])
563 #inset new paragraph above the current paragraph
564 file.body[k + 1: k + 1] = paragraph_bellow
570 def convert_note(file):
573 i = find_tokens(file.body, ["\\begin_inset Note",
574 "\\begin_inset Comment",
575 "\\begin_inset Greyedout"], i)
579 file.body[i] = file.body[i][0:13] + 'Note ' + file.body[i][13:]
583 def revert_note(file):
584 note_header = "\\begin_inset Note "
587 i = find_token(file.body, note_header, i)
591 file.body[i] = "\\begin_inset " + file.body[i][len(note_header):]
598 def convert_box(file):
601 i = find_tokens(file.body, ["\\begin_inset Boxed",
602 "\\begin_inset Doublebox",
603 "\\begin_inset Frameless",
604 "\\begin_inset ovalbox",
605 "\\begin_inset Ovalbox",
606 "\\begin_inset Shadowbox"], i)
610 file.body[i] = file.body[i][0:13] + 'Box ' + file.body[i][13:]
614 def revert_box(file):
615 box_header = "\\begin_inset Box "
618 i = find_token(file.body, box_header, i)
622 file.body[i] = "\\begin_inset " + file.body[i][len(box_header):]
629 def convert_collapsable(file):
632 i = find_tokens(file.body, ["\\begin_inset Box",
633 "\\begin_inset Branch",
634 "\\begin_inset CharStyle",
635 "\\begin_inset Float",
636 "\\begin_inset Foot",
637 "\\begin_inset Marginal",
638 "\\begin_inset Note",
639 "\\begin_inset OptArg",
640 "\\begin_inset Wrap"], i)
644 # Seach for a line starting 'collapsed'
645 # If, however, we find a line starting '\begin_layout'
646 # (_always_ present) then break with a warning message
649 if (file.body[i] == "collapsed false"):
650 file.body[i] = "status open"
652 elif (file.body[i] == "collapsed true"):
653 file.body[i] = "status collapsed"
655 elif (file.body[i][:13] == "\\begin_layout"):
656 file.warning("Malformed LyX file.")
663 def revert_collapsable(file):
666 i = find_tokens(file.body, ["\\begin_inset Box",
667 "\\begin_inset Branch",
668 "\\begin_inset CharStyle",
669 "\\begin_inset Float",
670 "\\begin_inset Foot",
671 "\\begin_inset Marginal",
672 "\\begin_inset Note",
673 "\\begin_inset OptArg",
674 "\\begin_inset Wrap"], i)
678 # Seach for a line starting 'status'
679 # If, however, we find a line starting '\begin_layout'
680 # (_always_ present) then break with a warning message
683 if (file.body[i] == "status open"):
684 file.body[i] = "collapsed false"
686 elif (file.body[i] == "status collapsed" or
687 file.body[i] == "status inlined"):
688 file.body[i] = "collapsed true"
690 elif (file.body[i][:13] == "\\begin_layout"):
691 file.warning("Malformed LyX file.")
701 def convert_ert(file):
704 i = find_token(file.body, "\\begin_inset ERT", i)
708 # Seach for a line starting 'status'
709 # If, however, we find a line starting '\begin_layout'
710 # (_always_ present) then break with a warning message
713 if (file.body[i] == "status Open"):
714 file.body[i] = "status open"
716 elif (file.body[i] == "status Collapsed"):
717 file.body[i] = "status collapsed"
719 elif (file.body[i] == "status Inlined"):
720 file.body[i] = "status inlined"
722 elif (file.body[i][:13] == "\\begin_layout"):
723 file.warning("Malformed LyX file.")
730 def revert_ert(file):
733 i = find_token(file.body, "\\begin_inset ERT", i)
737 # Seach for a line starting 'status'
738 # If, however, we find a line starting '\begin_layout'
739 # (_always_ present) then break with a warning message
742 if (file.body[i] == "status open"):
743 file.body[i] = "status Open"
745 elif (file.body[i] == "status collapsed"):
746 file.body[i] = "status Collapsed"
748 elif (file.body[i] == "status inlined"):
749 file.body[i] = "status Inlined"
751 elif (file.body[i][:13] == "\\begin_layout"):
752 file.warning("Malformed LyX file.")
762 def convert_minipage(file):
763 """ Convert minipages to the box inset.
764 We try to use the same order of arguments as lyx does.
767 inner_pos = ["c","t","b","s"]
771 i = find_token(file.body, "\\begin_inset Minipage", i)
775 file.body[i] = "\\begin_inset Box Frameless"
778 # convert old to new position using the pos list
779 if file.body[i][:8] == "position":
780 file.body[i] = 'position "%s"' % pos[int(file.body[i][9])]
782 file.body.insert(i, 'position "%s"' % pos[0])
785 file.body.insert(i, 'hor_pos "c"')
787 file.body.insert(i, 'has_inner_box 1')
790 # convert the inner_position
791 if file.body[i][:14] == "inner_position":
792 file.body[i] = 'inner_pos "%s"' % inner_pos[int(file.body[i][15])]
794 file.body.insert('inner_pos "%s"' % inner_pos[0])
797 # We need this since the new file format has a height and width
798 # in a different order.
799 if file.body[i][:6] == "height":
800 height = file.body[i][6:]
801 # test for default value of 221 and convert it accordingly
802 if height == ' "0pt"':
808 if file.body[i][:5] == "width":
809 width = file.body[i][5:]
814 if file.body[i][:9] == "collapsed":
815 if file.body[i][9:] == "true":
823 file.body.insert(i, 'use_parbox 0')
825 file.body.insert(i, 'width' + width)
827 file.body.insert(i, 'special "none"')
829 file.body.insert(i, 'height' + height)
831 file.body.insert(i, 'height_special "totalheight"')
833 file.body.insert(i, 'status ' + status)
837 # -------------------------------------------------------------------------------------------
838 # Convert backslashes into valid ERT code, append the converted text to
839 # file.body[i] and return the (maybe incremented) line index i
840 def convert_ertbackslash(body, i, ert):
843 body[i] = body[i] + '\\backslash '
847 body[i] = body[i] + c
851 def convert_vspace(file):
853 # Get default spaceamount
854 i = find_token(file.header, '\\defskip', 0)
856 defskipamount = 'medskip'
858 defskipamount = split(file.header[i])[1]
863 i = find_token(file.body, '\\begin_inset VSpace', i)
866 spaceamount = split(file.body[i])[2]
868 # Are we at the beginning or end of a paragraph?
870 start = get_paragraph(file.body, i) + 1
871 for k in range(start, i):
872 if is_nonempty_line(file.body[k]):
876 j = find_end_of_inset(file.body, i)
878 file.warning("Malformed LyX file: Missing '\\end_inset'.")
881 end = get_next_paragraph(file.body, i)
882 for k in range(j + 1, end):
883 if is_nonempty_line(file.body[k]):
887 # Convert to paragraph formatting if we are at the beginning or end
888 # of a paragraph and the resulting paragraph would not be empty
889 if ((paragraph_start and not paragraph_end) or
890 (paragraph_end and not paragraph_start)):
891 # The order is important: del and insert invalidate some indices
895 file.body.insert(start, '\\added_space_top ' + spaceamount + ' ')
897 file.body.insert(start, '\\added_space_bottom ' + spaceamount + ' ')
901 file.body[i:i+1] = ['\\begin_inset ERT', 'status Collapsed', '',
902 '\\layout Standard', '', '\\backslash ']
904 if spaceamount[-1] == '*':
905 spaceamount = spaceamount[:-1]
910 # Replace defskip by the actual value
911 if spaceamount == 'defskip':
912 spaceamount = defskipamount
914 # LaTeX does not know \\smallskip* etc
916 if spaceamount == 'smallskip':
917 spaceamount = '\\smallskipamount'
918 elif spaceamount == 'medskip':
919 spaceamount = '\\medskipamount'
920 elif spaceamount == 'bigskip':
921 spaceamount = '\\bigskipamount'
922 elif spaceamount == 'vfill':
923 spaceamount = '\\fill'
925 # Finally output the LaTeX code
926 if (spaceamount == 'smallskip' or spaceamount == 'medskip' or
927 spaceamount == 'bigskip' or spaceamount == 'vfill'):
928 file.body.insert(i, spaceamount)
931 file.body.insert(i, 'vspace*{')
933 file.body.insert(i, 'vspace{')
934 i = convert_ertbackslash(file.body, i, spaceamount)
935 file.body[i] = file.body[i] + '}'
939 # Convert a LyX length into valid ERT code and append it to body[i]
940 # Return the (maybe incremented) line index i
941 def convert_ertlen(body, i, len, special):
942 units = {"text%":"\\textwidth", "col%":"\\columnwidth",
943 "page%":"\\pagewidth", "line%":"\\linewidth",
944 "theight%":"\\textheight", "pheight%":"\\pageheight"}
946 # Convert special lengths
947 if special != 'none':
948 len = '%f\\' % len2value(len) + special
950 # Convert LyX units to LaTeX units
951 for unit in units.keys():
952 if find(len, unit) != -1:
953 len = '%f' % (len2value(len) / 100) + units[unit]
956 # Convert backslashes and insert the converted length into body
957 return convert_ertbackslash(body, i, len)
960 # Return the value of len without the unit in numerical form
962 result = re.search('([+-]?[0-9.]+)', len)
964 return float(result.group(1))
965 # No number means 1.0
969 def convert_frameless_box(file):
970 pos = ['t', 'c', 'b']
971 inner_pos = ['c', 't', 'b', 's']
974 i = find_token(file.body, '\\begin_inset Frameless', i)
977 j = find_end_of_inset(file.body, i)
979 file.warning("Malformed LyX file: Missing '\\end_inset'.")
985 params = {'position':'0', 'hor_pos':'c', 'has_inner_box':'1',
986 'inner_pos':'1', 'use_parbox':'0', 'width':'100col%',
987 'special':'none', 'height':'1in',
988 'height_special':'totalheight', 'collapsed':'false'}
989 for key in params.keys():
990 value = replace(get_value(file.body, key, i, j), '"', '')
992 if key == 'position':
993 # convert new to old position: 'position "t"' -> 0
994 value = find_token(pos, value, 0)
997 elif key == 'inner_pos':
998 # convert inner position
999 value = find_token(inner_pos, value, 0)
1004 j = del_token(file.body, key, i, j)
1007 # Convert to minipage or ERT?
1008 # Note that the inner_position and height parameters of a minipage
1009 # inset are ignored and not accessible for the user, although they
1010 # are present in the file format and correctly read in and written.
1011 # Therefore we convert to ERT if they do not have their LaTeX
1012 # defaults. These are:
1013 # - the value of "position" for "inner_pos"
1014 # - "\totalheight" for "height"
1015 if (params['use_parbox'] != '0' or
1016 params['has_inner_box'] != '1' or
1017 params['special'] != 'none' or
1018 inner_pos[params['inner_pos']] != pos[params['position']] or
1019 params['height_special'] != 'totalheight' or
1020 len2value(params['height']) != 1.0):
1023 if params['collapsed'] == 'true':
1024 params['collapsed'] = 'Collapsed'
1026 params['collapsed'] = 'Open'
1027 file.body[i : i] = ['\\begin_inset ERT', 'status ' + params['collapsed'],
1028 '', '\\layout Standard', '', '\\backslash ']
1030 if params['use_parbox'] == '1':
1031 file.body.insert(i, 'parbox')
1033 file.body.insert(i, 'begin{minipage}')
1034 file.body[i] = file.body[i] + '[' + pos[params['position']] + ']['
1035 i = convert_ertlen(file.body, i, params['height'], params['height_special'])
1036 file.body[i] = file.body[i] + '][' + inner_pos[params['inner_pos']] + ']{'
1037 i = convert_ertlen(file.body, i, params['width'], params['special'])
1038 if params['use_parbox'] == '1':
1039 file.body[i] = file.body[i] + '}{'
1041 file.body[i] = file.body[i] + '}'
1043 file.body[i:i] = ['', '\\end_inset']
1045 j = find_end_of_inset(file.body, i)
1047 file.warning("Malformed LyX file: Missing '\\end_inset'.")
1049 file.body[j-1:j-1] = ['\\begin_inset ERT', 'status ' + params['collapsed'],
1050 '', '\\layout Standard', '']
1052 if params['use_parbox'] == '1':
1053 file.body.insert(j, '}')
1055 file.body[j:j] = ['\\backslash ', 'end{minipage}']
1058 # Convert to minipage
1059 file.body[i:i] = ['\\begin_inset Minipage',
1060 'position %d' % params['position'],
1061 'inner_position %d' % params['inner_pos'],
1062 'height "' + params['height'] + '"',
1063 'width "' + params['width'] + '"',
1064 'collapsed ' + params['collapsed']]
1071 def convert_jurabib(file):
1072 i = find_token(file.header, '\\use_numerical_citations', 0)
1074 file.warning("Malformed lyx file: Missing '\\use_numerical_citations'.")
1076 file.header.insert(i + 1, '\\use_jurabib 0')
1079 def revert_jurabib(file):
1080 i = find_token(file.header, '\\use_jurabib', 0)
1082 file.warning("Malformed lyx file: Missing '\\use_jurabib'.")
1084 if get_value(file.header, '\\use_jurabib', 0) != "0":
1085 file.warning("Conversion of '\\use_jurabib = 1' not yet implemented.")
1086 # Don't remove '\\use_jurabib' so that people will get warnings by lyx
1094 def convert_bibtopic(file):
1095 i = find_token(file.header, '\\use_jurabib', 0)
1097 file.warning("Malformed lyx file: Missing '\\use_jurabib'.")
1099 file.header.insert(i + 1, '\\use_bibtopic 0')
1102 def revert_bibtopic(file):
1103 i = find_token(file.header, '\\use_bibtopic', 0)
1105 file.warning("Malformed lyx file: Missing '\\use_bibtopic'.")
1107 if get_value(file.header, '\\use_bibtopic', 0) != "0":
1108 file.warning("Conversion of '\\use_bibtopic = 1' not yet implemented.")
1109 # Don't remove '\\use_jurabib' so that people will get warnings by lyx
1116 def convert_float(file):
1119 i = find_token(file.body, '\\begin_inset Float', i)
1122 # Seach for a line starting 'wide'
1123 # If, however, we find a line starting '\begin_layout'
1124 # (_always_ present) then break with a warning message
1127 if (file.body[i][:4] == "wide"):
1128 file.body.insert(i + 1, 'sideways false')
1130 elif (file.body[i][:13] == "\\begin_layout"):
1131 file.warning("Malformed lyx file.")
1137 def revert_float(file):
1140 i = find_token(file.body, '\\begin_inset Float', i)
1143 j = find_end_of_inset(file.body, i)
1145 file.warning("Malformed lyx file: Missing '\\end_inset'.")
1148 if get_value(file.body, 'sideways', i, j) != "false":
1149 file.warning("Conversion of 'sideways true' not yet implemented.")
1150 # Don't remove 'sideways' so that people will get warnings by lyx
1153 del_token(file.body, 'sideways', i, j)
1157 def convert_graphics(file):
1158 """ Add extension to filenames of insetgraphics if necessary.
1162 i = find_token(file.body, "\\begin_inset Graphics", i)
1166 j = find_token2(file.body, "filename", i)
1170 filename = split(file.body[j])[1]
1171 absname = os.path.normpath(os.path.join(file.dir, filename))
1172 if file.input == stdin and not os.path.isabs(filename):
1173 # We don't know the directory and cannot check the file.
1174 # We could use a heuristic and take the current directory,
1175 # and we could try to find out if filename has an extension,
1176 # but that would be just guesses and could be wrong.
1177 file.warning("""Warning: Can not determine whether file
1179 needs an extension when reading from standard input.
1180 You may need to correct the file manually or run
1181 lyx2lyx again with the .lyx file as commandline argument.""" % filename)
1183 # This needs to be the same algorithm as in pre 233 insetgraphics
1184 if access(absname, F_OK):
1186 if access(absname + ".ps", F_OK):
1187 file.body[j] = replace(file.body[j], filename, filename + ".ps")
1189 if access(absname + ".eps", F_OK):
1190 file.body[j] = replace(file.body[j], filename, filename + ".eps")
1194 # Convert firstname and surname from styles -> char styles
1196 def convert_names(file):
1197 """ Convert in the docbook backend from firstname and surname style
1200 if file.backend != "docbook":
1206 i = find_token(file.body, "\\begin_layout Author", i)
1211 while file.body[i] == "":
1214 if file.body[i][:11] != "\\end_layout" or file.body[i+2][:13] != "\\begin_deeper":
1219 i = find_end_of( file.body, i+3, "\\begin_deeper","\\end_deeper")
1221 # something is really wrong, abort
1222 file.warning("Missing \\end_deeper, after style Author.")
1223 file.warning("Aborted attempt to parse FirstName and Surname.")
1225 firstname, surname = "", ""
1227 name = file.body[k:i]
1229 j = find_token(name, "\\begin_layout FirstName", 0)
1232 while(name[j] != "\\end_layout"):
1233 firstname = firstname + name[j]
1236 j = find_token(name, "\\begin_layout Surname", 0)
1239 while(name[j] != "\\end_layout"):
1240 surname = surname + name[j]
1244 del file.body[k+2:i+1]
1246 file.body[k-1:k-1] = ["", "",
1247 "\\begin_inset CharStyle Firstname",
1250 "\\begin_layout Standard",
1258 "\\begin_inset CharStyle Surname",
1261 "\\begin_layout Standard",
1270 def revert_names(file):
1271 """ Revert in the docbook backend from firstname and surname char style
1274 if file.backend != "docbook":
1279 # \use_natbib 1 \cite_engine <style>
1280 # \use_numerical_citations 0 -> where <style> is one of
1281 # \use_jurabib 0 "basic", "natbib_authoryear",
1282 # "natbib_numerical" or "jurabib"
1283 def convert_cite_engine(file):
1284 a = find_token(file.header, "\\use_natbib", 0)
1286 file.warning("Malformed lyx file: Missing '\\use_natbib'.")
1289 b = find_token(file.header, "\\use_numerical_citations", 0)
1290 if b == -1 or b != a+1:
1291 file.warning("Malformed lyx file: Missing '\\use_numerical_citations'.")
1294 c = find_token(file.header, "\\use_jurabib", 0)
1295 if c == -1 or c != b+1:
1296 file.warning("Malformed lyx file: Missing '\\use_jurabib'.")
1299 use_natbib = int(split(file.header[a])[1])
1300 use_numerical_citations = int(split(file.header[b])[1])
1301 use_jurabib = int(split(file.header[c])[1])
1303 cite_engine = "basic"
1305 if use_numerical_citations:
1306 cite_engine = "natbib_numerical"
1308 cite_engine = "natbib_authoryear"
1310 cite_engine = "jurabib"
1312 del file.header[a:c+1]
1313 file.header.insert(a, "\\cite_engine " + cite_engine)
1316 def revert_cite_engine(file):
1317 i = find_token(file.header, "\\cite_engine", 0)
1319 file.warning("Malformed lyx file: Missing '\\cite_engine'.")
1322 cite_engine = split(file.header[i])[1]
1327 if cite_engine == "natbib_numerical":
1330 elif cite_engine == "natbib_authoryear":
1332 elif cite_engine == "jurabib":
1336 file.header.insert(i, "\\use_jurabib " + use_jurabib)
1337 file.header.insert(i, "\\use_numerical_citations " + use_numerical)
1338 file.header.insert(i, "\\use_natbib " + use_natbib)
1344 def convert_paperpackage(file):
1345 i = find_token(file.header, "\\paperpackage", 0)
1347 file.warning("Malformed lyx file: Missing '\\paperpackage'.")
1350 packages = {'a4':'none', 'a4wide':'a4', 'widemarginsa4':'a4wide'}
1351 paperpackage = split(file.header[i])[1]
1352 file.header[i] = replace(file.header[i], paperpackage, packages[paperpackage])
1355 def revert_paperpackage(file):
1356 i = find_token(file.header, "\\paperpackage", 0)
1358 file.warning("Malformed lyx file: Missing '\\paperpackage'.")
1361 packages = {'none':'a4', 'a4':'a4wide', 'a4wide':'widemarginsa4',
1363 paperpackage = split(file.header[i])[1]
1364 file.header[i] = replace(file.header[i], paperpackage, packages[paperpackage])
1370 def convert_bullets(file):
1373 i = find_token(file.header, "\\bullet", i)
1376 if file.header[i][:12] == '\\bulletLaTeX':
1377 file.header[i] = file.header[i] + ' ' + strip(file.header[i+1])
1380 file.header[i] = file.header[i] + ' ' + strip(file.header[i+1]) +\
1381 ' ' + strip(file.header[i+2]) + ' ' + strip(file.header[i+3])
1383 del file.header[i+1:i + n]
1387 def revert_bullets(file):
1390 i = find_token(file.header, "\\bullet", i)
1393 if file.header[i][:12] == '\\bulletLaTeX':
1394 n = find(file.header[i], '"')
1396 file.warning("Malformed header.")
1399 file.header[i:i+1] = [file.header[i][:n-1],'\t' + file.header[i][n:], '\\end_bullet']
1402 frag = split(file.header[i])
1404 file.warning("Malformed header.")
1407 file.header[i:i+1] = [frag[0] + ' ' + frag[1],
1416 # \begin_header and \begin_document
1418 def add_begin_header(file):
1419 i = find_token(file.header, '\\lyxformat', 0)
1420 file.header.insert(i+1, '\\begin_header')
1421 file.header.insert(i+1, '\\begin_document')
1424 def remove_begin_header(file):
1425 i = find_token(file.header, "\\begin_document", 0)
1428 i = find_token(file.header, "\\begin_header", 0)
1434 # \begin_file.body and \end_file.body
1436 def add_begin_body(file):
1437 file.body.insert(0, '\\begin_body')
1438 file.body.insert(1, '')
1439 i = find_token(file.body, "\\end_document", 0)
1440 file.body.insert(i, '\\end_body')
1442 def remove_begin_body(file):
1443 i = find_token(file.body, "\\begin_body", 0)
1446 if not file.body[i]:
1448 i = find_token(file.body, "\\end_body", 0)
1456 def normalize_papersize(file):
1457 i = find_token(file.header, '\\papersize', 0)
1461 tmp = split(file.header[i])
1462 if tmp[1] == "Default":
1463 file.header[i] = '\\papersize default'
1465 if tmp[1] == "Custom":
1466 file.header[i] = '\\papersize custom'
1469 def denormalize_papersize(file):
1470 i = find_token(file.header, '\\papersize', 0)
1474 tmp = split(file.header[i])
1475 if tmp[1] == "custom":
1476 file.header[i] = '\\papersize Custom'
1480 # Strip spaces at end of command line
1482 def strip_end_space(file):
1483 for i in range(len(file.body)):
1484 if file.body[i][:1] == '\\':
1485 file.body[i] = strip(file.body[i])
1489 # Use boolean values for \use_geometry, \use_bibtopic and \tracking_changes
1491 def use_x_boolean(file):
1492 bin2bool = {'0': 'false', '1': 'true'}
1493 for use in '\\use_geometry', '\\use_bibtopic', '\\tracking_changes':
1494 i = find_token(file.header, use, 0)
1497 decompose = split(file.header[i])
1498 file.header[i] = decompose[0] + ' ' + bin2bool[decompose[1]]
1501 def use_x_binary(file):
1502 bool2bin = {'false': '0', 'true': '1'}
1503 for use in '\\use_geometry', '\\use_bibtopic', '\\tracking_changes':
1504 i = find_token(file.header, use, 0)
1507 decompose = split(file.header[i])
1508 file.header[i] = decompose[0] + ' ' + bool2bin[decompose[1]]
1514 table = { 223 : [insert_tracking_changes, add_end_header, remove_color_default,
1515 convert_spaces, convert_bibtex, remove_insetparent],
1516 224 : [convert_external, convert_comment],
1517 225 : [add_end_layout, layout2begin_layout, convert_end_document,
1518 convert_table_valignment_middle, convert_breaks],
1519 226 : [convert_note],
1520 227 : [convert_box],
1521 228 : [convert_collapsable, convert_ert],
1522 229 : [convert_minipage],
1523 230 : [convert_jurabib],
1524 231 : [convert_float],
1525 232 : [convert_bibtopic],
1526 233 : [convert_graphics, convert_names],
1527 234 : [convert_cite_engine],
1528 235 : [convert_paperpackage],
1529 236 : [convert_bullets, add_begin_header, add_begin_body,
1530 normalize_papersize, strip_end_space],
1531 237 : [use_x_boolean],
1532 238 : [update_latexaccents]}
1534 chain = table.keys()
1537 for version in chain:
1538 if file.format >= version:
1540 for convert in table[version]:
1542 file.format = version
1543 if file.end_format == file.format:
1549 236: [use_x_binary],
1550 235: [denormalize_papersize, remove_begin_body,remove_begin_header,
1552 234: [revert_paperpackage],
1553 233: [revert_cite_engine],
1554 232: [revert_names],
1555 231: [revert_bibtopic],
1556 230: [revert_float],
1557 229: [revert_jurabib],
1559 227: [revert_collapsable, revert_ert],
1560 226: [revert_box, revert_external_2],
1562 224: [rm_end_layout, begin_layout2layout, revert_end_document,
1563 revert_valignment_middle, convert_vspace, convert_frameless_box],
1564 223: [revert_external_2, revert_comment],
1565 221: [rm_end_header, revert_spaces, revert_bibtex,
1566 rm_tracking_changes, rm_body_changes]}
1568 chain = table.keys()
1572 for version in chain:
1573 if file.format <= version:
1575 for convert in table[version]:
1577 file.format = version
1578 if file.end_format == file.format:
1581 if __name__ == "__main__":