Am Samstag, 27. Januar 2007 13:10 schrieb Abdelrazak Younes: > Jürgen Spitzmüller wrote: > > Am Freitag, 26. Januar 2007 22:57 schrieb Abdelrazak Younes: > >> 1) LateX doesn't accept multiple lines caption so we might have to > >> forbid that I guess. > > > > I think a line break is allowed, but no paragraph break. > > What is a line break? If it is mean the one with Ctrl-Enter, LateX does > not like it. If you mean normal row-breaking (word-wrap), that is OK > with LateX. > > > > >> 2) If you put multiple captions inside a same float, they are numbered > >> sequentially even though they refer to the same float. I guess I should > >> update my patch accordingly... What do you think? > > > > You should do what the LaTeX output does > > Yes, that's what I've done in my latest patch for 2). I don't know how > to fix 1).
suppress the corresponding lfuns in getStatus (look at the ERT inset). > > (you are aware of subfig?). > > Never used it but yes. Do we need to do something special for this? No. This is orthogonal. > Anyway, here's an updated patch that mostly fix the text flowing issue. > The only remaining issues are: > * major one: lyx2lyx support: Georg promised to do it soon > * minor one: the red frame around the caption is not drawn correctly if > there's more than one caption in the same float. > > Georg, if you're going to do the lyx2lyx support, please take the patch > and commit it at the same time. Here is the complete patch, but I discovered some problems that need to be solved before it can go in: - You deleted some (but not all) code that handles LABEL_SENSITIVE. I reverted that, since we have other caption-like styles in layout files that still need to work. - The patch breaks optional arguments of captions. The most simple way to fix that would be to check for InsetOptArg at the first paragraph position in InsetCaption::latex(), and get the optional argument with latexOptional() if there is one. This would not need any lyx2lyx change. Of course it would also be possible to transfer the optional argument to the caption inset, but I don't know a good UI. - AFAIK not all layouts have a caption style, but with this patch we allow captions in any documents. Is this a problem? - In order to really fix bug 675 (Which started this thing) we need to implement InsetCaption::getStatus() and disable several lfuns. Once the optional argument question is answered we can put this in and do the rest later. Georg
Index: src/insets/insetcaption.C
===================================================================
--- src/insets/insetcaption.C (Revision 16882)
+++ src/insets/insetcaption.C (Arbeitskopie)
@@ -90,44 +90,24 @@ void InsetCaption::cursorPos(BufferView
}
-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<docstring>(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<docstring>(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 +129,9 @@ void InsetCaption::draw(PainterInfo & pi
// 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);
}
Index: src/insets/insetcaption.h
===================================================================
--- src/insets/insetcaption.h (Revision 16882)
+++ src/insets/insetcaption.h (Arbeitskopie)
@@ -12,7 +12,6 @@
#ifndef INSETCAPTION_H
#define INSETCAPTION_H
-
#include "insettext.h"
#include "lyxtextclass.h"
@@ -61,17 +60,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<InsetBase> doClone() const;
///
- mutable docstring label;
+ mutable docstring full_label_;
///
mutable int labelwidth_;
///
- mutable int counter_;
+ docstring label_;
+ ///
+ int counter_;
///
LyXTextClass const & textclass_;
};
Index: src/buffer.C
===================================================================
--- src/buffer.C (Revision 16882)
+++ src/buffer.C (Arbeitskopie)
@@ -141,7 +141,7 @@ using std::string;
namespace {
-int const LYX_FORMAT = 256;
+int const LYX_FORMAT = 257;
} // namespace anon
Index: src/text3.C
===================================================================
--- src/text3.C (Revision 16882)
+++ src/text3.C (Arbeitskopie)
@@ -1127,8 +1127,8 @@ void LyXText::dispatch(LCursor & cur, Fu
#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, Fu
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:
Index: src/lyxtextclass.C
===================================================================
--- src/lyxtextclass.C (Revision 16882)
+++ src/lyxtextclass.C (Arbeitskopie)
@@ -65,7 +65,7 @@ private:
};
-int const FORMAT = 2;
+int const FORMAT = 3;
bool layout2layout(FileName const & filename, FileName const & tempfile)
Index: src/buffer_funcs.C
===================================================================
--- src/buffer_funcs.C (Revision 16882)
+++ src/buffer_funcs.C (Arbeitskopie)
@@ -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 co
}
+void setCaptionLabels(InsetBase & inset, Floating const & fl,
+ Counters & counters)
+{
+ if (!inset.getText(0))
+ return;
+
+ // All caption within this inset will have the same label and number.
+ ParagraphList & pars = inset.getText(0)->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 and number.
+ 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<InsetCaption &>(icap).setCount(number);
+ static_cast<InsetCaption &>(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, bo
// 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();
Index: lib/scripts/layout2layout.py
===================================================================
--- lib/scripts/layout2layout.py (Revision 16882)
+++ lib/scripts/layout2layout.py (Arbeitskopie)
@@ -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:
Index: lib/lyx2lyx/LyX.py
===================================================================
--- lib/lyx2lyx/LyX.py (Revision 16882)
+++ lib/lyx2lyx/LyX.py (Arbeitskopie)
@@ -73,7 +73,7 @@ format_relation = [("0_06", [200], ge
("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():
Index: lib/lyx2lyx/lyx_1_5.py
===================================================================
--- lib/lyx2lyx/lyx_1_5.py (Revision 16882)
+++ lib/lyx2lyx/lyx_1_5.py (Arbeitskopie)
@@ -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]],
caption-test.lyx
Description: application/lyx
