From 500a5f959fa713c2106855c64fac55739f8a93ff Mon Sep 17 00:00:00 2001 From: Abdelrazak Younes Date: Tue, 30 Jan 2007 13:23:21 +0000 Subject: [PATCH] The caption inset patch by Georg, Martin and myself. * buffer.C: increase LyX format to 257. * lyxtextclass.C: increase FORMAT format to 3. * buffer_funcs.C: - setCaptionLabels(): new recursive function - setCaptions(): new function - updateLabels(): call setCaptions() for each paragraph. * InsetCaption: - add a virtual destructor - overload InsetText' getStatus() and wide(). - setLabel(): only set the new private member label_. - metrics(): don't set label here and correct for title metrics. - draw(): don't set label here - latex(): fix optional argument. - plaintext(): implement! * InsetText: - add a virtual destructor - add virtual to getStatus() and wide(). * output_latex.[Ch]: move latexOptArgInsets() out of anon namespace. * text3.C: enable LFUN_CAPTION_INSERT git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16948 a592a061-630c-0410-9148-cb99ea01b6c8 --- lib/lyx2lyx/LyX.py | 2 +- lib/lyx2lyx/lyx_1_5.py | 108 +++++++++++++++++++++++++++++++++-- lib/scripts/layout2layout.py | 74 ++++++++++++++++++++++-- lib/ui/stdmenus.inc | 1 + src/buffer.C | 2 +- src/buffer_funcs.C | 67 ++++++++++++++++++++++ src/insets/insetcaption.C | 88 +++++++++++++++------------- src/insets/insetcaption.h | 18 ++++-- src/insets/insettext.h | 7 ++- src/lyxtextclass.C | 2 +- src/output_latex.C | 8 +-- src/output_latex.h | 5 ++ src/text3.C | 7 +-- 13 files changed, 322 insertions(+), 67 deletions(-) diff --git a/lib/lyx2lyx/LyX.py b/lib/lyx2lyx/LyX.py index b0bdbdbee8..b8119276e6 100644 --- a/lib/lyx2lyx/LyX.py +++ b/lib/lyx2lyx/LyX.py @@ -73,7 +73,7 @@ format_relation = [("0_06", [200], generate_minor_versions("0.6" , 4)), ("1_2", [220], generate_minor_versions("1.2" , 4)), ("1_3", [221], generate_minor_versions("1.3" , 7)), ("1_4", range(222,246), generate_minor_versions("1.4" , 3)), - ("1_5", range(246,257), generate_minor_versions("1.5" , 0))] + ("1_5", range(246,258), generate_minor_versions("1.5" , 0))] def formats_list(): diff --git a/lib/lyx2lyx/lyx_1_5.py b/lib/lyx2lyx/lyx_1_5.py index 8918fb386f..8f4d453423 100644 --- a/lib/lyx2lyx/lyx_1_5.py +++ b/lib/lyx2lyx/lyx_1_5.py @@ -20,7 +20,7 @@ """ Convert files to the file format generated by lyx 1.5""" import re -from parser_tools import find_token, find_token_exact, find_tokens, find_end_of, get_value +from parser_tools import find_token, find_token_backwards, find_token_exact, find_tokens, find_end_of, get_value from LyX import get_encoding @@ -28,9 +28,13 @@ from LyX import get_encoding # Private helper functions def find_end_of_inset(lines, i): - " Find beginning of inset, where lines[i] is included." + " Find end of inset, where lines[i] is included." return find_end_of(lines, i, "\\begin_inset", "\\end_inset") +def find_end_of_layout(lines, i): + " Find end of layout, where lines[i] is included." + return find_end_of(lines, i, "\\begin_layout", "\\end_layout") + # End of helper functions #################################################################### @@ -720,6 +724,99 @@ def revert_encodings(document): document.inputencoding = get_value(document.header, "\\inputencoding", 0) +def convert_caption(document): + " Convert caption layouts to caption insets. " + i = 0 + while 1: + i = find_token(document.body, "\\begin_layout Caption", i) + if i == -1: + return + j = find_end_of_layout(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Missing `\\end_layout'.") + return + + document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""] + document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout, + "\\begin_inset Caption", "", + "\\begin_layout %s" % document.default_layout] + i = i + 1 + + +def revert_caption(document): + " Convert caption insets to caption layouts. " + " This assumes that the text class has a caption style. " + i = 0 + while 1: + i = find_token(document.body, "\\begin_inset Caption", i) + if i == -1: + return + + # We either need to delete the previous \begin_layout line, or we + # need to end the previous layout if this inset is not in the first + # position of the paragraph. + layout_before = find_token_backwards(document.body, "\\begin_layout", i) + if layout_before == -1: + document.warning("Malformed LyX document: Missing `\\begin_layout'.") + return + layout_line = document.body[layout_before] + del_layout_before = True + l = layout_before + 1 + while l < i: + if document.body[l] != "": + del_layout_before = False + break + l = l + 1 + if del_layout_before: + del document.body[layout_before:i] + i = layout_before + else: + document.body[i:i] = ["\\end_layout", ""] + i = i + 2 + + # Find start of layout in the inset and end of inset + j = find_token(document.body, "\\begin_layout", i) + if j == -1: + document.warning("Malformed LyX document: Missing `\\begin_layout'.") + return + k = find_end_of_inset(document.body, i) + if k == -1: + document.warning("Malformed LyX document: Missing `\\end_inset'.") + return + + # We either need to delete the following \end_layout line, or we need + # to restart the old layout if this inset is not at the paragraph end. + layout_after = find_token(document.body, "\\end_layout", k) + if layout_after == -1: + document.warning("Malformed LyX document: Missing `\\end_layout'.") + return + del_layout_after = True + l = k + 1 + while l < layout_after: + if document.body[l] != "": + del_layout_after = False + break + l = l + 1 + if del_layout_after: + del document.body[k+1:layout_after+1] + else: + document.body[k+1:k+1] = [layout_line, ""] + + # delete \begin_layout and \end_inset and replace \begin_inset with + # "\begin_layout Caption". This works because we can only have one + # paragraph in the caption inset: The old \end_layout will be recycled. + del document.body[k] + if document.body[k] == "": + del document.body[k] + del document.body[j] + if document.body[j] == "": + del document.body[j] + document.body[i] = "\\begin_layout Caption" + if document.body[i+1] == "": + del document.body[i+1] + i = i + 1 + + ## # Conversion hub # @@ -735,9 +832,11 @@ convert = [[246, []], [253, []], [254, [convert_esint]], [255, []], - [256, []]] + [256, []], + [257, [convert_caption]]] -revert = [[255, [revert_encodings]], +revert = [[256, [revert_caption]], + [255, [revert_encodings]], [254, [revert_clearpage, revert_cleardoublepage]], [253, [revert_esint]], [252, [revert_nomenclature, revert_printnomenclature]], @@ -753,3 +852,4 @@ revert = [[255, [revert_encodings]], if __name__ == "__main__": pass + diff --git a/lib/scripts/layout2layout.py b/lib/scripts/layout2layout.py index 59e43e743e..45bc499f8b 100644 --- a/lib/scripts/layout2layout.py +++ b/lib/scripts/layout2layout.py @@ -9,7 +9,7 @@ # Full author contact details are available in file CREDITS -# This script will update a .layout file to format 2 +# This script will update a .layout file to format 3 import os, re, string, sys @@ -76,6 +76,8 @@ def convert(lines): re_LabelStringAppendix = re.compile(r'^(\s*)(LabelStringAppendix)(\s+)(("[^"]+")|(\S+))', re.IGNORECASE) re_LatexType = re.compile(r'^(\s*)(LatexType)(\s+)(\S+)', re.IGNORECASE) re_Style = re.compile(r'^(\s*)(Style)(\s+)(\S+)', re.IGNORECASE) + re_CopyStyle = re.compile(r'^(\s*)(CopyStyle)(\s+)(\S+)', re.IGNORECASE) + re_NoStyle = re.compile(r'^(\s*)(NoStyle)(\s+)(\S+)', re.IGNORECASE) re_End = re.compile(r'^(\s*)(End)(\s*)$', re.IGNORECASE) # counters for sectioning styles (hardcoded in 1.3) @@ -118,6 +120,7 @@ def convert(lines): latextype_line = -1 style = "" maxcounter = 0 + format = 1 while i < len(lines): # Skip comments and empty lines @@ -129,13 +132,17 @@ def convert(lines): if (only_comment): match = re_Format.match(lines[i]) if match: - format = match.group(4) - if format == '2': + format = int(match.group(4)) + if format == 2: + lines[i] = "Format 3" + only_comment = 0 + elif format == 3: # nothing to do return - error('Cannot convert file format %s' % format) + else: + error('Cannot convert file format %s' % format) else: - lines.insert(i, "Format 2") + lines.insert(i, "Format 3") only_comment = 0 continue @@ -146,6 +153,63 @@ def convert(lines): i = i + 1 continue + if format == 2: + caption = [] + + # delete caption styles + match = re_Style.match(lines[i]) + if match: + style = string.lower(match.group(4)) + if style == "caption": + del lines[i] + while i < len(lines) and not re_End.match(lines[i]): + caption.append(lines[i]) + del lines[i] + if i == len(lines): + error('Incomplete caption style.') + else: + del lines[i] + continue + + # delete undefinition of caption styles + match = re_NoStyle.match(lines[i]) + if match: + style = string.lower(match.group(4)) + if style == "caption": + del lines[i] + continue + + # replace the CopyStyle statement with the definition of the real + # style. This may result in duplicate statements, but that is OK + # since the second one will overwrite the first one. + match = re_CopyStyle.match(lines[i]) + if match: + style = string.lower(match.group(4)) + if style == "caption": + if len(caption) > 0: + lines[i:i+1] = caption + else: + # FIXME: This style comes from an include file, we + # should replace the real style and not this default. + lines[i:i+1] = [' Margin First_Dynamic', + ' LatexType Command', + ' LatexName caption', + ' NeedProtect 1', + ' LabelSep xx', + ' ParSkip 0.4', + ' TopSep 0.5', + ' Align Center', + ' AlignPossible Center', + ' LabelType Sensitive', + ' LabelString "Senseless!"', + ' OptionalArgs 1', + ' LabelFont', + ' Series Bold', + ' EndFont'] + + i = i + 1 + continue + # Delete MaxCounter and remember the value of it match = re_MaxCounter.match(lines[i]) if match: diff --git a/lib/ui/stdmenus.inc b/lib/ui/stdmenus.inc index 4afd5a9f41..e3afda5d4a 100644 --- a/lib/ui/stdmenus.inc +++ b/lib/ui/stdmenus.inc @@ -298,6 +298,7 @@ Menuset Item "Citation...|C" "dialog-show-new-inset citation" Item "Cross-Reference...|R" "dialog-show-new-inset ref" Item "Label...|L" "label-insert" + Item "Caption..." "caption-insert" Item "Index Entry|d" "index-insert" Item "Glossary Entry|y" "nomencl-insert" Separator diff --git a/src/buffer.C b/src/buffer.C index 2630fc4b8e..bdb0821ed2 100644 --- a/src/buffer.C +++ b/src/buffer.C @@ -141,7 +141,7 @@ using std::string; namespace { -int const LYX_FORMAT = 256; +int const LYX_FORMAT = 257; } // namespace anon diff --git a/src/buffer_funcs.C b/src/buffer_funcs.C index 52f9b6f5e3..0429580415 100644 --- a/src/buffer_funcs.C +++ b/src/buffer_funcs.C @@ -38,6 +38,7 @@ #include "frontends/Alert.h" #include "insets/insetbibitem.h" +#include "insets/insetcaption.h" #include "insets/insetinclude.h" #include "support/filetools.h" @@ -351,6 +352,67 @@ bool needEnumCounterReset(ParIterator const & it) } +void setCaptionLabels(InsetBase & inset, Floating const & fl, + Counters & counters) +{ + LyXText * text = inset.getText(0); + if (!text) + return; + + ParagraphList & pars = text->paragraphs(); + if (pars.empty()) + return; + + // FIXME UNICODE + docstring const counter = from_ascii(fl.type()); + docstring const label = from_utf8(fl.name()); + + ParagraphList::iterator p = pars.begin(); + for (; p != pars.end(); ++p) { + InsetList::iterator it2 = p->insetlist.begin(); + InsetList::iterator end2 = p->insetlist.end(); + // Any caption within this float should have the same + // label prefix but different numbers. + for (; it2 != end2; ++it2) { + InsetBase & icap = *it2->inset; + // Look deeper just in case. + setCaptionLabels(icap, fl, counters); + if (icap.lyxCode() == InsetBase::CAPTION_CODE) { + // We found a caption! + counters.step(counter); + int number = counters.value(counter); + static_cast(icap).setCount(number); + static_cast(icap).setLabel(label); + } + } + } +} + + +void setCaptions(Paragraph & par, LyXTextClass const & textclass) +{ + if (par.insetlist.empty()) + return; + + Counters & counters = textclass.counters(); + + InsetList::iterator it = par.insetlist.begin(); + InsetList::iterator end = par.insetlist.end(); + for (; it != end; ++it) { + InsetBase & inset = *it->inset; + if (inset.lyxCode() != InsetBase::FLOAT_CODE + && inset.lyxCode() != InsetBase::WRAP_CODE) + continue; + + docstring const & type = inset.getInsetName(); + if (type.empty()) + continue; + + Floating const & fl = textclass.floats().getType(to_ascii(type)); + setCaptionLabels(inset, fl, counters); + } +} + // set the label of a paragraph. This includes the counters. void setLabel(Buffer const & buf, ParIterator & it, LyXTextClass const & textclass) { @@ -602,6 +664,11 @@ void updateLabels(Buffer const & buf, bool childonly) // set the counter for this paragraph setLabel(buf, it, textclass); + // It is better to set the captions after setLabel because + // the caption number might need the section number in the + // future. + setCaptions(*it, textclass); + // Now included docs InsetList::const_iterator iit = it->insetlist.begin(); InsetList::const_iterator end = it->insetlist.end(); diff --git a/src/insets/insetcaption.C b/src/insets/insetcaption.C index 55566f8dae..ed0a121a57 100644 --- a/src/insets/insetcaption.C +++ b/src/insets/insetcaption.C @@ -21,9 +21,12 @@ #include "BufferView.h" #include "Floating.h" #include "FloatList.h" +#include "funcrequest.h" +#include "FuncStatus.h" #include "gettext.h" #include "LColor.h" #include "metricsinfo.h" +#include "output_latex.h" #include "paragraph.h" #include "frontends/FontMetrics.h" @@ -90,44 +93,24 @@ void InsetCaption::cursorPos(BufferView const & bv, } -void InsetCaption::setLabel(LCursor & cur) const +void InsetCaption::setLabel(docstring const & label) { - // Set caption label _only_ if the cursor is in _this_ float: - if (cur.top().text() == &text_) { - string s; - size_t i = cur.depth(); - while (i > 0) { - --i; - InsetBase * const in = &cur[i].inset(); - if (in->lyxCode() == InsetBase::FLOAT_CODE || - in->lyxCode() == InsetBase::WRAP_CODE) { - s = to_utf8(in->getInsetName()); - break; - } - } - Floating const & fl = textclass_.floats().getType(s); - s = fl.name(); - docstring num; - if (s.empty()) - s = "Senseless"; - else - num = convert(counter_); - - // Generate the label - label = bformat(from_ascii("%1$s %2$s:"), _(s), num); - } + label_ = _(to_ascii(label)); } bool InsetCaption::metrics(MetricsInfo & mi, Dimension & dim) const { mi.base.textwidth -= 2 * TEXT_TO_INSET_OFFSET; - LCursor cur = mi.base.bv->cursor(); - setLabel(cur); - labelwidth_ = theFontMetrics(mi.base.font).width(label); + docstring const number = convert(counter_); + full_label_ = bformat(from_ascii("%1$s %2$s:"), label_, number); + labelwidth_ = theFontMetrics(mi.base.font).width(full_label_); dim.wid = labelwidth_; Dimension textdim; InsetText::metrics(mi, textdim); + // Correct for button width, and re-fit + mi.base.textwidth -= dim.wid; + InsetText::metrics(mi, textdim); dim.des = std::max(dim.des - textdim.asc + dim.asc, textdim.des); dim.asc = textdim.asc; dim.wid += textdim.wid; @@ -149,11 +132,9 @@ void InsetCaption::draw(PainterInfo & pi, int x, int y) const // the text inset or the paragraph? // We should also draw the float number (Lgb) - // See if we can find the name of the float this caption - // belongs to. - LCursor cur = pi.base.bv->cursor(); - setLabel(cur); - labelwidth_ = pi.pain.text(x, y, label, pi.base.font); + // Answer: the text inset (in buffer_funcs.C: setCaption). + + labelwidth_ = pi.pain.text(x, y, full_label_, pi.base.font); InsetText::draw(pi, x + labelwidth_, y); setPosCache(pi, x, y); } @@ -173,6 +154,31 @@ InsetBase * InsetCaption::editXY(LCursor & cur, int x, int y) } +bool InsetCaption::getStatus(LCursor & cur, FuncRequest const & cmd, + FuncStatus & status) const +{ + switch (cmd.action) { + + case LFUN_CAPTION_INSERT: + case LFUN_FLOAT_INSERT: + case LFUN_FLOAT_WIDE_INSERT: + case LFUN_WRAP_INSERT: + case LFUN_PARAGRAPH_MOVE_UP: + case LFUN_PARAGRAPH_MOVE_DOWN: + case LFUN_BREAK_PARAGRAPH: + case LFUN_BREAK_PARAGRAPH_KEEP_LAYOUT: + case LFUN_BREAK_PARAGRAPH_SKIP: + case LFUN_PARAGRAPH_SPACING: + case LFUN_PAGEBREAK_INSERT: + status.enabled(false); + return true; + + default: + return InsetText::getStatus(cur, cmd, status); + } +} + + int InsetCaption::latex(Buffer const & buf, odocstream & os, OutputParams const & runparams) const { @@ -181,18 +187,20 @@ int InsetCaption::latex(Buffer const & buf, odocstream & os, // This code is currently only able to handle the simple // \caption{...}, later we will make it take advantage // of the one of the caption packages. (Lgb) - odocstringstream ost; - int const l = InsetText::latex(buf, ost, runparams); - os << "\\caption{" << ost.str() << "}\n"; + os << "\\caption"; + int l = latexOptArgInsets(buf, paragraphs()[0], os, runparams, 1); + os << '{'; + l += InsetText::latex(buf, os, runparams); + os << "}\n"; return l + 1; } -int InsetCaption::plaintext(Buffer const & /*buf*/, odocstream & /*os*/, - OutputParams const & /*runparams*/) const +int InsetCaption::plaintext(Buffer const & buf, odocstream & os, + OutputParams const & runparams) const { - // FIXME: Implement me! - return 0; + os << full_label_ << ' '; + return InsetText::plaintext(buf, os, runparams); } diff --git a/src/insets/insetcaption.h b/src/insets/insetcaption.h index 310b0e0fd1..0640bea9d6 100644 --- a/src/insets/insetcaption.h +++ b/src/insets/insetcaption.h @@ -12,7 +12,6 @@ #ifndef INSETCAPTION_H #define INSETCAPTION_H - #include "insettext.h" #include "lyxtextclass.h" @@ -26,6 +25,8 @@ public: /// InsetCaption(BufferParams const &); /// + virtual ~InsetCaption() {} + /// void write(Buffer const & buf, std::ostream & os) const; /// void read(Buffer const & buf, LyXLex & lex); @@ -51,6 +52,10 @@ public: /// virtual InsetBase * editXY(LCursor & cur, int x, int y); /// + virtual bool getStatus(LCursor & cur, FuncRequest const & cmd, FuncStatus &) const; + /// + virtual bool wide() const { return false; } + /// virtual int latex(Buffer const & buf, odocstream & os, OutputParams const &) const; /// @@ -61,17 +66,20 @@ public: OutputParams const & runparams) const; /// void setCount(int c) { counter_ = c; } -private: /// - void setLabel(LCursor & cur) const; + void setLabel(docstring const & label); + +private: /// virtual std::auto_ptr doClone() const; /// - mutable docstring label; + mutable docstring full_label_; /// mutable int labelwidth_; /// - mutable int counter_; + docstring label_; + /// + int counter_; /// LyXTextClass const & textclass_; }; diff --git a/src/insets/insettext.h b/src/insets/insettext.h index b5a4531f17..6b7d356348 100644 --- a/src/insets/insettext.h +++ b/src/insets/insettext.h @@ -43,6 +43,9 @@ public: explicit InsetText(BufferParams const &); /// InsetText(); + /// + virtual ~InsetText() {} + /// empty inset to empty par void clear(); /// @@ -98,7 +101,7 @@ public: return (i == 0) ? const_cast(&text_) : 0; } /// - bool getStatus(LCursor & cur, FuncRequest const & cmd, FuncStatus &) const; + virtual bool getStatus(LCursor & cur, FuncRequest const & cmd, FuncStatus &) const; /// set the change for the entire inset void setChange(Change const & change); @@ -133,7 +136,7 @@ public: /// InsetText(InsetText const &); /// - bool wide() const { return wide_inset_; } + virtual bool wide() const { return wide_inset_; } /// void setWide(bool wide_inset) { wide_inset_ = wide_inset; } diff --git a/src/lyxtextclass.C b/src/lyxtextclass.C index 71e825483d..cdda271a71 100644 --- a/src/lyxtextclass.C +++ b/src/lyxtextclass.C @@ -65,7 +65,7 @@ private: }; -int const FORMAT = 2; +int const FORMAT = 3; bool layout2layout(FileName const & filename, FileName const & tempfile) diff --git a/src/output_latex.C b/src/output_latex.C index e78773eea6..51843b7019 100644 --- a/src/output_latex.C +++ b/src/output_latex.C @@ -83,10 +83,6 @@ TeXDeeper(Buffer const & buf, } -int latexOptArgInsets(Buffer const & buf, Paragraph const & par, - odocstream & os, OutputParams const & runparams, int number); - - ParagraphList::const_iterator TeXEnvironment(Buffer const & buf, ParagraphList const & paragraphs, @@ -212,6 +208,8 @@ TeXEnvironment(Buffer const & buf, return par; } +} + int latexOptArgInsets(Buffer const & buf, Paragraph const & par, odocstream & os, OutputParams const & runparams, int number) @@ -232,6 +230,8 @@ int latexOptArgInsets(Buffer const & buf, Paragraph const & par, } +namespace { + ParagraphList::const_iterator TeXOnePar(Buffer const & buf, ParagraphList const & paragraphs, diff --git a/src/output_latex.h b/src/output_latex.h index 5544a63356..ca6618c7a7 100644 --- a/src/output_latex.h +++ b/src/output_latex.h @@ -25,6 +25,11 @@ class Encoding; class OutputParams; class TexRow; +/// Export up to \p number optarg insets +int latexOptArgInsets(Buffer const & buf, Paragraph const & par, + odocstream & os, OutputParams const & runparams, + int number); + /** Export \p paragraphs of buffer \p buf to LaTeX. Don't use a temporary stringstream for \p os if the final output is supposed to go to a file. diff --git a/src/text3.C b/src/text3.C index 0646847ebd..3973d08ccc 100644 --- a/src/text3.C +++ b/src/text3.C @@ -1127,8 +1127,8 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd) #if 0 case LFUN_LIST_INSERT: case LFUN_THEOREM_INSERT: - case LFUN_CAPTION_INSERT: #endif + case LFUN_CAPTION_INSERT: case LFUN_NOTE_INSERT: case LFUN_CHARSTYLE_INSERT: case LFUN_BOX_INSERT: @@ -1159,9 +1159,8 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd) case LFUN_WRAP_INSERT: doInsertInset(cur, this, cmd, true, true); cur.posRight(); - // FIXME: the "Caption" name should not be hardcoded, - // but given by the float definition. - cur.dispatch(FuncRequest(LFUN_LAYOUT, "Caption")); + cur.dispatch(FuncRequest(LFUN_CAPTION_INSERT)); + updateLabels(cur.buffer()); break; case LFUN_INDEX_INSERT: -- 2.39.2