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 switch (cmd.action()) {
69 case LFUN_INSET_MODIFY:
70 if (cmd.getArg(0) == "ref") {
71 if (cmd.getArg(1) == "changetarget") {
72 string const oldtarget = cmd.getArg(2);
73 string const newtarget = cmd.getArg(3);
74 if (!oldtarget.empty() && !newtarget.empty()
75 && asString(cell(0)) == from_utf8(oldtarget))
76 changeTarget(from_utf8(newtarget));
77 cur.forceBufferUpdate();
81 if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
83 Buffer & buf = buffer();
84 *this = *ar[0].nucleus()->asRefInset();
92 case LFUN_INSET_DIALOG_UPDATE: {
93 string const data = createDialogStr();
94 cur.bv().updateDialog("ref", data);
98 case LFUN_MOUSE_RELEASE:
99 if (cur.selection()) {
103 if (cmd.button() == mouse_button::button3) {
104 LYXERR0("trying to goto ref '" << to_utf8(asString(cell(0))) << "'");
105 //FIXME: use DispatchResult argument
106 lyx::dispatch(FuncRequest(LFUN_LABEL_GOTO, asString(cell(0))));
109 if (cmd.button() == mouse_button::button1) {
110 // Eventually trigger dialog with button 3, not 1
111 string const data = createDialogStr();
112 cur.bv().showDialog("ref", data, this);
118 case LFUN_MOUSE_PRESS: {
119 bool do_selection = cmd.button() == mouse_button::button1
120 && cmd.modifier() == ShiftModifier;
121 // For some reason the cursor points inside the first cell, which is not
123 cur.leaveInset(*this);
124 cur.bv().mouseSetCursor(cur, do_selection);
128 case LFUN_MOUSE_DOUBLE:
129 case LFUN_MOUSE_TRIPLE:
130 // eat other mouse commands
134 InsetMathCommand::doDispatch(cur, cmd);
140 bool InsetMathRef::getStatus(Cursor & cur, FuncRequest const & cmd,
141 FuncStatus & status) const
143 switch (cmd.action()) {
145 case LFUN_INSET_MODIFY:
146 case LFUN_INSET_DIALOG_UPDATE:
147 case LFUN_MOUSE_RELEASE:
148 case LFUN_MOUSE_PRESS:
149 case LFUN_MOUSE_DOUBLE:
150 case LFUN_MOUSE_TRIPLE:
151 status.setEnabled(true);
154 return InsetMathCommand::getStatus(cur, cmd, status);
159 docstring const InsetMathRef::screenLabel() const
162 for (int i = 0; !types[i].latex_name.empty(); ++i) {
163 if (commandname() == types[i].latex_name) {
164 str = _(to_utf8(types[i].short_gui_name));
168 str += asString(cell(0));
170 //if (/* !isLatex && */ !cell(0).empty()) {
172 // str += asString(cell(1));
178 void InsetMathRef::validate(LaTeXFeatures & features) const
180 // This really should not happen here but does.
182 LYXERR0("Unassigned buffer_ in InsetMathRef::write!");
183 LYXERR0("LaTeX output may be wrong!");
185 bool const use_refstyle =
186 buffer_ && buffer().params().use_refstyle;
188 if (commandname() == "vref" || commandname() == "vpageref")
189 features.require("varioref");
190 else if (commandname() == "formatted") {
192 features.require("refstyle");
194 features.require("prettyref");
196 // if eqref is used with refstyle, we do our own output
197 else if (commandname() == "eqref" && use_refstyle)
198 features.require("amsmath");
199 else if (commandname() == "nameref")
200 features.require("nameref");
204 void InsetMathRef::docbook(XMLStream & xs, OutputParams const &) const
206 if (cell(1).empty()) {
207 docstring attr = from_utf8("linkend=\"") + xml::cleanID(asString(cell(0))) + from_utf8("\"");
208 xs << xml::CompTag("xref", to_utf8(attr));
210 // Link with linkend, as is it within the document (not outside, in which case xlink:href is better suited).
211 docstring attr = from_utf8("linkend=\"") + xml::cleanID(asString(cell(0))) + from_utf8("\"");
212 xs << xml::StartTag("link", to_utf8(attr))
214 << xml::EndTag("link");
219 void InsetMathRef::updateBuffer(ParIterator const & it, UpdateType /*utype*/, bool const /*deleted*/)
222 LYXERR0("InsetMathRef::updateBuffer: no buffer_!");
225 // register this inset into the buffer reference cache.
226 buffer().addReference(getTarget(), this, it);
230 string const InsetMathRef::createDialogStr() const
232 InsetCommandParams icp(REF_CODE, to_ascii(commandname()));
233 icp["reference"] = asString(cell(0));
234 if (!cell(1).empty())
235 icp["name"] = asString(cell(1));
236 return InsetCommand::params2string(icp);
240 docstring const InsetMathRef::getTarget() const
242 return asString(cell(0));
246 void InsetMathRef::changeTarget(docstring const & target)
248 InsetCommandParams icp(REF_CODE, to_ascii(commandname()));
249 icp["reference"] = target;
250 if (!cell(1).empty())
251 icp["name"] = asString(cell(1));
253 Buffer & buf = buffer();
254 if (createInsetMath_fromDialogStr(
255 from_utf8(InsetCommand::params2string(icp)), ar)) {
256 *this = *ar[0].nucleus()->asRefInset();
257 // FIXME audit setBuffer calls
263 void InsetMathRef::write(TeXMathStream & os) const
265 docstring const & cmd = commandname();
266 // This should not happen, but of course it does
268 LYXERR0("Unassigned buffer_ in InsetMathRef::write!");
269 LYXERR0("LaTeX output may be wrong!");
271 bool const use_refstyle =
272 buffer_ && buffer().params().use_refstyle;
273 bool special_case = cmd == "formatted" ||
274 cmd == "labelonly" ||
275 (cmd == "eqref" && use_refstyle);
276 // are we writing to the LyX file or not in a special case?
277 if (!os.latex() || !special_case) {
278 // if so, then this is easy
279 InsetMathCommand::write(os);
282 // we need to translate 'formatted' to prettyref or refstyle-type
283 // commands and just output the label with labelonly
284 // most of this is borrowed from InsetRef and should be kept in
286 ModeSpecifier specifier(os, currentMode(), lockedMode(), asciiOnly());
287 MathEnsurer ensurer(os, false);
289 if (use_refstyle && cmd == "eqref") {
290 // we advertise this as printing "(n)", so we'll do that, at least
291 // for refstyle, since refstlye's own \eqref prints, by default,
292 // "equation n". if one wants \eqref, one can get it by using a
293 // formatted label in this case.
294 os << '(' << from_ascii("\\ref{") << cell(0) << from_ascii("})");
296 else if (cmd == "formatted") {
298 os << "\\prettyref{" << cell(0) << "}";
300 odocstringstream ods;
301 // get the label we are referencing
302 for (auto const & d : cell(0)) {
305 docstring const ref = ods.str();
308 At the moment, the 'plural' and 'caps' options will
309 not work here. The reason is that we handle these as
310 'internal' LyX argumemts, but those are not handled by
311 InsetCommandParams::getCommand, which is what is used
312 in createInsetMath_fromDialogStr to interpret the data
313 coming from the dialog.
314 If this is fixed, then what follows will get the info
316 Fixing it, I think, would mean sub-classing
317 InsetCommandParams to InsetRefParams, and the overriding
319 *******************************************************
321 ods.str(docstring());
323 // get the options from the optional argument
324 for (auto const & d : cell(1))
326 docstring const options = ods.str();
327 bool const caps = support::contains(options, 'C');
328 bool const plural = support::contains(options, 's');
332 docstring const fcmd =
333 InsetRef::getFormattedCmd(ref, label, prefix, true);
337 os << '{' << label << '}';
340 else if (cmd == "labelonly") {
341 // noprefix does not work here, for reasons given above.
347 InsetMathRef::ref_type_info InsetMathRef::types[] = {
348 { from_ascii("ref"), from_ascii(N_("Standard[[mathref]]")), from_ascii(N_("Ref: "))},
349 { from_ascii("eqref"), from_ascii(N_("Equation")), from_ascii(N_("EqRef: "))},
350 { from_ascii("pageref"), from_ascii(N_("Page Number")), from_ascii(N_("Page: "))},
351 { from_ascii("vpageref"), from_ascii(N_("Textual Page Number")), from_ascii(N_("TextPage: "))},
352 { from_ascii("vref"), from_ascii(N_("Standard+Textual Page")), from_ascii(N_("Ref+Text: "))},
353 { from_ascii("formatted"), from_ascii(N_("PrettyRef")), from_ascii(N_("FormatRef: "))},
354 { from_ascii("nameref"), from_ascii(N_("Reference to Name")), from_ascii(N_("NameRef: "))},
355 { from_ascii("labelonly"), from_ascii(N_("Label Only")), from_ascii(N_("Label Only: "))},
356 { from_ascii(""), from_ascii(""), from_ascii("") }