DocBook: refactor code about retrieving captions and labels.

There was already an existing method in InsetCaptionable for captions, but not yet for labels. It was at least already useful at two places, that's why I moved it to InsetCaptionable.
This commit is contained in:
Thibaut Cuvelier 2020-11-15 03:03:16 +01:00
parent c4bbff8ecb
commit 46cbd6d234
4 changed files with 57 additions and 115 deletions

View File

@ -13,9 +13,10 @@
#include <config.h> #include <config.h>
#include "InsetBox.h"
#include "InsetCaptionable.h" #include "InsetCaptionable.h"
#include "InsetCaption.h" #include "InsetCaption.h"
#include "InsetLabel.h"
#include "Buffer.h" #include "Buffer.h"
#include "BufferParams.h" #include "BufferParams.h"
@ -64,14 +65,59 @@ InsetCaption const * InsetCaptionable::getCaptionInset() const
} }
} }
} }
return 0; return nullptr;
}
InsetLabel const * InsetCaptionable::getLabelInset() const
{
// A wrong hypothesis would be to limit the search to the caption: it is most likely there, but not necessarily!
// Iterate through the contents of the inset.
auto const end = paragraphs().end();
for (auto par = paragraphs().begin(); par != end; ++par) {
for (pos_type pos = 0; pos < par->size(); ++pos) {
const Inset * inset = par->getInset(pos);
// If this inset is a subfigure, skip it. Otherwise, you would return the label for the subfigure.
if (dynamic_cast<const InsetBox *>(inset)) {
continue;
}
// Maybe an inset is directly a label, in which case no more work is needed.
if (inset && dynamic_cast<const InsetLabel *>(inset))
return dynamic_cast<const InsetLabel *>(inset);
// More likely, the label is hidden in an inset of a paragraph (only if a subtype of InsetText). Thus,
// dig into that text.
if (!dynamic_cast<const InsetText *>(inset))
continue;
auto insetAsText = dynamic_cast<const InsetText *>(inset);
auto itIn = insetAsText->paragraphs().begin();
auto endIn = insetAsText->paragraphs().end();
for (; itIn != endIn; ++itIn) {
for (pos_type posIn = 0; posIn < itIn->size(); ++posIn) {
const Inset *insetIn = itIn->getInset(posIn);
if (insetIn && dynamic_cast<const InsetLabel *>(insetIn)) {
return dynamic_cast<const InsetLabel *>(insetIn);
}
}
}
// Obviously, this solution does not scale with more levels of paragraphs and insets, but this should
// be enough: it is only used in captions.
}
}
return nullptr;
} }
docstring InsetCaptionable::getCaptionText(OutputParams const & runparams) const docstring InsetCaptionable::getCaptionText(OutputParams const & runparams) const
{ {
InsetCaption const * ins = getCaptionInset(); InsetCaption const * ins = getCaptionInset();
if (ins == 0) if (!ins)
return docstring(); return docstring();
odocstringstream ods; odocstringstream ods;

View File

@ -21,6 +21,7 @@
namespace lyx { namespace lyx {
class InsetCaption; class InsetCaption;
class InsetLabel;
class InsetCaptionable : public InsetCollapsible class InsetCaptionable : public InsetCollapsible
{ {
@ -36,6 +37,8 @@ protected:
/// ///
InsetCaption const * getCaptionInset() const; InsetCaption const * getCaptionInset() const;
/// ///
InsetLabel const * getLabelInset() const;
///
docstring getCaptionText(OutputParams const &) const; docstring getCaptionText(OutputParams const &) const;
/// ///
docstring getCaptionHTML(OutputParams const &) const; docstring getCaptionHTML(OutputParams const &) const;

View File

@ -514,63 +514,6 @@ std::vector<const InsetCollapsible *> findSubfiguresInParagraph(const Paragraph
} }
namespace {
const InsetLabel* findLabelInParagraph(const Paragraph &par)
{
for (pos_type pos = 0; pos < par.size(); ++pos) {
// If this inset is a subfigure, skip it.
const Inset *inset = par.getInset(pos);
if (dynamic_cast<const InsetBox *>(inset)) {
continue;
}
// Maybe an inset is directly a label, in which case no more work is needed.
if (inset && dynamic_cast<const InsetLabel *>(inset))
return dynamic_cast<const InsetLabel *>(inset);
// More likely, the label is hidden in an inset of a paragraph (only if a subtype of InsetText).
if (!dynamic_cast<const InsetText *>(inset))
continue;
auto insetAsText = dynamic_cast<const InsetText *>(inset);
auto itIn = insetAsText->paragraphs().begin();
auto endIn = insetAsText->paragraphs().end();
for (; itIn != endIn; ++itIn) {
for (pos_type posIn = 0; posIn < itIn->size(); ++posIn) {
const Inset *insetIn = itIn->getInset(posIn);
if (insetIn && dynamic_cast<const InsetLabel *>(insetIn)) {
return dynamic_cast<const InsetLabel *>(insetIn);
}
}
}
// Obviously, this solution does not scale with more levels of paragraphs-insets, but this should be enough.
}
return nullptr;
}
} // anonymous namespace
const InsetCaption* findCaptionInParagraph(const Paragraph &par)
{
// Don't dive too deep, otherwise, this could be a subfigure caption.
for (pos_type pos = 0; pos < par.size(); ++pos) {
// If this inset is a subfigure, skip it.
const Inset *inset = par.getInset(pos);
if (dynamic_cast<const InsetBox *>(inset))
continue;
if (inset && dynamic_cast<const InsetCaption *>(inset))
return dynamic_cast<const InsetCaption *>(inset);
}
return nullptr;
}
/// Takes an unstructured subfigure container (typically, an InsetBox) and find the elements within: /// Takes an unstructured subfigure container (typically, an InsetBox) and find the elements within:
/// actual content (image or table), maybe a caption, maybe a label. /// actual content (image or table), maybe a caption, maybe a label.
std::tuple<InsetCode, const Inset *, const InsetCaption *, const InsetLabel *> docbookParseHopelessSubfigure(const InsetText * subfigure) std::tuple<InsetCode, const Inset *, const InsetCaption *, const InsetLabel *> docbookParseHopelessSubfigure(const InsetText * subfigure)
@ -814,13 +757,11 @@ void docbookNoSubfigures(XMLStream & xs, OutputParams const & runparams, const I
void InsetFloat::docbook(XMLStream & xs, OutputParams const & runparams) const void InsetFloat::docbook(XMLStream & xs, OutputParams const & runparams) const
{ {
// Determine whether the float has a title or not. For this, iterate through the paragraphs and look const InsetCaption* caption = getCaptionInset();
// for an InsetCaption. Do the same for labels and subfigures. const InsetLabel* label = getLabelInset();
// The caption and the label for each subfigure is handled by recursive calls.
const InsetCaption* caption = nullptr;
const InsetLabel* label = nullptr;
std::vector<const InsetCollapsible *> subfigures;
// Determine whether the float has subfigures.
std::vector<const InsetCollapsible *> subfigures;
auto end = paragraphs().end(); auto end = paragraphs().end();
for (auto it = paragraphs().begin(); it != end; ++it) { for (auto it = paragraphs().begin(); it != end; ++it) {
std::vector<const InsetCollapsible *> foundSubfigures = findSubfiguresInParagraph(*it); std::vector<const InsetCollapsible *> foundSubfigures = findSubfiguresInParagraph(*it);
@ -828,11 +769,6 @@ void InsetFloat::docbook(XMLStream & xs, OutputParams const & runparams) const
subfigures.reserve(subfigures.size() + foundSubfigures.size()); subfigures.reserve(subfigures.size() + foundSubfigures.size());
subfigures.insert(subfigures.end(), foundSubfigures.begin(), foundSubfigures.end()); subfigures.insert(subfigures.end(), foundSubfigures.begin(), foundSubfigures.end());
} }
if (!caption)
caption = findCaptionInParagraph(*it);
if (!label)
label = findLabelInParagraph(*it);
} }
// Gather a few things from global environment that are shared between all following cases. // Gather a few things from global environment that are shared between all following cases.

View File

@ -482,42 +482,6 @@ docstring InsetListings::xhtml(XMLStream & os, OutputParams const & rp) const
} }
namespace {
const InsetLabel* findLabelInParagraph(const Paragraph &par)
{
for (pos_type pos = 0; pos < par.size(); ++pos) {
const Inset *inset = par.getInset(pos);
// Maybe an inset is directly a label, in which case no more work is needed.
if (inset && dynamic_cast<const InsetLabel *>(inset))
return dynamic_cast<const InsetLabel *>(inset);
// More likely, the label is hidden in an inset of a paragraph (only if a subtype of InsetText).
if (!dynamic_cast<const InsetText *>(inset))
continue;
auto insetAsText = dynamic_cast<const InsetText *>(inset);
auto itIn = insetAsText->paragraphs().begin();
auto endIn = insetAsText->paragraphs().end();
for (; itIn != endIn; ++itIn) {
for (pos_type posIn = 0; posIn < itIn->size(); ++posIn) {
const Inset *insetIn = itIn->getInset(posIn);
if (insetIn && dynamic_cast<const InsetLabel *>(insetIn)) {
return dynamic_cast<const InsetLabel *>(insetIn);
}
}
}
// Obviously, this solution does not scale with more levels of paragraphs-insets, but this should be enough.
}
return nullptr;
}
} // anonymous namespace
void InsetListings::docbook(XMLStream & xs, OutputParams const & rp) const void InsetListings::docbook(XMLStream & xs, OutputParams const & rp) const
{ {
InsetLayout const & il = getLayout(); InsetLayout const & il = getLayout();
@ -531,14 +495,7 @@ void InsetListings::docbook(XMLStream & xs, OutputParams const & rp) const
// TODO: parts of this code could be merged with InsetFloat and findLabelInParagraph. // TODO: parts of this code could be merged with InsetFloat and findLabelInParagraph.
InsetCaption const * caption = getCaptionInset(); InsetCaption const * caption = getCaptionInset();
if (caption) { if (caption) {
// Find the label in the caption, if any. InsetLabel const * label = getLabelInset();
InsetLabel const * label;
auto const end = caption->paragraphs().end();
for (auto it = caption->paragraphs().begin(); it != end; ++it) {
label = findLabelInParagraph(*it);
if (label)
break;
}
// Ensure that the label will not be output a second time as an anchor. // Ensure that the label will not be output a second time as an anchor.
OutputParams rpNoLabel = rp; OutputParams rpNoLabel = rp;