2 * \file InsetMathRef.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
13 #include "InsetMathRef.h"
15 #include "BufferParams.h"
16 #include "BufferView.h"
19 #include "FuncRequest.h"
20 #include "FuncStatus.h"
21 #include "LaTeXFeatures.h"
24 #include "MathFactory.h"
25 #include "MathStream.h"
26 #include "MathSupport.h"
27 #include "ParIterator.h"
30 #include "insets/InsetCommand.h"
31 #include "insets/InsetRef.h"
33 #include "support/debug.h"
34 #include "support/gettext.h"
35 #include "support/lstrings.h"
36 #include "support/textutils.h"
44 InsetMathRef::InsetMathRef(Buffer * buf)
45 : InsetMathCommand(buf, from_ascii("ref"), false)
49 InsetMathRef::InsetMathRef(Buffer * buf, docstring const & data)
50 : InsetMathCommand(buf, data, false)
54 Inset * InsetMathRef::clone() const
56 return new InsetMathRef(*this);
60 void InsetMathRef::infoize(odocstream & os) const
62 os << "Ref: " << cell(0);
66 void InsetMathRef::doDispatch(Cursor & cur, FuncRequest & cmd)
68 // Ctrl + click: go to label
69 if (cmd.action() == LFUN_MOUSE_RELEASE && cmd.modifier() == ControlModifier) {
70 LYXERR0("trying to goto ref '" << to_utf8(asString(cell(0))) << "'");
71 //FIXME: use DispatchResult argument
72 lyx::dispatch(FuncRequest(LFUN_LABEL_GOTO, asString(cell(0))));
76 switch (cmd.action()) {
77 case LFUN_INSET_MODIFY: {
78 string const arg0 = cmd.getArg(0);
79 string const arg1 = cmd.getArg(1);
81 if (arg1 == "changetarget") {
82 string const oldtarget = cmd.getArg(2);
83 string const newtarget = cmd.getArg(3);
84 if (!oldtarget.empty() && !newtarget.empty()
85 && asString(cell(0)) == from_utf8(oldtarget))
86 changeTarget(from_utf8(newtarget));
87 cur.forceBufferUpdate();
91 if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
93 Buffer & buf = buffer();
94 *this = *ar[0].nucleus()->asRefInset();
98 } else if (arg0 == "changetype") {
99 docstring const data = from_ascii(createDialogStr(arg1));
100 MathData ar(buffer_);
101 if (createInsetMath_fromDialogStr(data, ar)) {
103 Buffer & buf = buffer();
104 *this = *ar[0].nucleus()->asRefInset();
113 case LFUN_INSET_DIALOG_UPDATE: {
114 string const data = createDialogStr();
115 cur.bv().updateDialog("ref", data);
119 case LFUN_INSET_SETTINGS: {
120 string const data = createDialogStr();
121 cur.bv().showDialog("ref", data, this);
126 case LFUN_MOUSE_RELEASE:
127 if (cur.selection()) {
131 if (cmd.button() == mouse_button::button1) {
132 string const data = createDialogStr();
133 cur.bv().showDialog("ref", data, this);
139 case LFUN_MOUSE_PRESS: {
140 bool do_selection = cmd.button() == mouse_button::button1
141 && cmd.modifier() == ShiftModifier;
142 // For some reason the cursor points inside the first cell, which is not
144 cur.leaveInset(*this);
145 cur.bv().mouseSetCursor(cur, do_selection);
149 case LFUN_MOUSE_DOUBLE:
150 case LFUN_MOUSE_TRIPLE:
151 // eat other mouse commands
155 InsetMathCommand::doDispatch(cur, cmd);
161 bool InsetMathRef::getStatus(Cursor & cur, FuncRequest const & cmd,
162 FuncStatus & status) const
164 switch (cmd.action()) {
166 case LFUN_INSET_MODIFY:
167 if (cmd.getArg(0) == "changetype")
168 status.setOnOff(from_ascii(cmd.getArg(1)) == commandname());
169 status.setEnabled(true);
171 case LFUN_INSET_DIALOG_UPDATE:
172 case LFUN_INSET_SETTINGS:
173 case LFUN_MOUSE_RELEASE:
174 case LFUN_MOUSE_PRESS:
175 case LFUN_MOUSE_DOUBLE:
176 case LFUN_MOUSE_TRIPLE:
177 status.setEnabled(true);
180 return InsetMathCommand::getStatus(cur, cmd, status);
185 docstring const InsetMathRef::screenLabel() const
188 for (int i = 0; !types[i].latex_name.empty(); ++i) {
189 if (commandname() == types[i].latex_name) {
190 str = _(to_utf8(types[i].short_gui_name));
194 str += asString(cell(0));
196 //if (/* !isLatex && */ !cell(0).empty()) {
198 // str += asString(cell(1));
204 void InsetMathRef::validate(LaTeXFeatures & features) const
206 // This really should not happen here but does.
208 LYXERR0("Unassigned buffer_ in InsetMathRef::write!");
209 LYXERR0("LaTeX output may be wrong!");
211 bool const use_refstyle =
212 buffer_ && buffer().params().use_refstyle;
214 if (commandname() == "vref" || commandname() == "vpageref")
215 features.require("varioref");
216 else if (commandname() == "formatted") {
218 features.require("refstyle");
220 features.require("prettyref");
222 // if eqref is used with refstyle, we do our own output
223 else if (commandname() == "eqref" && use_refstyle)
224 features.require("amsmath");
225 else if (commandname() == "nameref")
226 features.require("nameref");
230 void InsetMathRef::docbook(XMLStream & xs, OutputParams const &) const
232 if (cell(1).empty()) {
233 docstring attr = from_utf8("linkend=\"") + xml::cleanID(asString(cell(0))) + from_utf8("\"");
234 xs << xml::CompTag("xref", to_utf8(attr));
236 // Link with linkend, as is it within the document (not outside, in which case xlink:href is better suited).
237 docstring attr = from_utf8("linkend=\"") + xml::cleanID(asString(cell(0))) + from_utf8("\"");
238 xs << xml::StartTag("link", to_utf8(attr))
240 << xml::EndTag("link");
245 void InsetMathRef::updateBuffer(ParIterator const & it, UpdateType /*utype*/, bool const /*deleted*/)
248 LYXERR0("InsetMathRef::updateBuffer: no buffer_!");
251 // register this inset into the buffer reference cache.
252 buffer().addReference(getTarget(), this, it);
256 string const InsetMathRef::createDialogStr(string const & type) const
258 InsetCommandParams icp(REF_CODE, (type.empty()
259 ? to_ascii(commandname()) : type));
260 icp["reference"] = asString(cell(0));
261 if (!cell(1).empty())
262 icp["name"] = asString(cell(1));
263 return InsetCommand::params2string(icp);
267 docstring const InsetMathRef::getTarget() const
269 return asString(cell(0));
273 void InsetMathRef::changeTarget(docstring const & target)
275 InsetCommandParams icp(REF_CODE, to_ascii(commandname()));
276 icp["reference"] = target;
277 if (!cell(1).empty())
278 icp["name"] = asString(cell(1));
279 MathData ar(buffer_);
280 Buffer & buf = buffer();
281 if (createInsetMath_fromDialogStr(
282 from_utf8(InsetCommand::params2string(icp)), ar)) {
283 *this = *ar[0].nucleus()->asRefInset();
284 // FIXME audit setBuffer calls
290 void InsetMathRef::write(TeXMathStream & os) const
292 docstring const & cmd = commandname();
293 // This should not happen, but of course it does
295 LYXERR0("Unassigned buffer_ in InsetMathRef::write!");
296 LYXERR0("LaTeX output may be wrong!");
298 // are we writing to the LyX file?
300 // if so, then this is easy
301 InsetMathCommand::write(os);
304 bool const use_refstyle =
305 buffer_ && buffer().params().use_refstyle;
306 bool special_case = cmd == "formatted" ||
307 cmd == "labelonly" ||
308 (cmd == "eqref" && use_refstyle);
309 // we need to translate 'formatted' to prettyref or refstyle-type
310 // commands and just output the label with labelonly
311 // most of this is borrowed from InsetRef and should be kept in
313 ModeSpecifier specifier(os, currentMode(), lockedMode(), asciiOnly());
314 MathEnsurer ensurer(os, false);
316 os << from_ascii("\\") << cmd << "{" << cell(0) << from_ascii("}");
318 else if (use_refstyle && cmd == "eqref") {
319 // we advertise this as printing "(n)", so we'll do that, at least
320 // for refstyle, since refstlye's own \eqref prints, by default,
321 // "equation n". if one wants \eqref, one can get it by using a
322 // formatted label in this case.
323 os << '(' << from_ascii("\\ref{") << cell(0) << from_ascii("})");
325 else if (cmd == "formatted") {
327 os << "\\prettyref{" << cell(0) << "}";
329 odocstringstream ods;
330 // get the label we are referencing
331 for (auto const & d : cell(0)) {
334 docstring const ref = ods.str();
337 At the moment, the 'plural' and 'caps' options will
338 not work here. The reason is that we handle these as
339 'internal' LyX argumemts, but those are not handled by
340 InsetCommandParams::getCommand, which is what is used
341 in createInsetMath_fromDialogStr to interpret the data
342 coming from the dialog.
343 If this is fixed, then what follows will get the info
345 Fixing it, I think, would mean sub-classing
346 InsetCommandParams to InsetRefParams, and the overriding
348 *******************************************************
350 ods.str(docstring());
352 // get the options from the optional argument
353 for (auto const & d : cell(1))
355 docstring const options = ods.str();
356 bool const caps = support::contains(options, 'C');
357 bool const plural = support::contains(options, 's');
361 docstring const fcmd =
362 InsetRef::getFormattedCmd(ref, label, prefix, true);
366 os << '{' << label << '}';
369 else if (cmd == "labelonly") {
370 // noprefix does not work here, for reasons given above.
376 InsetMathRef::ref_type_info InsetMathRef::types[] = {
377 { from_ascii("ref"), from_ascii(N_("Standard[[mathref]]")), from_ascii(N_("Ref: "))},
378 { from_ascii("eqref"), from_ascii(N_("Equation")), from_ascii(N_("EqRef: "))},
379 { from_ascii("pageref"), from_ascii(N_("Page Number")), from_ascii(N_("Page: "))},
380 { from_ascii("vpageref"), from_ascii(N_("Textual Page Number")), from_ascii(N_("TextPage: "))},
381 { from_ascii("vref"), from_ascii(N_("Standard+Textual Page")), from_ascii(N_("Ref+Text: "))},
382 { from_ascii("formatted"), from_ascii(N_("PrettyRef")), from_ascii(N_("FormatRef: "))},
383 { from_ascii("nameref"), from_ascii(N_("Reference to Name")), from_ascii(N_("NameRef: "))},
384 { from_ascii("labelonly"), from_ascii(N_("Label Only")), from_ascii(N_("Label Only: "))},
385 { from_ascii(""), from_ascii(""), from_ascii("") }