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));
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 case LFUN_INSET_DIALOG_UPDATE:
168 case LFUN_INSET_SETTINGS:
169 case LFUN_MOUSE_RELEASE:
170 case LFUN_MOUSE_PRESS:
171 case LFUN_MOUSE_DOUBLE:
172 case LFUN_MOUSE_TRIPLE:
173 status.setEnabled(true);
176 return InsetMathCommand::getStatus(cur, cmd, status);
181 docstring const InsetMathRef::screenLabel() const
184 for (int i = 0; !types[i].latex_name.empty(); ++i) {
185 if (commandname() == types[i].latex_name) {
186 str = _(to_utf8(types[i].short_gui_name));
190 str += asString(cell(0));
192 //if (/* !isLatex && */ !cell(0).empty()) {
194 // str += asString(cell(1));
200 void InsetMathRef::validate(LaTeXFeatures & features) const
202 // This really should not happen here but does.
204 LYXERR0("Unassigned buffer_ in InsetMathRef::write!");
205 LYXERR0("LaTeX output may be wrong!");
207 bool const use_refstyle =
208 buffer_ && buffer().params().use_refstyle;
210 if (commandname() == "vref" || commandname() == "vpageref")
211 features.require("varioref");
212 else if (commandname() == "formatted") {
214 features.require("refstyle");
216 features.require("prettyref");
218 // if eqref is used with refstyle, we do our own output
219 else if (commandname() == "eqref" && use_refstyle)
220 features.require("amsmath");
221 else if (commandname() == "nameref")
222 features.require("nameref");
226 void InsetMathRef::docbook(XMLStream & xs, OutputParams const &) const
228 if (cell(1).empty()) {
229 docstring attr = from_utf8("linkend=\"") + xml::cleanID(asString(cell(0))) + from_utf8("\"");
230 xs << xml::CompTag("xref", to_utf8(attr));
232 // Link with linkend, as is it within the document (not outside, in which case xlink:href is better suited).
233 docstring attr = from_utf8("linkend=\"") + xml::cleanID(asString(cell(0))) + from_utf8("\"");
234 xs << xml::StartTag("link", to_utf8(attr))
236 << xml::EndTag("link");
241 void InsetMathRef::updateBuffer(ParIterator const & it, UpdateType /*utype*/, bool const /*deleted*/)
244 LYXERR0("InsetMathRef::updateBuffer: no buffer_!");
247 // register this inset into the buffer reference cache.
248 buffer().addReference(getTarget(), this, it);
252 string const InsetMathRef::createDialogStr(string const & type) const
254 InsetCommandParams icp(REF_CODE, (type.empty()
255 ? to_ascii(commandname()) : type));
256 icp["reference"] = asString(cell(0));
257 if (!cell(1).empty())
258 icp["name"] = asString(cell(1));
259 return InsetCommand::params2string(icp);
263 docstring const InsetMathRef::getTarget() const
265 return asString(cell(0));
269 void InsetMathRef::changeTarget(docstring const & target)
271 InsetCommandParams icp(REF_CODE, to_ascii(commandname()));
272 icp["reference"] = target;
273 if (!cell(1).empty())
274 icp["name"] = asString(cell(1));
276 Buffer & buf = buffer();
277 if (createInsetMath_fromDialogStr(
278 from_utf8(InsetCommand::params2string(icp)), ar)) {
279 *this = *ar[0].nucleus()->asRefInset();
280 // FIXME audit setBuffer calls
286 void InsetMathRef::write(TeXMathStream & os) const
288 docstring const & cmd = commandname();
289 // This should not happen, but of course it does
291 LYXERR0("Unassigned buffer_ in InsetMathRef::write!");
292 LYXERR0("LaTeX output may be wrong!");
294 bool const use_refstyle =
295 buffer_ && buffer().params().use_refstyle;
296 bool special_case = cmd == "formatted" ||
297 cmd == "labelonly" ||
298 (cmd == "eqref" && use_refstyle);
299 // are we writing to the LyX file or not in a special case?
300 if (!os.latex() || !special_case) {
301 // if so, then this is easy
302 InsetMathCommand::write(os);
305 // we need to translate 'formatted' to prettyref or refstyle-type
306 // commands and just output the label with labelonly
307 // most of this is borrowed from InsetRef and should be kept in
309 ModeSpecifier specifier(os, currentMode(), lockedMode(), asciiOnly());
310 MathEnsurer ensurer(os, false);
312 if (use_refstyle && cmd == "eqref") {
313 // we advertise this as printing "(n)", so we'll do that, at least
314 // for refstyle, since refstlye's own \eqref prints, by default,
315 // "equation n". if one wants \eqref, one can get it by using a
316 // formatted label in this case.
317 os << '(' << from_ascii("\\ref{") << cell(0) << from_ascii("})");
319 else if (cmd == "formatted") {
321 os << "\\prettyref{" << cell(0) << "}";
323 odocstringstream ods;
324 // get the label we are referencing
325 for (auto const & d : cell(0)) {
328 docstring const ref = ods.str();
331 At the moment, the 'plural' and 'caps' options will
332 not work here. The reason is that we handle these as
333 'internal' LyX argumemts, but those are not handled by
334 InsetCommandParams::getCommand, which is what is used
335 in createInsetMath_fromDialogStr to interpret the data
336 coming from the dialog.
337 If this is fixed, then what follows will get the info
339 Fixing it, I think, would mean sub-classing
340 InsetCommandParams to InsetRefParams, and the overriding
342 *******************************************************
344 ods.str(docstring());
346 // get the options from the optional argument
347 for (auto const & d : cell(1))
349 docstring const options = ods.str();
350 bool const caps = support::contains(options, 'C');
351 bool const plural = support::contains(options, 's');
355 docstring const fcmd =
356 InsetRef::getFormattedCmd(ref, label, prefix, true);
360 os << '{' << label << '}';
363 else if (cmd == "labelonly") {
364 // noprefix does not work here, for reasons given above.
370 InsetMathRef::ref_type_info InsetMathRef::types[] = {
371 { from_ascii("ref"), from_ascii(N_("Standard[[mathref]]")), from_ascii(N_("Ref: "))},
372 { from_ascii("eqref"), from_ascii(N_("Equation")), from_ascii(N_("EqRef: "))},
373 { from_ascii("pageref"), from_ascii(N_("Page Number")), from_ascii(N_("Page: "))},
374 { from_ascii("vpageref"), from_ascii(N_("Textual Page Number")), from_ascii(N_("TextPage: "))},
375 { from_ascii("vref"), from_ascii(N_("Standard+Textual Page")), from_ascii(N_("Ref+Text: "))},
376 { from_ascii("formatted"), from_ascii(N_("PrettyRef")), from_ascii(N_("FormatRef: "))},
377 { from_ascii("nameref"), from_ascii(N_("Reference to Name")), from_ascii(N_("NameRef: "))},
378 { from_ascii("labelonly"), from_ascii(N_("Label Only")), from_ascii(N_("Label Only: "))},
379 { from_ascii(""), from_ascii(""), from_ascii("") }