]> git.lyx.org Git - lyx.git/blob - src/mathed/InsetMathRef.cpp
typo
[lyx.git] / src / mathed / InsetMathRef.cpp
1 /**
2  * \file InsetMathRef.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author André Pönitz
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "InsetMathRef.h"
14
15 #include "BufferParams.h"
16 #include "BufferView.h"
17 #include "Buffer.h"
18 #include "Cursor.h"
19 #include "FuncRequest.h"
20 #include "FuncStatus.h"
21 #include "LaTeXFeatures.h"
22 #include "LyX.h"
23 #include "MathData.h"
24 #include "MathFactory.h"
25 #include "MathStream.h"
26 #include "MathSupport.h"
27 #include "ParIterator.h"
28 #include "xml.h"
29
30 #include "insets/InsetCommand.h"
31 #include "insets/InsetRef.h"
32
33 #include "support/debug.h"
34 #include "support/gettext.h"
35 #include "support/lstrings.h"
36 #include "support/textutils.h"
37
38 #include <ostream>
39
40 using namespace std;
41
42 namespace lyx {
43
44 InsetMathRef::InsetMathRef(Buffer * buf)
45         : InsetMathCommand(buf, from_ascii("ref"), false)
46 {}
47
48
49 InsetMathRef::InsetMathRef(Buffer * buf, docstring const & data)
50         : InsetMathCommand(buf, data, false)
51 {}
52
53
54 Inset * InsetMathRef::clone() const
55 {
56         return new InsetMathRef(*this);
57 }
58
59
60 void InsetMathRef::infoize(odocstream & os) const
61 {
62         os << "Ref: " << cell(0);
63 }
64
65
66 void InsetMathRef::doDispatch(Cursor & cur, FuncRequest & cmd)
67 {
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))));
73                 return;
74         }
75
76         switch (cmd.action()) {
77         case LFUN_INSET_MODIFY: {
78                 string const arg0 = cmd.getArg(0);
79                 string const arg1   = cmd.getArg(1);
80                 if (arg0 == "ref") {
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();
88                                 break;
89                         }
90                         MathData ar;
91                         if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
92                                 cur.recordUndo();
93                                 Buffer & buf = buffer();
94                                 *this = *ar[0].nucleus()->asRefInset();
95                                 setBuffer(buf);
96                                 break;
97                         }
98                 } else if (arg0 == "changetype") {
99                         docstring const data = from_ascii(createDialogStr(arg1));
100                         MathData ar;
101                         if (createInsetMath_fromDialogStr(data, ar)) {
102                                 cur.recordUndo();
103                                 Buffer & buf = buffer();
104                                 *this = *ar[0].nucleus()->asRefInset();
105                                 setBuffer(buf);
106                                 break;
107                         }
108                 }
109                 cur.undispatched();
110                 break;
111         }
112
113         case LFUN_INSET_DIALOG_UPDATE: {
114                 string const data = createDialogStr();
115                 cur.bv().updateDialog("ref", data);
116                 break;
117         }
118
119         case LFUN_INSET_SETTINGS: {
120                 string const data = createDialogStr();
121                 cur.bv().showDialog("ref", data, this);
122                 cur.dispatched();
123                 break;
124         }
125
126         case LFUN_MOUSE_RELEASE:
127                 if (cur.selection()) {
128                         cur.undispatched();
129                         break;
130                 }
131                 if (cmd.button() == mouse_button::button1) {
132                         string const data = createDialogStr();
133                         cur.bv().showDialog("ref", data, this);
134                         break;
135                 }
136                 cur.undispatched();
137                 break;
138
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
143                 // active.
144                 cur.leaveInset(*this);
145                 cur.bv().mouseSetCursor(cur, do_selection);
146                 break;
147         }
148
149         case LFUN_MOUSE_DOUBLE:
150         case LFUN_MOUSE_TRIPLE:
151                 // eat other mouse commands
152                 break;
153
154         default:
155                 InsetMathCommand::doDispatch(cur, cmd);
156                 break;
157         }
158 }
159
160
161 bool InsetMathRef::getStatus(Cursor & cur, FuncRequest const & cmd,
162                          FuncStatus & status) const
163 {
164         switch (cmd.action()) {
165         // we handle these
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);
174                 return true;
175         default:
176                 return InsetMathCommand::getStatus(cur, cmd, status);
177         }
178 }
179
180
181 docstring const InsetMathRef::screenLabel() const
182 {
183         docstring str;
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));
187                         break;
188                 }
189         }
190         str += asString(cell(0));
191
192         //if (/* !isLatex && */ !cell(0).empty()) {
193         //      str += "||";
194         //      str += asString(cell(1));
195         //}
196         return str;
197 }
198
199
200 void InsetMathRef::validate(LaTeXFeatures & features) const
201 {
202         // This really should not happen here but does.
203         if (!buffer_) {
204                 LYXERR0("Unassigned buffer_ in InsetMathRef::write!");
205                 LYXERR0("LaTeX output may be wrong!");
206         }
207         bool const use_refstyle =
208                 buffer_ && buffer().params().use_refstyle;
209
210         if (commandname() == "vref" || commandname() == "vpageref")
211                 features.require("varioref");
212         else if (commandname() == "formatted") {
213                 if (use_refstyle)
214                         features.require("refstyle");
215                 else
216                         features.require("prettyref");
217         }
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");
223 }
224
225
226 void InsetMathRef::docbook(XMLStream & xs, OutputParams const &) const
227 {
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));
231         } else {
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))
235                    << asString(cell(1))
236                    << xml::EndTag("link");
237         }
238 }
239
240
241 void InsetMathRef::updateBuffer(ParIterator const & it, UpdateType /*utype*/, bool const /*deleted*/)
242 {
243         if (!buffer_) {
244                 LYXERR0("InsetMathRef::updateBuffer: no buffer_!");
245                 return;
246         }
247         // register this inset into the buffer reference cache.
248         buffer().addReference(getTarget(), this, it);
249 }
250
251
252 string const InsetMathRef::createDialogStr(string const & type) const
253 {
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);
260 }
261
262
263 docstring const InsetMathRef::getTarget() const
264 {
265         return asString(cell(0));
266 }
267
268
269 void InsetMathRef::changeTarget(docstring const & target)
270 {
271         InsetCommandParams icp(REF_CODE, to_ascii(commandname()));
272         icp["reference"] = target;
273         if (!cell(1).empty())
274                 icp["name"] = asString(cell(1));
275         MathData ar;
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
281                 setBuffer(buf);
282         }
283 }
284
285
286 void InsetMathRef::write(TeXMathStream & os) const
287 {
288         docstring const & cmd = commandname();
289         // This should not happen, but of course it does
290         if (!buffer_) {
291                 LYXERR0("Unassigned buffer_ in InsetMathRef::write!");
292                 LYXERR0("LaTeX output may be wrong!");
293         }
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);
303                 return;
304         }
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 
308         // sync with that.
309         ModeSpecifier specifier(os, currentMode(), lockedMode(), asciiOnly());
310         MathEnsurer ensurer(os, false);
311
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("})");
318         }
319         else if (cmd == "formatted") {
320                 if (!use_refstyle)
321                         os << "\\prettyref{" << cell(0) << "}";
322                 else {
323                          odocstringstream ods;
324                         // get the label we are referencing
325                         for (auto const & d : cell(0)) {
326                                 ods << d;
327                         }
328                         docstring const ref = ods.str();
329
330                         /*
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
338                         we need.
339                         Fixing it, I think, would mean sub-classing
340                         InsetCommandParams to InsetRefParams, and the overriding
341                         getCommand.
342                         *******************************************************
343                         // reset
344                         ods.str(docstring());
345                         ods.clear();
346                         // get the options from the optional argument
347                         for (auto const & d : cell(1))
348                                 ods << d;
349                         docstring const options = ods.str();
350                         bool const caps   = support::contains(options, 'C');
351                         bool const plural = support::contains(options, 's');
352                         */
353                         docstring label;
354                         docstring prefix;
355                         docstring const fcmd =
356                                 InsetRef::getFormattedCmd(ref, label, prefix, true);
357                         os << fcmd;
358                         //if (plural)
359                         //      os << "[s]";
360                         os << '{' << label << '}';
361                 }
362         }
363         else if (cmd == "labelonly") {
364                 // noprefix does not work here, for reasons given above.
365                 os << cell(0);
366         }
367 }
368
369
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("") }
380 };
381
382
383 } // namespace lyx