Fixup LFUN_REFERENCE_TO_PARAGRAPH for captions in other buffers

The movement to the caption is now done in the LFUN function itself,
as we need the DocIterator in the caption

This greatly simplifies the code in the TocWidget and shifts all the
complexity to the LFUN itself

(cherry picked from commit 9464f0526e)
This commit is contained in:
Juergen Spitzmueller 2024-07-30 12:36:20 +02:00
parent 0c77174406
commit 173464b8a3
5 changed files with 64 additions and 56 deletions

View File

@ -1283,8 +1283,15 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
break; break;
case LFUN_REFERENCE_TO_PARAGRAPH: { case LFUN_REFERENCE_TO_PARAGRAPH: {
int const id = convert<int>(cmd.getArg(0)); vector<string> const pids = getVectorFromString(cmd.getArg(0));
flag.setEnabled(id >= 0); for (string const & s : pids) {
int const id = convert<int>(s);
if (id < 0) {
flag.setEnabled(false);
break;
}
}
flag.setEnabled(true);
break; break;
} }
@ -1648,42 +1655,59 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
} }
case LFUN_REFERENCE_TO_PARAGRAPH: { case LFUN_REFERENCE_TO_PARAGRAPH: {
int const id = convert<int>(cmd.getArg(0)); vector<string> const pids = getVectorFromString(cmd.getArg(0));
string const type = cmd.getArg(1);
int id = convert<int>(pids.front());
if (id < 0) if (id < 0)
break; break;
string const type = cmd.getArg(1);
int i = 0; int i = 0;
for (Buffer * b = &buffer_; i == 0 || b != &buffer_; for (Buffer * b = &buffer_; i == 0 || b != &buffer_;
b = theBufferList().next(b)) { b = theBufferList().next(b)) {
DocIterator const dit = b->getParFromID(id); DocIterator dit = b->getParFromID(id);
if (dit.empty()) { if (dit.empty()) {
LYXERR(Debug::INFO, "No matching paragraph found! [" << id << "]."); LYXERR(Debug::INFO, "No matching paragraph found! [" << id << "].");
++i; ++i;
continue; continue;
} }
string const label = dit.innerParagraph().getLabelForXRef(); string label = dit.innerParagraph().getLabelForXRef();
if (!label.empty()) { if (!label.empty()) {
// if the paragraph has a label, we refer to this // if the paragraph has a label, we refer to this
string const arg = (type.empty()) ? label : label + " " + type; string const arg = (type.empty()) ? label : label + " " + type;
lyx::dispatch(FuncRequest(LFUN_REFERENCE_INSERT, arg)); lyx::dispatch(FuncRequest(LFUN_REFERENCE_INSERT, arg));
break; break;
} else { } 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_BOOKMARK_SAVE, "0"));
lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_GOTO, cmd.argument())); for (string const & s : pids) {
// ... insert the label id = convert<int>(s);
// we do not want to open the dialog, hence we if (id < 0)
// do not employ LFUN_LABEL_INSERT break;
InsetCommandParams p(LABEL_CODE); dit = b->getParFromID(id);
docstring const label = dit.getPossibleLabel(); lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_GOTO, s));
p["name"] = label; }
string const data = InsetCommand::params2string(p); // ... and try again if we find a label ...
lyx::dispatch(FuncRequest(LFUN_INSET_INSERT, data)); 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 // ... and go back to the original position
lyx::dispatch(FuncRequest(LFUN_BOOKMARK_GOTO, "0")); lyx::dispatch(FuncRequest(LFUN_BOOKMARK_GOTO, "0"));
// ... to insert the ref // ... to insert the ref
string const arg = (type.empty()) ? to_utf8(label)
: to_utf8(label) + " " + type;
lyx::dispatch(FuncRequest(LFUN_REFERENCE_INSERT, arg)); lyx::dispatch(FuncRequest(LFUN_REFERENCE_INSERT, arg));
break; break;
} }

View File

@ -3537,8 +3537,9 @@ void LyXAction::init()
* \li Notion: The function checks of the paragraph already has a label. * \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. * If so, it uses that. Otherwise it inserts a label and uses this.
* \li Syntax: reference-to-paragraph <PAR_ID> [<TYPE>] * \li Syntax: reference-to-paragraph <PAR_ID> [<TYPE>]
* \li Params: <PAR_ID>: paragraph id \n * \li Params: <PAR_IDs>: paragraph ids, might be a comma-separated list\n
<TYPE>: cross-references type * if it is in a nested inset\n
* <TYPE>: cross-references type
* \li Origin: spitz, 28 Jul 2024 * \li Origin: spitz, 28 Jul 2024
* \endvar * \endvar
*/ */

View File

@ -75,17 +75,22 @@ public:
/// ///
docstring const & prettyStr() const { return pretty_str_; } 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 isOutput() const { return output_; }
/// ///
bool isMissing() const { return missing_; } bool isMissing() const { return missing_; }
/// ///
void setAction(FuncRequest const & a) { action_ = a; } 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 /// custom action, or the default one (paragraph-goto) if not customised
FuncRequest action() const; FuncRequest action() const;
/// /// return only main par ID
int id() const; int id() const;
/// String for display, e.g. it has a mark if output is inactive /// String for display, e.g. it has a mark if output is inactive
docstring const asString() const; docstring const asString() const;
@ -105,6 +110,8 @@ private:
bool missing_; bool missing_;
/// Custom action /// Custom action
FuncRequest action_; FuncRequest action_;
/// Paragraph IDs including nested insets (comma-separated).
docstring par_ids_;
}; };

View File

@ -46,10 +46,13 @@ void TocBuilder::captionItem(DocIterator const & dit, docstring const & s,
bool output_active) bool output_active)
{ {
// first show the float before moving to the caption // first show the float before moving to the caption
docstring parids = dit.paragraphGotoArgument(true);
docstring arg = "paragraph-goto " + dit.paragraphGotoArgument(); docstring arg = "paragraph-goto " + dit.paragraphGotoArgument();
if (!stack_.empty()) if (!stack_.empty()) {
arg = "paragraph-goto " + arg = "paragraph-goto " +
(*toc_)[stack_.top().pos].dit().paragraphGotoArgument() + ";" + arg; (*toc_)[stack_.top().pos].dit().paragraphGotoArgument() + ";" + arg;
parids = (*toc_)[stack_.top().pos].dit().paragraphGotoArgument(true) + "," + parids;
}
FuncRequest func(LFUN_COMMAND_SEQUENCE, arg); FuncRequest func(LFUN_COMMAND_SEQUENCE, arg);
if (!stack_.empty() && !stack_.top().is_captioned) { 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]; TocItem & captionable = (*toc_)[stack_.top().pos];
captionable.str(s); captionable.str(s);
captionable.setAction(func); captionable.setAction(func);
captionable.setParIDs(parids);
stack_.top().is_captioned = true; stack_.top().is_captioned = true;
} else { } else {
// This is a new entry. // This is a new entry.

View File

@ -254,39 +254,11 @@ void TocWidget::doDispatch(Cursor & cur, FuncRequest const & cmd,
docstring const type = cmd.argument(); docstring const type = cmd.argument();
TocItem const & item = TocItem const & item =
gui_view_.tocModels().currentItem(current_type_, index); gui_view_.tocModels().currentItem(current_type_, index);
if (item.action().action() == LFUN_PARAGRAPH_GOTO) { docstring const id = (item.parIDs().empty())
// easy case ? item.dit().paragraphGotoArgument(true)
docstring const id = item.dit().paragraphGotoArgument(true); : item.parIDs();
docstring const arg = (type.empty()) ? id : id + " " + type; docstring const arg = (type.empty()) ? id : id + " " + type;
dispatch(FuncRequest(cmd, arg)); 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));
break; break;
} }