]> git.lyx.org Git - lyx.git/blob - src/insets/InsetNote.cpp
New attempt on #9906: allow following hyperlinks via context menu.
[lyx.git] / src / insets / InsetNote.cpp
1 /**
2  * \file InsetNote.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  * \author Martin Vermeer
8  * \author Jürgen Spitzmüller
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "InsetNote.h"
16
17 #include "Buffer.h"
18 #include "BufferParams.h"
19 #include "BufferView.h"
20 #include "ColorSet.h"
21 #include "Cursor.h"
22 #include "DispatchResult.h"
23 #include "Exporter.h"
24 #include "FuncRequest.h"
25 #include "FuncStatus.h"
26 #include "InsetIterator.h"
27 #include "LaTeXFeatures.h"
28 #include "Lexer.h"
29 #include "LyXRC.h"
30 #include "OutputParams.h"
31 #include "output_docbook.h"
32 #include "ParIterator.h"
33 #include "TextClass.h"
34 #include "TocBackend.h"
35
36 #include "support/debug.h"
37 #include "support/docstream.h"
38 #include "support/gettext.h"
39 #include "support/lstrings.h"
40 #include "support/Translator.h"
41
42 #include "frontends/Application.h"
43
44 #include <algorithm>
45 #include <sstream>
46
47 using namespace std;
48
49 namespace lyx {
50
51 namespace {
52
53 typedef Translator<string, InsetNoteParams::Type> NoteTranslator;
54
55 NoteTranslator const init_notetranslator()
56 {
57         NoteTranslator translator("Note", InsetNoteParams::Note);
58         translator.addPair("Comment", InsetNoteParams::Comment);
59         translator.addPair("Greyedout", InsetNoteParams::Greyedout);
60         return translator;
61 }
62
63
64 NoteTranslator const & notetranslator()
65 {
66         static NoteTranslator const translator = init_notetranslator();
67         return translator;
68 }
69
70
71 } // namespace
72
73
74 InsetNoteParams::InsetNoteParams()
75         : type(Note)
76 {}
77
78
79 void InsetNoteParams::write(ostream & os) const
80 {
81         string const label = notetranslator().find(type);
82         os << "Note " << label << "\n";
83 }
84
85
86 void InsetNoteParams::read(Lexer & lex)
87 {
88         string label;
89         lex >> label;
90         if (lex)
91                 type = notetranslator().find(label);
92 }
93
94
95 /////////////////////////////////////////////////////////////////////
96 //
97 // InsetNote
98 //
99 /////////////////////////////////////////////////////////////////////
100
101 InsetNote::InsetNote(Buffer * buf, string const & label)
102         : InsetCollapsible(buf)
103 {
104         params_.type = notetranslator().find(label);
105 }
106
107
108 InsetNote::~InsetNote()
109 {
110         hideDialogs("note", this);
111 }
112
113
114 docstring InsetNote::layoutName() const
115 {
116         return from_ascii("Note:" + notetranslator().find(params_.type));
117 }
118
119
120 void InsetNote::write(ostream & os) const
121 {
122         params_.write(os);
123         InsetCollapsible::write(os);
124 }
125
126
127 void InsetNote::read(Lexer & lex)
128 {
129         params_.read(lex);
130         InsetCollapsible::read(lex);
131 }
132
133
134 bool InsetNote::showInsetDialog(BufferView * bv) const
135 {
136         bv->showDialog("note", params2string(params()),
137                 const_cast<InsetNote *>(this));
138         return true;
139 }
140
141
142 void InsetNote::doDispatch(Cursor & cur, FuncRequest & cmd)
143 {
144         switch (cmd.action()) {
145
146         case LFUN_INSET_MODIFY: {
147                 // Do not do anything if converting to the same type of Note.
148                 // A quick break here is done instead of disabling the LFUN
149                 // because disabling the LFUN would lead to a greyed out
150                 // entry, which might confuse users.
151                 // In the future, we might want to have a radio button for
152                 // switching between notes.
153                 InsetNoteParams params;
154                 string2params(to_utf8(cmd.argument()), params);
155                 if (params_.type == params.type)
156                   break;
157
158                 cur.recordUndoInset(this);
159                 string2params(to_utf8(cmd.argument()), params_);
160                 setButtonLabel();
161                 // what we really want here is a TOC update, but that means
162                 // a full buffer update
163                 cur.forceBufferUpdate();
164                 break;
165         }
166
167         case LFUN_INSET_DIALOG_UPDATE:
168                 cur.bv().updateDialog("note", params2string(params()));
169                 break;
170
171         default:
172                 InsetCollapsible::doDispatch(cur, cmd);
173                 break;
174         }
175 }
176
177
178 bool InsetNote::getStatus(Cursor & cur, FuncRequest const & cmd,
179                 FuncStatus & flag) const
180 {
181         switch (cmd.action()) {
182
183         case LFUN_INSET_MODIFY:
184                 if (cmd.getArg(0) == "note") {
185                         InsetNoteParams params;
186                         string2params(to_utf8(cmd.argument()), params);
187                         flag.setOnOff(params_.type == params.type);
188                 }
189                 return true;
190
191         case LFUN_INSET_DIALOG_UPDATE:
192                 flag.setEnabled(true);
193                 return true;
194
195         default:
196                 return InsetCollapsible::getStatus(cur, cmd, flag);
197         }
198 }
199
200
201 bool InsetNote::isMacroScope() const
202 {
203         // LyX note has no latex output
204         if (params_.type == InsetNoteParams::Note)
205                 return true;
206
207         return InsetCollapsible::isMacroScope();
208 }
209
210
211 void InsetNote::latex(otexstream & os, OutputParams const & runparams_in) const
212 {
213         if (params_.type == InsetNoteParams::Note)
214                 return;
215
216         OutputParams runparams(runparams_in);
217         if (params_.type == InsetNoteParams::Comment) {
218                 runparams.inComment = true;
219                 // Ignore files that are exported inside a comment
220                 runparams.exportdata.reset(new ExportData);
221         }
222
223         // the space after the comment in 'a[comment] b' will be eaten by the
224         // comment environment since the space before b is ignored with the
225         // following latex output:
226         //
227         // a%
228         // \begin{comment}
229         // comment
230         // \end{comment}
231         //  b
232         //
233         // Adding {} before ' b' fixes this.
234         // The {} will be automatically added, but only if needed, for all
235         // insets whose InsetLayout Display tag is false. This is achieved
236         // by telling otexstream to protect an immediately following space
237         // and is done for both comment and greyedout insets.
238         InsetCollapsible::latex(os, runparams);
239
240         runparams_in.encoding = runparams.encoding;
241 }
242
243
244 int InsetNote::plaintext(odocstringstream & os,
245                          OutputParams const & runparams_in, size_t max_length) const
246 {
247         if (params_.type == InsetNoteParams::Note)
248                 return 0;
249
250         OutputParams runparams(runparams_in);
251         if (params_.type == InsetNoteParams::Comment) {
252                 runparams.inComment = true;
253                 // Ignore files that are exported inside a comment
254                 runparams.exportdata.reset(new ExportData);
255         }
256         os << '[' << buffer().B_("note") << ":\n";
257         InsetText::plaintext(os, runparams, max_length);
258         os << "\n]";
259
260         return PLAINTEXT_NEWLINE + 1; // one char on a separate line
261 }
262
263
264 void InsetNote::docbook(XMLStream & xs, OutputParams const & runparams_in) const
265 {
266         if (params_.type == InsetNoteParams::Note)
267                 return;
268
269         OutputParams runparams(runparams_in);
270         if (params_.type == InsetNoteParams::Comment) {
271                 xs << xml::StartTag("remark");
272                 xs << xml::CR();
273                 runparams.inComment = true;
274                 // Ignore files that are exported inside a comment
275                 runparams.exportdata.reset(new ExportData);
276         }
277         // Greyed out text is output as such (no way to mark text as greyed out with DocBook).
278
279         InsetText::docbook(xs, runparams);
280
281         if (params_.type == InsetNoteParams::Comment) {
282                 xs << xml::CR();
283                 xs << xml::EndTag("remark");
284                 xs << xml::CR();
285         }
286 }
287
288
289 docstring InsetNote::xhtml(XMLStream & xs, OutputParams const & rp) const
290 {
291         if (params_.type == InsetNoteParams::Note)
292                 return docstring();
293
294         return InsetCollapsible::xhtml(xs, rp);
295 }
296
297
298 void InsetNote::validate(LaTeXFeatures & features) const
299 {
300         switch (params_.type) {
301         case InsetNoteParams::Comment:
302                 if (features.runparams().flavor == OutputParams::HTML)
303                         // we do output this but set display to "none" by default,
304                         // but people might want to use it.
305                         InsetCollapsible::validate(features);
306                 else
307                         // Only do the requires
308                         features.useInsetLayout(getLayout());
309                 break;
310         case InsetNoteParams::Greyedout:
311                 if (features.hasRTLLanguage())
312                         features.require("environ");
313                 InsetCollapsible::validate(features);
314                 break;
315         case InsetNoteParams::Note:
316                 break;
317         }
318 }
319
320
321 string InsetNote::contextMenuName() const
322 {
323         return "context-note";
324 }
325
326 bool InsetNote::allowSpellCheck() const
327 {
328         return (params_.type == InsetNoteParams::Greyedout || lyxrc.spellcheck_notes);
329 }
330
331 FontInfo InsetNote::getFont() const
332 {
333         FontInfo font = getLayout().font();
334         // FIXME: This hardcoded color is a hack!
335         if (params_.type == InsetNoteParams::Greyedout
336             && buffer().params().notefontcolor != lyx::rgbFromHexName("#cccccc")) {
337                 ColorCode c = lcolor.getFromLyXName("notefontcolor");
338                 if (c != Color_none)
339                         font.setColor(c);
340         }
341         return font;
342 }
343
344
345 string InsetNote::params2string(InsetNoteParams const & params)
346 {
347         ostringstream data;
348         data << "note" << ' ';
349         params.write(data);
350         return data.str();
351 }
352
353
354 void InsetNote::string2params(string const & in, InsetNoteParams & params)
355 {
356         params = InsetNoteParams();
357
358         if (in.empty())
359                 return;
360
361         istringstream data(in);
362         Lexer lex;
363         lex.setStream(data);
364         lex.setContext("InsetNote::string2params");
365         lex >> "note";
366         // There are cases, such as when we are called via getStatus() from
367         // Dialog::canApply(), where we are just called with "note" rather
368         // than a full "note Note TYPE".
369         if (!lex.isOK())
370                 return;
371         lex >> "Note";
372
373         params.read(lex);
374 }
375
376
377 } // namespace lyx