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
30 # Remove \color default
32 def remove_color_default(lines):
35 i = find_token(lines, "\\color default", i)
38 lines[i] = replace(lines[i], "\\color default",
45 def add_end_header(header):
46 header.append("\\end_header");
49 def rm_end_header(lines):
50 i = find_token(lines, "\\end_header", 0)
57 # \SpecialChar ~ -> \InsetSpace ~
59 def convert_spaces(lines):
60 for i in range(len(lines)):
61 lines[i] = replace(lines[i],"\\SpecialChar ~","\\InsetSpace ~")
64 def revert_spaces(lines):
65 for i in range(len(lines)):
66 lines[i] = replace(lines[i],"\\InsetSpace ~", "\\SpecialChar ~")
72 def convert_bibtex(lines):
73 for i in range(len(lines)):
74 lines[i] = replace(lines[i],"\\begin_inset LatexCommand \\BibTeX",
75 "\\begin_inset LatexCommand \\bibtex")
78 def revert_bibtex(lines):
79 for i in range(len(lines)):
80 lines[i] = replace(lines[i], "\\begin_inset LatexCommand \\bibtex",
81 "\\begin_inset LatexCommand \\BibTeX")
87 def remove_insetparent(lines):
90 i = find_token(lines, "\\begin_inset LatexCommand \\lyxparent", i)
99 def convert_external(lines):
100 external_rexp = re.compile(r'\\begin_inset External ([^,]*),"([^"]*)",')
101 external_header = "\\begin_inset External"
104 i = find_token(lines, external_header, i)
107 look = external_rexp.search(lines[i])
110 args[0] = look.group(1)
111 args[1] = look.group(2)
112 #FIXME: if the previous search fails then warn
114 if args[0] == "RasterImage":
115 # Convert a RasterImage External Inset to a Graphics Inset.
116 top = "\\begin_inset Graphics"
118 filename = "\tfilename " + args[1]
119 lines[i:i+1] = [top, filename]
122 # Convert the old External Inset format to the new.
123 top = external_header
124 template = "\ttemplate " + args[0]
126 filename = "\tfilename " + args[1]
127 lines[i:i+1] = [top, template, filename]
130 lines[i:i+1] = [top, template]
134 def revert_external_1(lines):
135 external_header = "\\begin_inset External"
138 i = find_token(lines, external_header, i)
142 template = split(lines[i+1])
146 filename = split(lines[i+1])
150 params = split(lines[i+1])
152 if lines[i+1]: del lines[i+1]
154 lines[i] = lines[i] + " " + template[0]+ ', "' + filename[0] + '", " '+ join(params[1:]) + '"'
158 def revert_external_2(lines):
159 draft_token = '\tdraft'
162 i = find_token(lines, '\\begin_inset External', i)
165 j = find_end_of_inset(lines, i + 1)
167 #this should not happen
169 k = find_token(lines, draft_token, i+1, j-1)
170 if (k != -1 and len(draft_token) == len(lines[k])):
178 def convert_comment(lines):
180 comment = "\\layout Comment"
182 i = find_token(lines, comment, i)
186 lines[i:i+1] = ["\\layout Standard","","",
187 "\\begin_inset Comment",
194 i = find_token(lines, "\\layout", i)
197 lines[i:i] = ["\\end_inset ","",""]
200 j = find_token(lines, '\\begin_deeper', old_i, i)
201 if j == -1: j = i + 1
202 k = find_token(lines, '\\begin_inset', old_i, i)
203 if k == -1: k = i + 1
208 i = find_end_of( lines, i, "\\begin_deeper","\\end_deeper")
210 #This case should not happen
211 #but if this happens deal with it greacefully adding
212 #the missing \end_deeper.
214 lines[i:i] = ["\end_deeper","","","\\end_inset ","",""]
222 i = find_end_of( lines, i, "\\begin_inset","\\end_inset")
224 #This case should not happen
225 #but if this happens deal with it greacefully adding
226 #the missing \end_inset.
228 lines[i:i] = ["\\end_inset ","","","\\end_inset ","",""]
234 if find(lines[i], comment) == -1:
235 lines[i:i] = ["\\end_inset"]
238 lines[i:i+1] = ["\\layout Standard"]
242 def revert_comment(lines):
245 i = find_tokens(lines, ["\\begin_inset Comment", "\\begin_inset Greyedout"], i)
249 lines[i] = "\\begin_inset Note"
256 def add_end_layout(lines):
257 i = find_token(lines, '\\layout', 0)
263 struct_stack = ["\\layout"]
266 i = find_tokens(lines, ["\\begin_inset", "\\end_inset", "\\layout",
267 "\\begin_deeper", "\\end_deeper", "\\the_end"], i)
269 token = split(lines[i])[0]
271 if token == "\\begin_inset":
272 struct_stack.append(token)
276 if token == "\\end_inset":
277 tail = struct_stack.pop()
278 if tail == "\\layout":
280 lines.insert(i,"\\end_layout")
282 #Check if it is the correct tag
287 if token == "\\layout":
288 tail = struct_stack.pop()
291 lines.insert(i,"\\end_layout")
294 struct_stack.append(tail)
296 struct_stack.append(token)
299 if token == "\\begin_deeper":
301 lines.insert(i,"\\end_layout")
303 struct_stack.append(token)
306 if token == "\\end_deeper":
308 lines.insert(i,"\\end_layout")
310 while struct_stack[-1] != "\\begin_deeper":
316 lines.insert(i, "\\end_layout")
320 def rm_end_layout(lines):
323 i = find_token(lines, '\\end_layout', i)
332 # Handle change tracking keywords
334 def insert_tracking_changes(lines):
335 i = find_token(lines, "\\tracking_changes", 0)
337 lines.append("\\tracking_changes 0")
339 def rm_tracking_changes(lines):
340 i = find_token(lines, "\\author", 0)
344 i = find_token(lines, "\\tracking_changes", 0)
350 def rm_body_changes(lines):
353 i = find_token(lines, "\\change_", i)
361 # \layout -> \begin_layout
363 def layout2begin_layout(lines):
366 i = find_token(lines, '\\layout', i)
370 lines[i] = replace(lines[i], '\\layout', '\\begin_layout')
374 def begin_layout2layout(lines):
377 i = find_token(lines, '\\begin_layout', i)
381 lines[i] = replace(lines[i], '\\begin_layout', '\\layout')
386 # valignment="center" -> valignment="middle"
388 def convert_valignment_middle(lines, start, end):
389 for i in range(start, end):
390 if re.search('^<(column|cell) .*valignment="center".*>$', lines[i]):
391 lines[i] = replace(lines[i], 'valignment="center"', 'valignment="middle"')
394 def convert_table_valignment_middle(lines):
397 i = find_token(lines, '\\begin_inset Tabular', i)
400 j = find_end_of_inset(lines, i + 1)
402 #this should not happen
403 convert_valignment_middle(lines, i + 1, len(lines))
405 convert_valignment_middle(lines, i + 1, j)
409 def revert_table_valignment_middle(lines, start, end):
410 for i in range(start, end):
411 if re.search('^<(column|cell) .*valignment="middle".*>$', lines[i]):
412 lines[i] = replace(lines[i], 'valignment="middle"', 'valignment="center"')
415 def revert_valignment_middle(lines):
418 i = find_token(lines, '\\begin_inset Tabular', i)
421 j = find_end_of_inset(lines, i + 1)
423 #this should not happen
424 revert_table_valignment_middle(lines, i + 1, len(lines))
426 revert_table_valignment_middle(lines, i + 1, j)
431 # \the_end -> \end_document
433 def convert_end_document(lines):
434 i = find_token(lines, "\\the_end", 0)
436 lines.append("\\end_document")
438 lines[i] = "\\end_document"
441 def revert_end_document(lines):
442 i = find_token(lines, "\\end_document", 0)
444 lines.append("\\the_end")
446 lines[i] = "\\the_end"
450 # Convert line and page breaks
453 #\line_top \line_bottom \pagebreak_top \pagebreak_bottom \added_space_top xxx \added_space_bottom yyy
457 #\begin layout Standard
462 #\begin_inset VSpace xxx
466 #\begin_layout Standard
470 #\begin_layout Standard
472 #\begin_inset VSpace xxx
479 def convert_breaks(lines):
482 i = find_token(lines, "\\begin_layout", i)
486 line_top = find(lines[i],"\\line_top")
487 line_bot = find(lines[i],"\\line_bottom")
488 pb_top = find(lines[i],"\\pagebreak_top")
489 pb_bot = find(lines[i],"\\pagebreak_bottom")
490 vspace_top = find(lines[i],"\\added_space_top")
491 vspace_bot = find(lines[i],"\\added_space_bottom")
493 if line_top == -1 and line_bot == -1 and pb_bot == -1 and pb_top == -1 and vspace_top == -1 and vspace_bot == -1:
496 for tag in "\\line_top", "\\line_bottom", "\\pagebreak_top", "\\pagebreak_bottom":
497 lines[i] = replace(lines[i], tag, "")
500 # the position could be change because of the removal of other
501 # paragraph properties above
502 vspace_top = find(lines[i],"\\added_space_top")
503 tmp_list = split(lines[i][vspace_top:])
504 vspace_top_value = tmp_list[1]
505 lines[i] = lines[i][:vspace_top] + join(tmp_list[2:])
508 # the position could be change because of the removal of other
509 # paragraph properties above
510 vspace_bot = find(lines[i],"\\added_space_bottom")
511 tmp_list = split(lines[i][vspace_bot:])
512 vspace_bot_value = tmp_list[1]
513 lines[i] = lines[i][:vspace_bot] + join(tmp_list[2:])
515 lines[i] = strip(lines[i])
518 # Create an empty paragraph for line and page break that belong
519 # above the paragraph
520 if pb_top !=-1 or line_top != -1 or vspace_bot != -1:
522 paragraph_above = ['','\\begin_layout Standard','','']
525 paragraph_above.extend(['\\newpage ',''])
528 paragraph_above.extend(['\\begin_inset VSpace ' + vspace_top_value,'\\end_inset ','',''])
531 paragraph_above.extend(['\\lyxline ',''])
533 paragraph_above.extend(['\\end_layout',''])
535 #inset new paragraph above the current paragraph
536 lines[i-2:i-2] = paragraph_above
537 i = i + len(paragraph_above)
539 # Ensure that nested style are converted later.
540 k = find_end_of(lines, i, "\\begin_layout", "\\end_layout")
545 if pb_top !=-1 or line_top != -1 or vspace_bot != -1:
547 paragraph_bellow = ['','\\begin_layout Standard','','']
550 paragraph_bellow.extend(['\\lyxline ',''])
553 paragraph_bellow.extend(['\\begin_inset VSpace ' + vspace_bot_value,'\\end_inset ','',''])
556 paragraph_bellow.extend(['\\newpage ',''])
558 paragraph_bellow.extend(['\\end_layout',''])
560 #inset new paragraph above the current paragraph
561 lines[k + 1: k + 1] = paragraph_bellow
567 def convert_note(lines):
570 i = find_tokens(lines, ["\\begin_inset Note",
571 "\\begin_inset Comment",
572 "\\begin_inset Greyedout"], i)
576 lines[i] = lines[i][0:13] + 'Note ' + lines[i][13:]
580 def revert_note(lines):
581 note_header = "\\begin_inset Note "
584 i = find_token(lines, note_header, i)
588 lines[i] = "\\begin_inset " + lines[i][len(note_header):]
595 def convert_box(lines):
598 i = find_tokens(lines, ["\\begin_inset Boxed",
599 "\\begin_inset Doublebox",
600 "\\begin_inset Frameless",
601 "\\begin_inset ovalbox",
602 "\\begin_inset Ovalbox",
603 "\\begin_inset Shadowbox"], i)
607 lines[i] = lines[i][0:13] + 'Box ' + lines[i][13:]
611 def revert_box(lines):
612 box_header = "\\begin_inset Box "
615 i = find_token(lines, box_header, i)
619 lines[i] = "\\begin_inset " + lines[i][len(box_header):]
626 def convert_collapsable(lines, opt):
629 i = find_tokens(lines, ["\\begin_inset Box",
630 "\\begin_inset Branch",
631 "\\begin_inset CharStyle",
632 "\\begin_inset Float",
633 "\\begin_inset Foot",
634 "\\begin_inset Marginal",
635 "\\begin_inset Note",
636 "\\begin_inset OptArg",
637 "\\begin_inset Wrap"], i)
641 # Seach for a line starting 'collapsed'
642 # If, however, we find a line starting '\begin_layout'
643 # (_always_ present) then break with a warning message
646 if (lines[i] == "collapsed false"):
647 lines[i] = "status open"
649 elif (lines[i] == "collapsed true"):
650 lines[i] = "status collapsed"
652 elif (lines[i][:13] == "\\begin_layout"):
653 opt.warning("Malformed LyX file.")
660 def revert_collapsable(lines, opt):
663 i = find_tokens(lines, ["\\begin_inset Box",
664 "\\begin_inset Branch",
665 "\\begin_inset CharStyle",
666 "\\begin_inset Float",
667 "\\begin_inset Foot",
668 "\\begin_inset Marginal",
669 "\\begin_inset Note",
670 "\\begin_inset OptArg",
671 "\\begin_inset Wrap"], i)
675 # Seach for a line starting 'status'
676 # If, however, we find a line starting '\begin_layout'
677 # (_always_ present) then break with a warning message
680 if (lines[i] == "status open"):
681 lines[i] = "collapsed false"
683 elif (lines[i] == "status collapsed" or
684 lines[i] == "status inlined"):
685 lines[i] = "collapsed true"
687 elif (lines[i][:13] == "\\begin_layout"):
688 opt.warning("Malformed LyX file.")
698 def convert_ert(lines, opt):
701 i = find_token(lines, "\\begin_inset ERT", i)
705 # Seach for a line starting 'status'
706 # If, however, we find a line starting '\begin_layout'
707 # (_always_ present) then break with a warning message
710 if (lines[i] == "status Open"):
711 lines[i] = "status open"
713 elif (lines[i] == "status Collapsed"):
714 lines[i] = "status collapsed"
716 elif (lines[i] == "status Inlined"):
717 lines[i] = "status inlined"
719 elif (lines[i][:13] == "\\begin_layout"):
720 opt.warning("Malformed LyX file.")
727 def revert_ert(lines, opt):
730 i = find_token(lines, "\\begin_inset ERT", i)
734 # Seach for a line starting 'status'
735 # If, however, we find a line starting '\begin_layout'
736 # (_always_ present) then break with a warning message
739 if (lines[i] == "status open"):
740 lines[i] = "status Open"
742 elif (lines[i] == "status collapsed"):
743 lines[i] = "status Collapsed"
745 elif (lines[i] == "status inlined"):
746 lines[i] = "status Inlined"
748 elif (lines[i][:13] == "\\begin_layout"):
749 opt.warning("Malformed LyX file.")
759 def convert_minipage(lines):
760 """ Convert minipages to the box inset.
761 We try to use the same order of arguments as lyx does.
764 inner_pos = ["c","t","b","s"]
768 i = find_token(lines, "\\begin_inset Minipage", i)
772 lines[i] = "\\begin_inset Box Frameless"
775 # convert old to new position using the pos list
776 if lines[i][:8] == "position":
777 lines[i] = 'position "%s"' % pos[int(lines[i][9])]
779 lines.insert(i, 'position "%s"' % pos[0])
782 lines.insert(i, 'hor_pos "c"')
784 lines.insert(i, 'has_inner_box 1')
787 # convert the inner_position
788 if lines[i][:14] == "inner_position":
789 lines[i] = 'inner_pos "%s"' % inner_pos[int(lines[i][15])]
791 lines.insert('inner_pos "%s"' % inner_pos[0])
794 # We need this since the new file format has a height and width
795 # in a different order.
796 if lines[i][:6] == "height":
797 height = lines[i][6:]
798 # test for default value of 221 and convert it accordingly
799 if height == ' "0pt"':
805 if lines[i][:5] == "width":
811 if lines[i][:9] == "collapsed":
812 if lines[i][9:] == "true":
820 lines.insert(i, 'use_parbox 0')
822 lines.insert(i, 'width' + width)
824 lines.insert(i, 'special "none"')
826 lines.insert(i, 'height' + height)
828 lines.insert(i, 'height_special "totalheight"')
830 lines.insert(i, 'status ' + status)
834 # -------------------------------------------------------------------------------------------
835 # Convert backslashes into valid ERT code, append the converted text to
836 # lines[i] and return the (maybe incremented) line index i
837 def convert_ertbackslash(lines, i, ert):
840 lines[i] = lines[i] + '\\backslash '
844 lines[i] = lines[i] + c
848 def convert_vspace(header, lines, opt):
850 # Get default spaceamount
851 i = find_token(header, '\\defskip', 0)
853 defskipamount = 'medskip'
855 defskipamount = split(header[i])[1]
860 i = find_token(lines, '\\begin_inset VSpace', i)
863 spaceamount = split(lines[i])[2]
865 # Are we at the beginning or end of a paragraph?
867 start = get_paragraph(lines, i) + 1
868 for k in range(start, i):
869 if is_nonempty_line(lines[k]):
873 j = find_end_of_inset(lines, i)
875 opt.warning("Malformed LyX file: Missing '\\end_inset'.")
878 end = get_next_paragraph(lines, i)
879 for k in range(j + 1, end):
880 if is_nonempty_line(lines[k]):
884 # Convert to paragraph formatting if we are at the beginning or end
885 # of a paragraph and the resulting paragraph would not be empty
886 if ((paragraph_start and not paragraph_end) or
887 (paragraph_end and not paragraph_start)):
888 # The order is important: del and insert invalidate some indices
892 lines.insert(start, '\\added_space_top ' + spaceamount + ' ')
894 lines.insert(start, '\\added_space_bottom ' + spaceamount + ' ')
898 lines[i:i+1] = ['\\begin_inset ERT', 'status Collapsed', '',
899 '\\layout Standard', '', '\\backslash ']
901 if spaceamount[-1] == '*':
902 spaceamount = spaceamount[:-1]
907 # Replace defskip by the actual value
908 if spaceamount == 'defskip':
909 spaceamount = defskipamount
911 # LaTeX does not know \\smallskip* etc
913 if spaceamount == 'smallskip':
914 spaceamount = '\\smallskipamount'
915 elif spaceamount == 'medskip':
916 spaceamount = '\\medskipamount'
917 elif spaceamount == 'bigskip':
918 spaceamount = '\\bigskipamount'
919 elif spaceamount == 'vfill':
920 spaceamount = '\\fill'
922 # Finally output the LaTeX code
923 if (spaceamount == 'smallskip' or spaceamount == 'medskip' or
924 spaceamount == 'bigskip' or spaceamount == 'vfill'):
925 lines.insert(i, spaceamount)
928 lines.insert(i, 'vspace*{')
930 lines.insert(i, 'vspace{')
931 i = convert_ertbackslash(lines, i, spaceamount)
932 lines[i] = lines[i] + '}'
936 # Convert a LyX length into valid ERT code and append it to lines[i]
937 # Return the (maybe incremented) line index i
938 def convert_ertlen(lines, i, len, special):
939 units = {"text%":"\\textwidth", "col%":"\\columnwidth",
940 "page%":"\\pagewidth", "line%":"\\linewidth",
941 "theight%":"\\textheight", "pheight%":"\\pageheight"}
943 # Convert special lengths
944 if special != 'none':
945 len = '%f\\' % len2value(len) + special
947 # Convert LyX units to LaTeX units
948 for unit in units.keys():
949 if find(len, unit) != -1:
950 len = '%f' % (len2value(len) / 100) + units[unit]
953 # Convert backslashes and insert the converted length into lines
954 return convert_ertbackslash(lines, i, len)
957 # Return the value of len without the unit in numerical form
959 result = re.search('([+-]?[0-9.]+)', len)
961 return float(result.group(1))
962 # No number means 1.0
966 def convert_frameless_box(lines, opt):
967 pos = ['t', 'c', 'b']
968 inner_pos = ['c', 't', 'b', 's']
971 i = find_token(lines, '\\begin_inset Frameless', i)
974 j = find_end_of_inset(lines, i)
976 opt.warning("Malformed LyX file: Missing '\\end_inset'\n")
982 params = {'position':'0', 'hor_pos':'c', 'has_inner_box':'1',
983 'inner_pos':'1', 'use_parbox':'0', 'width':'100col%',
984 'special':'none', 'height':'1in',
985 'height_special':'totalheight', 'collapsed':'false'}
986 for key in params.keys():
987 value = replace(get_value(lines, key, i, j), '"', '')
989 if key == 'position':
990 # convert new to old position: 'position "t"' -> 0
991 value = find_token(pos, value, 0)
994 elif key == 'inner_pos':
995 # convert inner position
996 value = find_token(inner_pos, value, 0)
1001 j = del_token(lines, key, i, j)
1004 # Convert to minipage or ERT?
1005 # Note that the inner_position and height parameters of a minipage
1006 # inset are ignored and not accessible for the user, although they
1007 # are present in the file format and correctly read in and written.
1008 # Therefore we convert to ERT if they do not have their LaTeX
1009 # defaults. These are:
1010 # - the value of "position" for "inner_pos"
1011 # - "\totalheight" for "height"
1012 if (params['use_parbox'] != '0' or
1013 params['has_inner_box'] != '1' or
1014 params['special'] != 'none' or
1015 inner_pos[params['inner_pos']] != pos[params['position']] or
1016 params['height_special'] != 'totalheight' or
1017 len2value(params['height']) != 1.0):
1020 if params['collapsed'] == 'true':
1021 params['collapsed'] = 'Collapsed'
1023 params['collapsed'] = 'Open'
1024 lines[i : i] = ['\\begin_inset ERT', 'status ' + params['collapsed'],
1025 '', '\\layout Standard', '', '\\backslash ']
1027 if params['use_parbox'] == '1':
1028 lines.insert(i, 'parbox')
1030 lines.insert(i, 'begin{minipage}')
1031 lines[i] = lines[i] + '[' + pos[params['position']] + ']['
1032 i = convert_ertlen(lines, i, params['height'], params['height_special'])
1033 lines[i] = lines[i] + '][' + inner_pos[params['inner_pos']] + ']{'
1034 i = convert_ertlen(lines, i, params['width'], params['special'])
1035 if params['use_parbox'] == '1':
1036 lines[i] = lines[i] + '}{'
1038 lines[i] = lines[i] + '}'
1040 lines[i:i] = ['', '\\end_inset ']
1042 j = find_end_of_inset(lines, i)
1044 opt.warning("Malformed LyX file: Missing '\\end_inset'.")
1046 lines[j-1:j-1] = ['\\begin_inset ERT', 'status ' + params['collapsed'],
1047 '', '\\layout Standard', '']
1049 if params['use_parbox'] == '1':
1050 lines.insert(j, '}')
1052 lines[j:j] = ['\\backslash ', 'end{minipage}']
1055 # Convert to minipage
1056 lines[i:i] = ['\\begin_inset Minipage',
1057 'position %d' % params['position'],
1058 'inner_position %d' % params['inner_pos'],
1059 'height "' + params['height'] + '"',
1060 'width "' + params['width'] + '"',
1061 'collapsed ' + params['collapsed']]
1068 def convert_jurabib(header, opt):
1069 i = find_token(header, '\\use_numerical_citations', 0)
1071 opt.warning("Malformed lyx file: Missing '\\use_numerical_citations'")
1073 header.insert(i + 1, '\\use_jurabib 0')
1076 def revert_jurabib(header, opt):
1077 i = find_token(header, '\\use_jurabib', 0)
1079 opt.warning("Malformed lyx file: Missing '\\use_jurabib'")
1081 if get_value(header, '\\use_jurabib', 0) != "0":
1082 opt.warning("Conversion of '\\use_jurabib = 1' not yet implemented.")
1083 # Don't remove '\\use_jurabib' so that people will get warnings by lyx
1091 def convert_bibtopic(header, opt):
1092 i = find_token(header, '\\use_jurabib', 0)
1094 opt.warning("Malformed lyx file: Missing '\\use_jurabib'")
1096 header.insert(i + 1, '\\use_bibtopic 0')
1099 def revert_bibtopic(header, opt):
1100 i = find_token(header, '\\use_bibtopic', 0)
1102 opt.warning("Malformed lyx file: Missing '\\use_bibtopic'")
1104 if get_value(header, '\\use_bibtopic', 0) != "0":
1105 opt.warning("Conversion of '\\use_bibtopic = 1' not yet implemented.")
1106 # Don't remove '\\use_jurabib' so that people will get warnings by lyx
1113 def convert_float(lines, opt):
1116 i = find_token(lines, '\\begin_inset Float', i)
1119 # Seach for a line starting 'wide'
1120 # If, however, we find a line starting '\begin_layout'
1121 # (_always_ present) then break with a warning message
1124 if (lines[i][:4] == "wide"):
1125 lines.insert(i + 1, 'sideways false')
1127 elif (lines[i][:13] == "\\begin_layout"):
1128 opt.warning("Malformed lyx file")
1134 def revert_float(lines, opt):
1137 i = find_token(lines, '\\begin_inset Float', i)
1140 j = find_end_of_inset(lines, i)
1142 opt.warning("Malformed lyx file: Missing '\\end_inset'")
1145 if get_value(lines, 'sideways', i, j) != "false":
1146 opt.warning("Conversion of 'sideways true' not yet implemented.")
1147 # Don't remove 'sideways' so that people will get warnings by lyx
1150 del_token(lines, 'sideways', i, j)
1154 def convert_graphics(lines, opt):
1155 """ Add extension to filenames of insetgraphics if necessary.
1159 i = find_token(lines, "\\begin_inset Graphics", i)
1163 j = find_token2(lines, "filename", i)
1167 filename = split(lines[j])[1]
1168 absname = os.path.normpath(os.path.join(opt.dir, filename))
1169 if opt.input == stdin and not os.path.isabs(filename):
1170 # We don't know the directory and cannot check the file.
1171 # We could use a heuristic and take the current directory,
1172 # and we could try to find out if filename has an extension,
1173 # but that would be just guesses and could be wrong.
1174 opt.warning("""Warning: Can not determine whether file
1176 needs an extension when reading from standard input.
1177 You may need to correct the file manually or run
1178 lyx2lyx again with the .lyx file as commandline argument.""" % filename)
1180 # This needs to be the same algorithm as in pre 233 insetgraphics
1181 if access(absname, F_OK):
1183 if access(absname + ".ps", F_OK):
1184 lines[j] = replace(lines[j], filename, filename + ".ps")
1186 if access(absname + ".eps", F_OK):
1187 lines[j] = replace(lines[j], filename, filename + ".eps")
1191 # Convert firstname and surname from styles -> char styles
1193 def convert_names(lines, opt):
1194 """ Convert in the docbook backend from firstname and surname style
1197 if opt.backend != "docbook":
1203 i = find_token(lines, "\\begin_layout Author", i)
1208 while lines[i] == "":
1211 if lines[i][:11] != "\\end_layout" or lines[i+2][:13] != "\\begin_deeper":
1216 i = find_end_of( lines, i+3, "\\begin_deeper","\\end_deeper")
1218 # something is really wrong, abort
1219 opt.warning("Missing \\end_deeper,after style Author")
1220 opt.warning("Aborted attempt to parse FirstName and Surname")
1222 firstname, surname = "", ""
1226 j = find_token(name, "\\begin_layout FirstName", 0)
1229 while(name[j] != "\\end_layout"):
1230 firstname = firstname + name[j]
1233 j = find_token(name, "\\begin_layout Surname", 0)
1236 while(name[j] != "\\end_layout"):
1237 surname = surname + name[j]
1243 lines[k-1:k-1] = ["", "",
1244 "\\begin_inset CharStyle Firstname",
1247 "\\begin_layout Standard",
1255 "\\begin_inset CharStyle Surname",
1258 "\\begin_layout Standard",
1267 def revert_names(lines, opt):
1268 """ Revert in the docbook backend from firstname and surname char style
1271 if opt.backend != "docbook":
1276 # \use_natbib 1 \cite_engine <style>
1277 # \use_numerical_citations 0 -> where <style> is one of
1278 # \use_jurabib 0 "basic", "natbib_authoryear",
1279 # "natbib_numerical" or "jurabib"
1280 def convert_cite_engine(header, opt):
1281 a = find_token(header, "\\use_natbib", 0)
1283 opt.warning("Malformed lyx file: Missing '\\use_natbib'")
1286 b = find_token(header, "\\use_numerical_citations", 0)
1287 if b == -1 or b != a+1:
1288 opt.warning("Malformed lyx file: Missing '\\use_numerical_citations'")
1291 c = find_token(header, "\\use_jurabib", 0)
1292 if c == -1 or c != b+1:
1293 opt.warning("Malformed lyx file: Missing '\\use_jurabib'")
1296 use_natbib = int(split(header[a])[1])
1297 use_numerical_citations = int(split(header[b])[1])
1298 use_jurabib = int(split(header[c])[1])
1300 cite_engine = "basic"
1302 if use_numerical_citations:
1303 cite_engine = "natbib_numerical"
1305 cite_engine = "natbib_authoryear"
1307 cite_engine = "jurabib"
1310 header.insert(a, "\\cite_engine " + cite_engine)
1313 def revert_cite_engine(header, opt):
1314 i = find_token(header, "\\cite_engine", 0)
1316 opt.warning("Malformed lyx file: Missing '\\cite_engine'")
1319 cite_engine = split(header[i])[1]
1324 if cite_engine == "natbib_numerical":
1327 elif cite_engine == "natbib_authoryear":
1329 elif cite_engine == "jurabib":
1333 header.insert(i, "\\use_jurabib " + use_jurabib)
1334 header.insert(i, "\\use_numerical_citations " + use_numerical)
1335 header.insert(i, "\\use_natbib " + use_natbib)
1341 def convert_paperpackage(header, opt):
1342 i = find_token(header, "\\paperpackage", 0)
1344 opt.warning("Malformed lyx file: Missing '\\paperpackage'")
1347 packages = {'a4':'none', 'a4wide':'a4', 'widemarginsa4':'a4wide'}
1348 paperpackage = split(header[i])[1]
1349 header[i] = replace(header[i], paperpackage, packages[paperpackage])
1352 def revert_paperpackage(header, opt):
1353 i = find_token(header, "\\paperpackage", 0)
1355 opt.warning("Malformed lyx file: Missing '\\paperpackage'")
1358 packages = {'none':'a4', 'a4':'a4wide', 'a4wide':'widemarginsa4',
1360 paperpackage = split(header[i])[1]
1361 header[i] = replace(header[i], paperpackage, packages[paperpackage])
1367 def convert_bullets(header, opt):
1370 i = find_token(header, "\\bullet", i)
1373 if header[i][:12] == '\\bulletLaTeX':
1374 header[i] = header[i] + ' ' + strip(header[i+1])
1377 header[i] = header[i] + ' ' + strip(header[i+1]) +\
1378 ' ' + strip(header[i+2]) + ' ' + strip(header[i+3])
1380 del header[i+1:i + n]
1384 def revert_bullets(header, opt):
1387 i = find_token(header, "\\bullet", i)
1390 if header[i][:12] == '\\bulletLaTeX':
1391 n = find(header[i], '"')
1393 opt.warn("Malformed header")
1396 header[i:i+1] = [header[i][:n-1],'\t' + header[i][n:], '\\end_bullet']
1399 frag = split(header[i])
1401 opt.warn("Malformed header")
1404 header[i:i+1] = [frag[0] + ' ' + frag[1],
1413 # \begin_header and \begin_document
1415 def add_begin_header(header, opt):
1416 i = find_token(header, '\\lyxformat', 0)
1417 header.insert(i+1, '\\begin_header')
1418 header.insert(i+1, '\\begin_document')
1421 def remove_begin_header(header, opt):
1422 i = find_token(header, "\\begin_header", 0)
1425 i = find_token(header, "\\begin_document", 0)
1431 # \begin_body and \end_body
1433 def add_begin_body(body, opt):
1434 body.insert(0, '\\begin_body')
1435 i = find_token(body, "\\end_document", 0)
1436 body.insert(i, '\\end_body')
1438 def remove_begin_body(body, opt):
1439 i = find_token(body, "\\begin_body", 0)
1442 i = find_token(body, "\\end_body", 0)
1450 def convert(header, body, opt):
1451 if opt.format < 223:
1452 insert_tracking_changes(header)
1453 add_end_header(header)
1454 remove_color_default(body)
1455 convert_spaces(body)
1456 convert_bibtex(body)
1457 remove_insetparent(body)
1459 if opt.end == opt.format: return
1461 if opt.format < 224:
1462 convert_external(body)
1463 convert_comment(body)
1465 if opt.end == opt.format: return
1467 if opt.format < 225:
1468 add_end_layout(body)
1469 layout2begin_layout(body)
1470 convert_end_document(body)
1471 convert_table_valignment_middle(body)
1472 convert_breaks(body)
1474 if opt.end == opt.format: return
1476 if opt.format < 226:
1479 if opt.end == opt.format: return
1481 if opt.format < 227:
1484 if opt.end == opt.format: return
1486 if opt.format < 228:
1487 convert_collapsable(body, opt)
1488 convert_ert(body, opt)
1490 if opt.end == opt.format: return
1492 if opt.format < 229:
1493 convert_minipage(body)
1495 if opt.end == opt.format: return
1497 if opt.format < 230:
1498 convert_jurabib(header, opt)
1500 if opt.end == opt.format: return
1502 if opt.format < 231:
1503 convert_float(body, opt)
1505 if opt.end == opt.format: return
1507 if opt.format < 232:
1508 convert_bibtopic(header, opt)
1510 if opt.end == opt.format: return
1512 if opt.format < 233:
1513 convert_graphics(body, opt)
1514 convert_names(body, opt)
1516 if opt.end == opt.format: return
1518 if opt.format < 234:
1519 convert_cite_engine(header, opt)
1521 if opt.end == opt.format: return
1523 if opt.format < 235:
1524 convert_paperpackage(header, opt)
1526 if opt.end == opt.format: return
1528 if opt.format < 236:
1529 convert_bullets(header, opt)
1530 add_begin_header(header, opt)
1531 add_begin_body(body, opt)
1534 def revert(header, body, opt):
1535 if opt.format > 235:
1536 remove_begin_body(body, opt)
1537 remove_begin_header(header, opt)
1538 revert_bullets(header, opt)
1540 if opt.end == opt.format: return
1542 if opt.format > 234:
1543 revert_paperpackage(header, opt)
1545 if opt.end == opt.format: return
1547 if opt.format > 233:
1548 revert_cite_engine(header, opt)
1550 if opt.end == opt.format: return
1552 if opt.format > 232:
1553 revert_names(body, opt)
1555 if opt.end == opt.format: return
1557 if opt.format > 231:
1558 revert_bibtopic(header, opt)
1560 if opt.end == opt.format: return
1562 if opt.format > 230:
1563 revert_float(body, opt)
1565 if opt.end == opt.format: return
1567 if opt.format > 229:
1568 revert_jurabib(header, opt)
1570 if opt.end == opt.format: return
1572 if opt.format > 228:
1574 if opt.end == opt.format: return
1576 if opt.format > 227:
1577 revert_collapsable(body, opt)
1578 revert_ert(body, opt)
1580 if opt.end == opt.format: return
1582 if opt.format > 226:
1584 revert_external_2(body)
1586 if opt.end == opt.format: return
1588 if opt.format > 225:
1591 if opt.end == opt.format: return
1593 if opt.format > 224:
1595 begin_layout2layout(body)
1596 revert_end_document(body)
1597 revert_valignment_middle(body)
1598 convert_vspace(header, body, opt)
1599 convert_frameless_box(body, opt)
1600 if opt.end == opt.format: return
1602 if opt.format > 223:
1603 revert_external_2(body)
1604 revert_comment(body)
1606 if opt.end == opt.format: return
1608 if opt.format > 221:
1609 rm_end_header(header)
1612 rm_tracking_changes(header)
1613 rm_body_changes(body)
1617 if __name__ == "__main__":