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