From 46cbd6d234c67facb375f18984645299fcc76ef4 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Sun, 15 Nov 2020 03:03:16 +0100 Subject: [PATCH] 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. --- src/insets/InsetCaptionable.cpp | 52 ++++++++++++++++++++++-- src/insets/InsetCaptionable.h | 3 ++ src/insets/InsetFloat.cpp | 72 ++------------------------------- src/insets/InsetListings.cpp | 45 +-------------------- 4 files changed, 57 insertions(+), 115 deletions(-) diff --git a/src/insets/InsetCaptionable.cpp b/src/insets/InsetCaptionable.cpp index a8a2108ce9..474eaf059e 100644 --- a/src/insets/InsetCaptionable.cpp +++ b/src/insets/InsetCaptionable.cpp @@ -13,9 +13,10 @@ #include +#include "InsetBox.h" #include "InsetCaptionable.h" - #include "InsetCaption.h" +#include "InsetLabel.h" #include "Buffer.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(inset)) { + continue; + } + + // Maybe an inset is directly a label, in which case no more work is needed. + if (inset && dynamic_cast(inset)) + return dynamic_cast(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(inset)) + continue; + + auto insetAsText = dynamic_cast(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(insetIn)) { + return dynamic_cast(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 { InsetCaption const * ins = getCaptionInset(); - if (ins == 0) + if (!ins) return docstring(); odocstringstream ods; diff --git a/src/insets/InsetCaptionable.h b/src/insets/InsetCaptionable.h index aa9a4cc426..ac11f55ca2 100644 --- a/src/insets/InsetCaptionable.h +++ b/src/insets/InsetCaptionable.h @@ -21,6 +21,7 @@ namespace lyx { class InsetCaption; +class InsetLabel; class InsetCaptionable : public InsetCollapsible { @@ -36,6 +37,8 @@ protected: /// InsetCaption const * getCaptionInset() const; /// + InsetLabel const * getLabelInset() const; + /// docstring getCaptionText(OutputParams const &) const; /// docstring getCaptionHTML(OutputParams const &) const; diff --git a/src/insets/InsetFloat.cpp b/src/insets/InsetFloat.cpp index 86e3f9b338..f486fc7980 100644 --- a/src/insets/InsetFloat.cpp +++ b/src/insets/InsetFloat.cpp @@ -514,63 +514,6 @@ std::vector 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(inset)) { - continue; - } - - // Maybe an inset is directly a label, in which case no more work is needed. - if (inset && dynamic_cast(inset)) - return dynamic_cast(inset); - - // More likely, the label is hidden in an inset of a paragraph (only if a subtype of InsetText). - if (!dynamic_cast(inset)) - continue; - - auto insetAsText = dynamic_cast(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(insetIn)) { - return dynamic_cast(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(inset)) - continue; - - if (inset && dynamic_cast(inset)) - return dynamic_cast(inset); - } - - return nullptr; -} - - /// Takes an unstructured subfigure container (typically, an InsetBox) and find the elements within: /// actual content (image or table), maybe a caption, maybe a label. std::tuple 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 { - // Determine whether the float has a title or not. For this, iterate through the paragraphs and look - // for an InsetCaption. Do the same for labels and subfigures. - // The caption and the label for each subfigure is handled by recursive calls. - const InsetCaption* caption = nullptr; - const InsetLabel* label = nullptr; - std::vector subfigures; + const InsetCaption* caption = getCaptionInset(); + const InsetLabel* label = getLabelInset(); + // Determine whether the float has subfigures. + std::vector subfigures; auto end = paragraphs().end(); for (auto it = paragraphs().begin(); it != end; ++it) { std::vector foundSubfigures = findSubfiguresInParagraph(*it); @@ -828,11 +769,6 @@ void InsetFloat::docbook(XMLStream & xs, OutputParams const & runparams) const subfigures.reserve(subfigures.size() + foundSubfigures.size()); 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. diff --git a/src/insets/InsetListings.cpp b/src/insets/InsetListings.cpp index cff7bcc9c1..7ac940d742 100644 --- a/src/insets/InsetListings.cpp +++ b/src/insets/InsetListings.cpp @@ -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(inset)) - return dynamic_cast(inset); - - // More likely, the label is hidden in an inset of a paragraph (only if a subtype of InsetText). - if (!dynamic_cast(inset)) - continue; - - auto insetAsText = dynamic_cast(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(insetIn)) { - return dynamic_cast(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 { 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. InsetCaption const * caption = getCaptionInset(); if (caption) { - // Find the label in the caption, if any. - InsetLabel const * label; - auto const end = caption->paragraphs().end(); - for (auto it = caption->paragraphs().begin(); it != end; ++it) { - label = findLabelInParagraph(*it); - if (label) - break; - } + InsetLabel const * label = getLabelInset(); // Ensure that the label will not be output a second time as an anchor. OutputParams rpNoLabel = rp;