]> git.lyx.org Git - lyx.git/blob - src/insets/InsetScript.cpp
Update Win installer for new dictionary links. Untested.
[lyx.git] / src / insets / InsetScript.cpp
1 /**
2  * \file InsetScript.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Georg Baum
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "InsetScript.h"
14
15 #include "Buffer.h"
16 #include "BufferParams.h"
17 #include "BufferView.h"
18 #include "Cursor.h"
19 #include "Dimension.h"
20 #include "DispatchResult.h"
21 #include "Exporter.h"
22 #include "FuncRequest.h"
23 #include "FuncStatus.h"
24 #include "LaTeXFeatures.h"
25 #include "Lexer.h"
26 #include "LyXAction.h"
27 #include "MetricsInfo.h"
28 #include "output_docbook.h"
29 #include "output_xhtml.h"
30 #include "TextClass.h"
31 #include "TextMetrics.h"
32
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 #include "frontends/FontMetrics.h"
40 #include "frontends/Painter.h"
41
42 #include <algorithm>
43
44 using namespace std;
45
46 namespace lyx {
47
48 namespace {
49
50 typedef Translator<string, InsetScriptParams::Type> ScriptTranslator;
51 typedef Translator<docstring, InsetScriptParams::Type> ScriptTranslatorLoc;
52
53 ScriptTranslator const init_scripttranslator()
54 {
55         ScriptTranslator translator("subscript", InsetScriptParams::Subscript);
56         translator.addPair("superscript", InsetScriptParams::Superscript);
57         return translator;
58 }
59
60
61 ScriptTranslatorLoc const init_scripttranslator_loc()
62 {
63         ScriptTranslatorLoc translator(_("Subscript"), InsetScriptParams::Subscript);
64         translator.addPair(_("Superscript"), InsetScriptParams::Superscript);
65         return translator;
66 }
67
68
69 ScriptTranslator const & scripttranslator()
70 {
71         static ScriptTranslator const translator =
72             init_scripttranslator();
73         return translator;
74 }
75
76
77 ScriptTranslatorLoc const & scripttranslator_loc()
78 {
79         static ScriptTranslatorLoc const translator =
80             init_scripttranslator_loc();
81         return translator;
82 }
83
84 } // namespace
85
86
87 InsetScriptParams::InsetScriptParams()
88         : type(Subscript)
89 {}
90
91
92 void InsetScriptParams::write(ostream & os) const
93 {
94         string const label = scripttranslator().find(type);
95         os << "script " << label << "\n";
96 }
97
98
99 void InsetScriptParams::read(Lexer & lex)
100 {
101         string label;
102         lex >> label;
103         if (lex)
104                 type = scripttranslator().find(label);
105 }
106
107
108 int InsetScriptParams::shift(FontInfo const & font) const
109 {
110         frontend::FontMetrics const & fm = theFontMetrics(font);
111         switch (type) {
112         case Subscript:
113                 return fm.maxAscent() / 3;
114         case Superscript:
115                 return -fm.maxAscent() / 2;
116         }
117         // shut up compiler
118         return 0;
119 }
120
121
122 /////////////////////////////////////////////////////////////////////
123 //
124 // InsetScript
125 //
126 /////////////////////////////////////////////////////////////////////
127
128 InsetScript::InsetScript(Buffer * buf, InsetScriptParams const & params)
129         : InsetText(buf, InsetText::PlainLayout), params_(params)
130 {
131         setDrawFrame(false);
132 }
133
134
135 InsetScript::InsetScript(Buffer * buf, string const & label)
136         : InsetText(buf)
137 {
138         setDrawFrame(false);
139         params_.type = scripttranslator().find(label);
140 }
141
142
143 InsetScript::~InsetScript()
144 {
145 }
146
147
148 docstring InsetScript::layoutName() const
149 {
150         return from_ascii("Script:" + scripttranslator().find(params_.type));
151 }
152
153
154 void InsetScript::metrics(MetricsInfo & mi, Dimension & dim) const
155 {
156         int const shift = params_.shift(mi.base.font);
157         // Remember the value of the outser font, so that it can be used in cursorPos.
158         outer_font_ = mi.base.font;
159         Changer dummy = mi.base.changeScript();
160         InsetText::metrics(mi, dim);
161         dim.asc -= shift;
162         dim.des += shift;
163 }
164
165
166 void InsetScript::draw(PainterInfo & pi, int x, int y) const
167 {
168         int const shift = params_.shift(pi.base.font);
169         Changer dummy = pi.base.changeScript();
170         InsetText::draw(pi, x, y + shift);
171 }
172
173
174 void InsetScript::cursorPos(BufferView const & bv,
175                 CursorSlice const & sl, bool boundary, int & x, int & y) const
176 {
177         int const shift = params_.shift(outer_font_);
178         InsetText::cursorPos(bv, sl, boundary, x, y);
179         y += shift;
180 }
181
182
183 void InsetScript::write(ostream & os) const
184 {
185         params_.write(os);
186         text().write(os);
187 }
188
189
190 void InsetScript::read(Lexer & lex)
191 {
192         params_.read(lex);
193         InsetText::read(lex);
194 }
195
196
197 void InsetScript::edit(Cursor & cur, bool front, EntryDirection entry_from)
198 {
199         cur.push(*this);
200         InsetText::edit(cur, front, entry_from);
201 }
202
203
204 Inset * InsetScript::editXY(Cursor & cur, int x, int y)
205 {
206         cur.push(*this);
207         return InsetText::editXY(cur, x, y);
208 }
209
210 void InsetScript::doDispatch(Cursor & cur, FuncRequest & cmd)
211 {
212         switch (cmd.action()) {
213         case LFUN_INSET_MODIFY:
214                 cur.recordUndoInset(this);
215                 string2params(to_utf8(cmd.argument()), params_);
216                 break;
217         default:
218                 InsetText::doDispatch(cur, cmd);
219                 break;
220         }
221 }
222
223
224 bool InsetScript::insetAllowed(InsetCode code) const
225 {
226         switch (code) {
227         // code that is not allowed in a script
228         case BIBITEM_CODE:
229         case BIBTEX_CODE:
230         case BOX_CODE:
231         case BRANCH_CODE:
232         case CAPTION_CODE:
233         case COLLAPSIBLE_CODE:
234         case FLOAT_CODE:
235         case FLOAT_LIST_CODE:
236         case FOOT_CODE:
237         case INCLUDE_CODE:
238         case INDEX_PRINT_CODE:
239         case LISTINGS_CODE:
240         case MARGIN_CODE:
241         case MATH_MACRO_CODE:
242         case MATHMACRO_CODE:
243         case NEWLINE_CODE:
244         case NEWPAGE_CODE:
245         case NOMENCL_PRINT_CODE:
246         case QUOTE_CODE:
247         case PREVIEW_CODE:
248         case TABULAR_CODE:
249         case TOC_CODE:
250         case WRAP_CODE:
251                 return false;
252         default:
253                 return InsetText::insetAllowed(code);
254         }
255 }
256
257 bool InsetScript::getStatus(Cursor & cur, FuncRequest const & cmd,
258                 FuncStatus & flag) const
259 {
260         switch (cmd.action()) {
261         case LFUN_MATH_DISPLAY:
262         case LFUN_BOX_INSERT:
263         case LFUN_BRANCH_INSERT:
264         case LFUN_CAPTION_INSERT:
265         case LFUN_FLOAT_INSERT:
266         case LFUN_FLOAT_LIST_INSERT:
267         case LFUN_FLOAT_WIDE_INSERT:
268         case LFUN_FOOTNOTE_INSERT:
269         case LFUN_INDEX_PRINT:
270         case LFUN_LISTING_INSERT:
271         case LFUN_MARGINALNOTE_INSERT:
272         case LFUN_NEWLINE_INSERT:
273         case LFUN_NEWPAGE_INSERT:
274         case LFUN_NOMENCL_PRINT:
275         case LFUN_PREVIEW_INSERT:
276         case LFUN_QUOTE_INSERT:
277         case LFUN_TABULAR_INSERT:
278         case LFUN_TABULAR_STYLE_INSERT:
279         case LFUN_WRAP_INSERT:
280                 flag.setEnabled(false);
281                 return true;
282         case LFUN_INSET_MODIFY:
283                 flag.setEnabled(true);
284                 return true;
285         case LFUN_COMMAND_SEQUENCE: {
286                 // argument contains ';'-terminated commands
287                 string arg = to_utf8(cmd.argument());
288                 // prevent insertion of display math formulas like AMS align
289                 while (!arg.empty()) {
290                         string first;
291                         arg = support::split(arg, first, ';');
292                         FuncRequest func(lyxaction.lookupFunc(first));
293                         if (func.action() == LFUN_MATH_MUTATE) {
294                                 flag.setEnabled(false);
295                                 return true;
296                         }
297                 }
298                 break;
299         }
300         default:
301                 break;
302         }
303         return InsetText::getStatus(cur, cmd, flag);
304 }
305
306
307 docstring InsetScript::toolTip(BufferView const &, int, int) const
308 {
309         OutputParams rp(&buffer().params().encoding());
310         odocstringstream ods;
311         InsetText::plaintext(ods, rp, 200);
312         docstring content_tip = ods.str();
313         // shorten it if necessary
314         support::truncateWithEllipsis(content_tip, 200);
315         docstring res = scripttranslator_loc().find(params_.type);
316         if (!content_tip.empty())
317                 res += from_ascii(": ") + content_tip;
318         return res;
319 }
320
321
322 int InsetScript::plaintext(odocstringstream & os,
323         OutputParams const & runparams, size_t max_length) const
324 {
325         odocstringstream oss;
326         InsetText::plaintext(oss, runparams, max_length);
327         docstring const text = oss.str();
328         switch (params_.type) {
329         case InsetScriptParams::Subscript:
330                 if (text.size() == 1) {
331                         char_type const c = support::subscript(text[0]);
332                         if (c != text[0]) {
333                                 os.put(c);
334                                 return 0;
335                         }
336                 }
337                 os << '[' << buffer().B_("subscript") << ':';
338                 break;
339         case InsetScriptParams::Superscript:
340                 if (text.size() == 1) {
341                         char_type const c = support::superscript(text[0]);
342                         if (c != text[0]) {
343                                 os.put(c);
344                                 return 0;
345                         }
346                 }
347                 os << '[' << buffer().B_("superscript") << ':';
348                 break;
349         }
350         InsetText::plaintext(os, runparams, max_length);
351         os << ']';
352
353         return PLAINTEXT_NEWLINE;
354 }
355
356
357 void InsetScript::docbook(XMLStream & xs, OutputParams const & runparams) const
358 {
359         docstring cmdname;
360         switch (params_.type) {
361         case InsetScriptParams::Subscript:
362                 cmdname = from_ascii("subscript");
363                 break;
364         case InsetScriptParams::Superscript:
365                 cmdname = from_ascii("superscript");
366                 break;
367         }
368
369         xs << xml::StartTag(cmdname);
370         InsetText::docbook(xs, runparams);
371         xs << xml::EndTag(cmdname);
372 }
373
374
375 string InsetScript::contextMenuName() const
376 {
377         return "context-script";
378 }
379
380
381 string InsetScript::params2string(InsetScriptParams const & params)
382 {
383         ostringstream data;
384         data << "script ";
385         params.write(data);
386         return data.str();
387 }
388
389
390 void InsetScript::string2params(string const & in, InsetScriptParams & params)
391 {
392         params = InsetScriptParams();
393
394         if (in.empty())
395                 return;
396
397         istringstream data(in);
398         Lexer lex;
399         lex.setStream(data);
400         lex.setContext("InsetScript::string2params");
401         lex >> "script" >> "script";
402
403         params.read(lex);
404 }
405
406
407 } // namespace lyx