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