]> git.lyx.org Git - lyx.git/blob - src/bufferview_funcs.C
Add In nsetOld * argument to updateInset to rebreak the correct par.
[lyx.git] / src / bufferview_funcs.C
1 /**
2  * \file bufferview_funcs.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Jean-Marc Lasgouttes
8  * \author John Levon
9  * \author Angus Leeming
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "bufferview_funcs.h"
17 #include "BufferView.h"
18 #include "paragraph.h"
19 #include "lyxfont.h"
20 #include "lyxlex.h"
21 #include "lyxtext.h"
22 #include "buffer.h"
23 #include "lyx_cb.h"
24 #include "language.h"
25 #include "gettext.h"
26 #include "ParagraphParameters.h"
27 #include "author.h"
28 #include "changes.h"
29
30 #include "frontends/LyXView.h"
31 #include "frontends/Alert.h"
32 #include "mathed/math_cursor.h"
33
34 #include "support/tostr.h"
35 #include "Lsstream.h"
36
37 #include "insets/updatableinset.h"
38 #include "insets/insettext.h"
39 #include <boost/bind.hpp>
40 #include <algorithm>
41
42 using namespace lyx::support;
43
44
45 namespace {
46
47 LyXFont freefont(LyXFont::ALL_IGNORE);
48 bool toggleall(false);
49
50 }
51
52 namespace bv_funcs {
53
54 // Set data using font and toggle
55 // If successful, returns true
56 bool font2string(LyXFont const & font, bool toggle, string & data)
57 {
58         string lang = "ignore";
59         if (font.language())
60                 lang = font.language()->lang();
61
62         ostringstream os;
63         os << "family " << font.family() << '\n'
64            << "series " << font.series() << '\n'
65            << "shape " << font.shape() << '\n'
66            << "size " << font.size() << '\n'
67            << "emph " << font.emph() << '\n'
68            << "underbar " << font.underbar() << '\n'
69            << "noun " << font.noun() << '\n'
70            << "number " << font.number() << '\n'
71            << "color " << font.color() << '\n'
72            << "language " << lang << '\n'
73            << "toggleall " << tostr(toggle);
74         data = STRCONV(os.str());
75         return true;
76 }
77
78
79 // Set font and toggle using data
80 // If successful, returns true
81 bool string2font(string const & data, LyXFont & font, bool & toggle)
82 {
83         istringstream is(STRCONV(data));
84         LyXLex lex(0,0);
85         lex.setStream(is);
86
87         int nset = 0;
88         while (lex.isOK()) {
89                 string token;
90                 if (lex.next())
91                         token = lex.getString();
92
93                 if (token.empty() || !lex.next())
94                         break;
95
96                 if (token == "family") {
97                         int const next = lex.getInteger();
98                         font.setFamily(LyXFont::FONT_FAMILY(next));
99
100                 } else if (token == "series") {
101                         int const next = lex.getInteger();
102                         font.setSeries(LyXFont::FONT_SERIES(next));
103
104                 } else if (token == "shape") {
105                         int const next = lex.getInteger();
106                         font.setShape(LyXFont::FONT_SHAPE(next));
107
108                 } else if (token == "size") {
109                         int const next = lex.getInteger();
110                         font.setSize(LyXFont::FONT_SIZE(next));
111
112                 } else if (token == "emph" || token == "underbar" ||
113                            token == "noun" || token == "number") {
114
115                         int const next = lex.getInteger();
116                         LyXFont::FONT_MISC_STATE const misc =
117                                 LyXFont::FONT_MISC_STATE(next);
118
119                         if (token == "emph")
120                             font.setEmph(misc);
121                         else if (token == "underbar")
122                                 font.setUnderbar(misc);
123                         else if (token == "noun")
124                                 font.setNoun(misc);
125                         else if (token == "number")
126                                 font.setNumber(misc);
127
128                 } else if (token == "color") {
129                         int const next = lex.getInteger();
130                         font.setColor(LColor::color(next));
131
132                 } else if (token == "language") {
133                         string const next = lex.getString();
134                         if (next == "ignore")
135                                 font.setLanguage(ignore_language);
136                         else
137                                 font.setLanguage(languages.getLanguage(next));
138
139                 } else if (token == "toggleall") {
140                         toggle = lex.getBool();
141
142                 } else {
143                         // Unrecognised token
144                         break;
145                 }
146
147                 ++nset;
148         }
149         return (nset > 0);
150 }
151
152
153 string const freefont2string()
154 {
155         string data;
156         if (font2string(freefont, toggleall, data))
157                 return data;
158         return string();
159 }
160
161
162 void update_and_apply_freefont(BufferView * bv, string const & data)
163 {
164         LyXFont font;
165         bool toggle;
166         if (string2font(data, font, toggle)) {
167                 freefont = font;
168                 toggleall = toggle;
169                 apply_freefont(bv);
170         }
171 }
172
173
174 void apply_freefont(BufferView * bv)
175 {
176         toggleAndShow(bv, freefont, toggleall);
177         bv->owner()->view_state_changed();
178         bv->owner()->message(_("Character set"));
179 }
180
181
182 void emph(BufferView * bv)
183 {
184         LyXFont font(LyXFont::ALL_IGNORE);
185         font.setEmph(LyXFont::TOGGLE);
186         toggleAndShow(bv, font);
187 }
188
189
190 void bold(BufferView * bv)
191 {
192         LyXFont font(LyXFont::ALL_IGNORE);
193         font.setSeries(LyXFont::BOLD_SERIES);
194         toggleAndShow(bv, font);
195 }
196
197
198 void noun(BufferView * bv)
199 {
200         LyXFont font(LyXFont::ALL_IGNORE);
201         font.setNoun(LyXFont::TOGGLE);
202         toggleAndShow(bv, font);
203 }
204
205
206 void number(BufferView * bv)
207 {
208         LyXFont font(LyXFont::ALL_IGNORE);
209         font.setNumber(LyXFont::TOGGLE);
210         toggleAndShow(bv, font);
211 }
212
213
214 void lang(BufferView * bv, string const & l)
215 {
216         Language const * lang = languages.getLanguage(l);
217         if (!lang)
218                 return;
219
220         LyXFont font(LyXFont::ALL_IGNORE);
221         font.setLanguage(lang);
222         toggleAndShow(bv, font);
223 }
224
225
226 bool changeDepth(BufferView * bv, LyXText * text, DEPTH_CHANGE type, bool test_only)
227 {
228         if (!bv->available() || !text)
229                 return false;
230
231         if (test_only)
232                 return text->changeDepth(type, true);
233
234         bool const changed = text->changeDepth(type, false);
235         if (text->inset_owner)
236                 bv->updateInset(text->inset_owner);
237         return changed;
238 }
239
240
241 void code(BufferView * bv)
242 {
243         LyXFont font(LyXFont::ALL_IGNORE);
244         font.setFamily(LyXFont::TYPEWRITER_FAMILY); // no good
245         toggleAndShow(bv, font);
246 }
247
248
249 void sans(BufferView * bv)
250 {
251         LyXFont font(LyXFont::ALL_IGNORE);
252         font.setFamily(LyXFont::SANS_FAMILY);
253         toggleAndShow(bv, font);
254 }
255
256
257 void roman(BufferView * bv)
258 {
259         LyXFont font(LyXFont::ALL_IGNORE);
260         font.setFamily(LyXFont::ROMAN_FAMILY);
261         toggleAndShow(bv, font);
262 }
263
264
265 void styleReset(BufferView * bv)
266 {
267         LyXFont font(LyXFont::ALL_INHERIT, ignore_language);
268         toggleAndShow(bv, font);
269 }
270
271
272 void underline(BufferView * bv)
273 {
274         LyXFont font(LyXFont::ALL_IGNORE);
275         font.setUnderbar(LyXFont::TOGGLE);
276         toggleAndShow(bv, font);
277 }
278
279
280 void fontSize(BufferView * bv, string const & size)
281 {
282         LyXFont font(LyXFont::ALL_IGNORE);
283         font.setLyXSize(size);
284         toggleAndShow(bv, font);
285 }
286
287
288 // Returns the current font and depth as a message.
289 string const currentState(BufferView * bv)
290 {
291         if (!bv->available())
292                 return string();
293
294         if (mathcursor)
295                 return mathcursor->info();
296
297         ostringstream state;
298
299         LyXText * text = bv->getLyXText();
300         Buffer * buffer = bv->buffer();
301         LyXCursor const & c(text->cursor);
302
303         bool const show_change = buffer->params.tracking_changes
304                 && c.pos() != c.par()->size()
305                 && c.par()->lookupChange(c.pos()) != Change::UNCHANGED;
306
307         if (show_change) {
308                 Change change(c.par()->lookupChangeFull(c.pos()));
309                 Author const & a(bv->buffer()->authors().get(change.author));
310                 state << _("Change: ") << a.name();
311                 if (!a.email().empty()) {
312                         state << " (" << a.email() << ")";
313                 }
314                 if (change.changetime)
315                         state << _(" at ") << ctime(&change.changetime);
316                 state << " : ";
317         }
318
319         // I think we should only show changes from the default
320         // font. (Asger)
321         LyXFont font = text->real_current_font;
322         LyXFont const & defaultfont =
323                 buffer->params.getLyXTextClass().defaultfont();
324         font.reduce(defaultfont);
325
326         // avoid _(...) re-entrance problem
327         string const s = font.stateText(&buffer->params);
328         state << bformat(_("Font: %1$s"), s);
329
330         // state << bformat(_("Font: %1$s"), font.stateText(&buffer->params));
331
332         // The paragraph depth
333         int depth = text->getDepth();
334         if (depth > 0)
335                 state << bformat(_(", Depth: %1$s"), tostr(depth));
336
337         // The paragraph spacing, but only if different from
338         // buffer spacing.
339         if (!text->cursor.par()->params().spacing().isDefault()) {
340                 Spacing::Space cur_space =
341                         text->cursor.par()->params().spacing().getSpace();
342                 state << _(", Spacing: ");
343
344                 switch (cur_space) {
345                 case Spacing::Single:
346                         state << _("Single");
347                         break;
348                 case Spacing::Onehalf:
349                         state << _("OneHalf");
350                         break;
351                 case Spacing::Double:
352                         state << _("Double");
353                         break;
354                 case Spacing::Other:
355                         state << _("Other (")
356                               << text->cursor.par()->params().spacing().getValue()
357                               << ')';
358                         break;
359                 case Spacing::Default:
360                         // should never happen, do nothing
361                         break;
362                 }
363         }
364 #ifdef DEVEL_VERSION
365         state << _(", Paragraph: ") << text->cursor.par()->id();
366         state << "  Inset: " <<
367                 (text->cursor.par()->inInset() ? text->cursor.par()->inInset()->id() : -1);
368 #endif
369         return STRCONV(state.str());
370 }
371
372
373 /* Does the actual toggle job of the calls above.
374  * Also shows the current font state.
375  */
376 void toggleAndShow(BufferView * bv, LyXFont const & font, bool toggleall)
377 {
378         if (!bv->available())
379                 return;
380
381         if (bv->theLockingInset()) {
382                 bv->theLockingInset()->setFont(bv, font, toggleall);
383                 return;
384         }
385
386         LyXText * text = bv->getLyXText();
387         text->toggleFree(font, toggleall);
388         bv->update();
389
390         if (font.language() != ignore_language ||
391             font.number() != LyXFont::IGNORE) {
392                 LyXCursor & cursor = text->cursor;
393                 text->computeBidiTables(text->cursor.par(), bv->buffer(),
394                         text->cursorRow());
395                 if (cursor.boundary() !=
396                     text->isBoundary(bv->buffer(), *cursor.par(), cursor.pos(),
397                                      text->real_current_font))
398                         text->setCursor(cursor.par(), cursor.pos(),
399                                         false, !cursor.boundary());
400         }
401 }
402
403
404 // deletes a selection during an insertion
405 void replaceSelection(LyXText * lt)
406 {
407         if (lt->selection.set()) {
408                 lt->cutSelection(true, false);
409                 lt->bv()->update();
410         }
411 }
412
413 }; // namespace bv_funcs