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