diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 6f339e51e1..56b5ca6c02 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -1283,8 +1283,15 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; case LFUN_REFERENCE_TO_PARAGRAPH: { - int const id = convert(cmd.getArg(0)); - flag.setEnabled(id >= 0); + vector const pids = getVectorFromString(cmd.getArg(0)); + for (string const & s : pids) { + int const id = convert(s); + if (id < 0) { + flag.setEnabled(false); + break; + } + } + flag.setEnabled(true); break; } @@ -1648,42 +1655,59 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) } case LFUN_REFERENCE_TO_PARAGRAPH: { - int const id = convert(cmd.getArg(0)); + vector const pids = getVectorFromString(cmd.getArg(0)); + string const type = cmd.getArg(1); + int id = convert(pids.front()); if (id < 0) break; - string const type = cmd.getArg(1); int i = 0; for (Buffer * b = &buffer_; i == 0 || b != &buffer_; b = theBufferList().next(b)) { - DocIterator const dit = b->getParFromID(id); + DocIterator dit = b->getParFromID(id); if (dit.empty()) { LYXERR(Debug::INFO, "No matching paragraph found! [" << id << "]."); ++i; continue; } - string const label = dit.innerParagraph().getLabelForXRef(); + string label = dit.innerParagraph().getLabelForXRef(); if (!label.empty()) { // if the paragraph has a label, we refer to this string const arg = (type.empty()) ? label : label + " " + type; lyx::dispatch(FuncRequest(LFUN_REFERENCE_INSERT, arg)); break; } else { - // if there is not a label yet, go to the paragraph ... + // if there is not a label yet, or we do not see it + // (since it is in a different buffer), + // go to the paragraph (including nested insets) ... lyx::dispatch(FuncRequest(LFUN_BOOKMARK_SAVE, "0")); - lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_GOTO, cmd.argument())); - // ... insert the label - // we do not want to open the dialog, hence we - // do not employ LFUN_LABEL_INSERT - InsetCommandParams p(LABEL_CODE); - docstring const label = dit.getPossibleLabel(); - p["name"] = label; - string const data = InsetCommand::params2string(p); - lyx::dispatch(FuncRequest(LFUN_INSET_INSERT, data)); + for (string const & s : pids) { + id = convert(s); + if (id < 0) + break; + dit = b->getParFromID(id); + lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_GOTO, s)); + } + // ... and try again if we find a label ... + label = dit.innerParagraph().getLabelForXRef(); + string arg; + if (!label.empty()) { + // if the paragraph has a label, we refer to this + arg = (type.empty()) ? label : label + " " + type; + } else { + // ... if not, insert a new label + // we do not want to open the dialog, hence we + // do not employ LFUN_LABEL_INSERT + InsetCommandParams p(LABEL_CODE); + docstring const new_label = dit.getPossibleLabel(); + p["name"] = new_label; + string const data = InsetCommand::params2string(p); + lyx::dispatch(FuncRequest(LFUN_INSET_INSERT, data)); + arg = (type.empty()) ? to_utf8(new_label) + : to_utf8(new_label) + " " + type; + } // ... and go back to the original position lyx::dispatch(FuncRequest(LFUN_BOOKMARK_GOTO, "0")); // ... to insert the ref - string const arg = (type.empty()) ? to_utf8(label) - : to_utf8(label) + " " + type; lyx::dispatch(FuncRequest(LFUN_REFERENCE_INSERT, arg)); break; } diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index 6ac454d715..d9218f4c7e 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -3537,8 +3537,9 @@ void LyXAction::init() * \li Notion: The function checks of the paragraph already has a label. * If so, it uses that. Otherwise it inserts a label and uses this. * \li Syntax: reference-to-paragraph [] - * \li Params: : paragraph id \n - : cross-references type + * \li Params: : paragraph ids, might be a comma-separated list\n + * if it is in a nested inset\n + * : cross-references type * \li Origin: spitz, 28 Jul 2024 * \endvar */ diff --git a/src/TocBackend.h b/src/TocBackend.h index 7ad36fec66..68eb825c6d 100644 --- a/src/TocBackend.h +++ b/src/TocBackend.h @@ -75,17 +75,22 @@ public: /// docstring const & prettyStr() const { return pretty_str_; } /// - void prettyStr (docstring const & s) { pretty_str_ = s; } + void prettyStr(docstring const & s) { pretty_str_ = s; } /// bool isOutput() const { return output_; } /// bool isMissing() const { return missing_; } /// void setAction(FuncRequest const & a) { action_ = a; } + /// return comma-separated list of all par IDs (including nested insets) + /// this is used by captioned elements + docstring const parIDs() const { return par_ids_; } + /// + void setParIDs(docstring const & ids) { par_ids_ = ids; } /// custom action, or the default one (paragraph-goto) if not customised FuncRequest action() const; - /// + /// return only main par ID int id() const; /// String for display, e.g. it has a mark if output is inactive docstring const asString() const; @@ -105,6 +110,8 @@ private: bool missing_; /// Custom action FuncRequest action_; + /// Paragraph IDs including nested insets (comma-separated). + docstring par_ids_; }; diff --git a/src/TocBuilder.cpp b/src/TocBuilder.cpp index aff19bc2b1..1cfeddc450 100644 --- a/src/TocBuilder.cpp +++ b/src/TocBuilder.cpp @@ -46,10 +46,13 @@ void TocBuilder::captionItem(DocIterator const & dit, docstring const & s, bool output_active) { // first show the float before moving to the caption + docstring parids = dit.paragraphGotoArgument(true); docstring arg = "paragraph-goto " + dit.paragraphGotoArgument(); - if (!stack_.empty()) + if (!stack_.empty()) { arg = "paragraph-goto " + (*toc_)[stack_.top().pos].dit().paragraphGotoArgument() + ";" + arg; + parids = (*toc_)[stack_.top().pos].dit().paragraphGotoArgument(true) + "," + parids; + } FuncRequest func(LFUN_COMMAND_SEQUENCE, arg); if (!stack_.empty() && !stack_.top().is_captioned) { @@ -58,6 +61,7 @@ void TocBuilder::captionItem(DocIterator const & dit, docstring const & s, TocItem & captionable = (*toc_)[stack_.top().pos]; captionable.str(s); captionable.setAction(func); + captionable.setParIDs(parids); stack_.top().is_captioned = true; } else { // This is a new entry. diff --git a/src/frontends/qt/TocWidget.cpp b/src/frontends/qt/TocWidget.cpp index c4a16d9ff8..dc9667ca17 100644 --- a/src/frontends/qt/TocWidget.cpp +++ b/src/frontends/qt/TocWidget.cpp @@ -254,39 +254,11 @@ void TocWidget::doDispatch(Cursor & cur, FuncRequest const & cmd, docstring const type = cmd.argument(); TocItem const & item = gui_view_.tocModels().currentItem(current_type_, index); - if (item.action().action() == LFUN_PARAGRAPH_GOTO) { - // easy case - docstring const id = item.dit().paragraphGotoArgument(true); - docstring const arg = (type.empty()) ? id : id + " " + type; - dispatch(FuncRequest(cmd, arg)); - break; - } - // Captions etc. - // Here we cannot employ LFUN_REFERENCE_TO_PARAGRAPH - // as it won't land in the inset. Seo we do it ourselves; - // 1. save current position - lyx::dispatch(FuncRequest(LFUN_BOOKMARK_SAVE, "0")); - // go to the item - sendDispatch(item.action()); - // check if it has a label - docstring label = from_utf8(cur.innerParagraph().getLabelForXRef()); - if (label.empty()) { - // if not: - // insert a new label - // we do not want to open the dialog, hence we - // do not employ LFUN_LABEL_INSERT - InsetCommandParams p(LABEL_CODE); - label = cur.getPossibleLabel(); - p["name"] = label; - string const data = InsetCommand::params2string(p); - lyx::dispatch(FuncRequest(LFUN_INSET_INSERT, data)); - } - // now go back to the original position ... - lyx::dispatch(FuncRequest(LFUN_BOOKMARK_GOTO, "0")); - // ... to insert the ref - docstring const arg = (type.empty()) ? label - : label + from_ascii(" ") + type; - lyx::dispatch(FuncRequest(LFUN_REFERENCE_INSERT, arg)); + docstring const id = (item.parIDs().empty()) + ? item.dit().paragraphGotoArgument(true) + : item.parIDs(); + docstring const arg = (type.empty()) ? id : id + " " + type; + dispatch(FuncRequest(cmd, arg)); break; }