]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiCharacter.cpp
Fix a crash following the input of an invalid paragraph separation value in the docum...
[lyx.git] / src / frontends / qt4 / GuiCharacter.cpp
1 /**
2  * \file GuiCharacter.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 Edwin Leuven
8  * \author John Levon
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "GuiCharacter.h"
16
17 #include "qt_helpers.h"
18 #include "Font.h"
19 #include "Buffer.h"
20 #include "BufferParams.h"
21 #include "FuncRequest.h"
22 #include "Language.h"
23
24 #include <QCloseEvent>
25
26 using namespace std;
27
28 namespace lyx {
29 namespace frontend {
30
31 static vector<ShapePair> const getShapeData()
32 {
33         vector<ShapePair> shape(6);
34
35         ShapePair pr;
36
37         pr.first = qt_("No change");
38         pr.second = IGNORE_SHAPE;
39         shape[0] = pr;
40
41         pr.first = qt_("Upright");
42         pr.second = UP_SHAPE;
43         shape[1] = pr;
44
45         pr.first = qt_("Italic");
46         pr.second = ITALIC_SHAPE;
47         shape[2] = pr;
48
49         pr.first = qt_("Slanted");
50         pr.second = SLANTED_SHAPE;
51         shape[3] = pr;
52
53         pr.first = qt_("Small Caps");
54         pr.second = SMALLCAPS_SHAPE;
55         shape[4] = pr;
56
57         pr.first = qt_("Reset");
58         pr.second = INHERIT_SHAPE;
59         shape[5] = pr;
60
61         return shape;
62 }
63
64
65 static vector<SizePair> const getSizeData()
66 {
67         vector<SizePair> size(14);
68
69         SizePair pr;
70
71         pr.first = qt_("No change");
72         pr.second = FONT_SIZE_IGNORE;
73         size[0] = pr;
74
75         pr.first = qt_("Tiny");
76         pr.second = FONT_SIZE_TINY;
77         size[1] = pr;
78
79         pr.first = qt_("Smallest");
80         pr.second = FONT_SIZE_SCRIPT;
81         size[2] = pr;
82
83         pr.first = qt_("Smaller");
84         pr.second = FONT_SIZE_FOOTNOTE;
85         size[3] = pr;
86
87         pr.first = qt_("Small");
88         pr.second = FONT_SIZE_SMALL;
89         size[4] = pr;
90
91         pr.first = qt_("Normal");
92         pr.second = FONT_SIZE_NORMAL;
93         size[5] = pr;
94
95         pr.first = qt_("Large");
96         pr.second = FONT_SIZE_LARGE;
97         size[6] = pr;
98
99         pr.first = qt_("Larger");
100         pr.second = FONT_SIZE_LARGER;
101         size[7] = pr;
102
103         pr.first = qt_("Largest");
104         pr.second = FONT_SIZE_LARGEST;
105         size[8] = pr;
106
107         pr.first = qt_("Huge");
108         pr.second = FONT_SIZE_HUGE;
109         size[9] = pr;
110
111         pr.first = qt_("Huger");
112         pr.second = FONT_SIZE_HUGER;
113         size[10] = pr;
114
115         pr.first = qt_("Increase");
116         pr.second = FONT_SIZE_INCREASE;
117         size[11] = pr;
118
119         pr.first = qt_("Decrease");
120         pr.second = FONT_SIZE_DECREASE;
121         size[12] = pr;
122
123         pr.first = qt_("Reset");
124         pr.second = FONT_SIZE_INHERIT;
125         size[13] = pr;
126
127         return size;
128 }
129
130
131 static vector<BarPair> const getBarData()
132 {
133         vector<BarPair> bar(5);
134
135         BarPair pr;
136
137         pr.first = qt_("No change");
138         pr.second = IGNORE;
139         bar[0] = pr;
140
141         pr.first = qt_("Emph");
142         pr.second = EMPH_TOGGLE;
143         bar[1] = pr;
144
145         pr.first = qt_("Underbar");
146         pr.second = UNDERBAR_TOGGLE;
147         bar[2] = pr;
148
149         pr.first = qt_("Noun");
150         pr.second = NOUN_TOGGLE;
151         bar[3] = pr;
152
153         pr.first = qt_("Reset");
154         pr.second = INHERIT;
155         bar[4] = pr;
156
157         return bar;
158 }
159
160
161 static vector<ColorPair> const getColorData()
162 {
163         vector<ColorPair> color(11);
164
165         ColorPair pr;
166
167         pr.first = qt_("No change");
168         pr.second = Color_ignore;
169         color[0] = pr;
170
171         pr.first = qt_("No color");
172         pr.second = Color_none;
173         color[1] = pr;
174
175         pr.first = qt_("Black");
176         pr.second = Color_black;
177         color[2] = pr;
178
179         pr.first = qt_("White");
180         pr.second = Color_white;
181         color[3] = pr;
182
183         pr.first = qt_("Red");
184         pr.second = Color_red;
185         color[4] = pr;
186
187         pr.first = qt_("Green");
188         pr.second = Color_green;
189         color[5] = pr;
190
191         pr.first = qt_("Blue");
192         pr.second = Color_blue;
193         color[6] = pr;
194
195         pr.first = qt_("Cyan");
196         pr.second = Color_cyan;
197         color[7] = pr;
198
199         pr.first = qt_("Magenta");
200         pr.second = Color_magenta;
201         color[8] = pr;
202
203         pr.first = qt_("Yellow");
204         pr.second = Color_yellow;
205         color[9] = pr;
206
207         pr.first = qt_("Reset");
208         pr.second = Color_inherit;
209         color[10] = pr;
210
211         return color;
212 }
213
214
215 static vector<SeriesPair> const getSeriesData()
216 {
217         vector<SeriesPair> series(4);
218
219         SeriesPair pr;
220
221         pr.first = qt_("No change");
222         pr.second = IGNORE_SERIES;
223         series[0] = pr;
224
225         pr.first = qt_("Medium");
226         pr.second = MEDIUM_SERIES;
227         series[1] = pr;
228
229         pr.first = qt_("Bold");
230         pr.second = BOLD_SERIES;
231         series[2] = pr;
232
233         pr.first = qt_("Reset");
234         pr.second = INHERIT_SERIES;
235         series[3] = pr;
236
237         return series;
238 }
239
240
241 static vector<FamilyPair> const getFamilyData()
242 {
243         vector<FamilyPair> family(5);
244
245         FamilyPair pr;
246
247         pr.first = qt_("No change");
248         pr.second = IGNORE_FAMILY;
249         family[0] = pr;
250
251         pr.first = qt_("Roman");
252         pr.second = ROMAN_FAMILY;
253         family[1] = pr;
254
255         pr.first = qt_("Sans Serif");
256         pr.second = SANS_FAMILY;
257         family[2] = pr;
258
259         pr.first = qt_("Typewriter");
260         pr.second = TYPEWRITER_FAMILY;
261         family[3] = pr;
262
263         pr.first = qt_("Reset");
264         pr.second = INHERIT_FAMILY;
265         family[4] = pr;
266
267         return family;
268 }
269
270
271 GuiCharacter::GuiCharacter(GuiView & lv)
272         : GuiDialog(lv, "character", qt_("Text Style")), font_(ignore_font),
273           toggleall_(false), reset_lang_(false)
274 {
275         setupUi(this);
276
277         connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
278         connect(applyPB, SIGNAL(clicked()), this, SLOT(slotApply()));
279         connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose()));
280
281         connect(miscCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
282         connect(sizeCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
283         connect(familyCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
284         connect(seriesCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
285         connect(shapeCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
286         connect(colorCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
287         connect(langCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
288         connect(toggleallCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
289
290 #ifdef Q_WS_MACX
291         // On Mac it's common to have tool windows which are always in the
292         // foreground and are hidden when the main window is not focused.
293         setWindowFlags(Qt::Tool);
294         autoapplyCB->setChecked(true);
295 #endif
296
297         family = getFamilyData();
298         series = getSeriesData();
299         shape  = getShapeData();
300         size   = getSizeData();
301         bar    = getBarData();
302         color  = getColorData();
303         language = getLanguageData(true);
304
305         for (vector<FamilyPair>::const_iterator cit = family.begin();
306                 cit != family.end(); ++cit) {
307                 familyCO->addItem(cit->first);
308         }
309
310         for (vector<SeriesPair>::const_iterator cit = series.begin();
311                 cit != series.end(); ++cit) {
312                 seriesCO->addItem(cit->first);
313         }
314         for (vector<ShapePair>::const_iterator cit = shape.begin();
315                 cit != shape.end(); ++cit) {
316                 shapeCO->addItem(cit->first);
317         }
318         for (vector<SizePair>::const_iterator cit = size.begin();
319                 cit != size.end(); ++cit) {
320                 sizeCO->addItem(cit->first);
321         }
322         for (vector<BarPair>::const_iterator cit = bar.begin();
323                 cit != bar.end(); ++cit) {
324                 miscCO->addItem(cit->first);
325         }
326         for (vector<ColorPair>::const_iterator cit = color.begin();
327                 cit != color.end(); ++cit) {
328                 colorCO->addItem(cit->first);
329         }
330         for (vector<LanguagePair>::const_iterator cit = language.begin();
331                 cit != language.end(); ++cit) {
332                 langCO->addItem(toqstr(cit->first));
333         }
334
335         bc().setPolicy(ButtonPolicy::OkApplyCancelReadOnlyPolicy);
336         bc().setOK(okPB);
337         bc().setApply(applyPB);
338         bc().setCancel(closePB);
339         bc().addReadOnly(familyCO);
340         bc().addReadOnly(seriesCO);
341         bc().addReadOnly(sizeCO);
342         bc().addReadOnly(shapeCO);
343         bc().addReadOnly(miscCO);
344         bc().addReadOnly(langCO);
345         bc().addReadOnly(colorCO);
346         bc().addReadOnly(toggleallCB);
347         bc().addReadOnly(autoapplyCB);
348
349 // FIXME: hack to work around resizing bug in Qt >= 4.2
350 // bug verified with Qt 4.2.{0-3} (JSpitzm)
351 #if QT_VERSION >= 0x040200
352         // qt resizes the comboboxes only after show(), so ...
353         QDialog::show();
354 #endif
355 }
356
357
358 void GuiCharacter::change_adaptor()
359 {
360         changed();
361
362         if (!autoapplyCB->isChecked())
363                 return;
364
365         // to be really good here, we should set the combos to the values of
366         // the current text, and make it appear as "no change" if the values
367         // stay the same between applys. Might be difficult though wrt to a
368         // moved cursor - jbl
369         slotApply();
370         familyCO->setCurrentIndex(0);
371         seriesCO->setCurrentIndex(0);
372         sizeCO->setCurrentIndex(0);
373         shapeCO->setCurrentIndex(0);
374         miscCO->setCurrentIndex(0);
375         langCO->setCurrentIndex(0);
376         colorCO->setCurrentIndex(0);
377 }
378
379
380 void GuiCharacter::closeEvent(QCloseEvent * e)
381 {
382         slotClose();
383         GuiDialog::closeEvent(e);
384 }
385
386
387 template<class A, class B>
388 static int findPos2nd(vector<pair<A, B> > const & vec, B const & val)
389 {
390         typedef typename vector<pair<A, B> >::const_iterator
391                 const_iterator;
392
393         for (const_iterator cit = vec.begin(); cit != vec.end(); ++cit)
394                 if (cit->second == val)
395                         return int(cit - vec.begin());
396
397         return 0;
398 }
399
400
401 void GuiCharacter::updateContents()
402 {
403         familyCO->setCurrentIndex(findPos2nd(family, getFamily()));
404         seriesCO->setCurrentIndex(findPos2nd(series, getSeries()));
405         shapeCO->setCurrentIndex(findPos2nd(shape, getShape()));
406         sizeCO->setCurrentIndex(findPos2nd(size, getSize()));
407         miscCO->setCurrentIndex(findPos2nd(bar, getBar()));
408         colorCO->setCurrentIndex(findPos2nd(color, getColor()));
409         langCO->setCurrentIndex(findPos2nd(language, getLanguage()));
410
411         toggleallCB->setChecked(toggleall_);
412 }
413
414
415 void GuiCharacter::applyView()
416 {
417         setFamily(family[familyCO->currentIndex()].second);
418         setSeries(series[seriesCO->currentIndex()].second);
419         setShape(shape[shapeCO->currentIndex()].second);
420         setSize(size[sizeCO->currentIndex()].second);
421         setBar(bar[miscCO->currentIndex()].second);
422         setColor(color[colorCO->currentIndex()].second);
423         setLanguage(language[langCO->currentIndex()].second);
424
425         toggleall_ = toggleallCB->isChecked();
426 }
427
428
429 bool GuiCharacter::initialiseParams(string const &)
430 {
431         // so that the user can press Ok
432         if (getFamily()    != IGNORE_FAMILY
433             || getSeries() != IGNORE_SERIES
434             || getShape()  != IGNORE_SHAPE
435             || getSize()   != FONT_SIZE_IGNORE
436             || getBar()    != IGNORE
437             || getColor()  != Color_ignore
438             || font_.language() != ignore_language)
439                 setButtonsValid(true);
440
441         return true;
442 }
443
444
445 void GuiCharacter::dispatchParams()
446 {
447         dispatch(FuncRequest(getLfun(), font_.toString(toggleall_)));
448 }
449
450
451 FontFamily GuiCharacter::getFamily() const
452 {
453         return font_.fontInfo().family();
454 }
455
456
457 void GuiCharacter::setFamily(FontFamily val)
458 {
459         font_.fontInfo().setFamily(val);
460 }
461
462
463 FontSeries GuiCharacter::getSeries() const
464 {
465         return font_.fontInfo().series();
466 }
467
468
469 void GuiCharacter::setSeries(FontSeries val)
470 {
471         font_.fontInfo().setSeries(val);
472 }
473
474
475 FontShape GuiCharacter::getShape() const
476 {
477         return font_.fontInfo().shape();
478 }
479
480
481 void GuiCharacter::setShape(FontShape val)
482 {
483         font_.fontInfo().setShape(val);
484 }
485
486
487 FontSize GuiCharacter::getSize() const
488 {
489         return font_.fontInfo().size();
490 }
491
492
493 void GuiCharacter::setSize(FontSize val)
494 {
495         font_.fontInfo().setSize(val);
496 }
497
498
499 FontState GuiCharacter::getBar() const
500 {
501         if (font_.fontInfo().emph() == FONT_TOGGLE)
502                 return EMPH_TOGGLE;
503
504         if (font_.fontInfo().underbar() == FONT_TOGGLE)
505                 return UNDERBAR_TOGGLE;
506
507         if (font_.fontInfo().noun() == FONT_TOGGLE)
508                 return NOUN_TOGGLE;
509
510         if (font_.fontInfo().emph() == FONT_IGNORE
511             && font_.fontInfo().underbar() == FONT_IGNORE
512             && font_.fontInfo().noun() == FONT_IGNORE)
513                 return IGNORE;
514
515         return INHERIT;
516 }
517
518
519 void GuiCharacter::setBar(FontState val)
520 {
521         switch (val) {
522         case IGNORE:
523                 font_.fontInfo().setEmph(FONT_IGNORE);
524                 font_.fontInfo().setUnderbar(FONT_IGNORE);
525                 font_.fontInfo().setNoun(FONT_IGNORE);
526                 break;
527
528         case EMPH_TOGGLE:
529                 font_.fontInfo().setEmph(FONT_TOGGLE);
530                 break;
531
532         case UNDERBAR_TOGGLE:
533                 font_.fontInfo().setUnderbar(FONT_TOGGLE);
534                 break;
535
536         case NOUN_TOGGLE:
537                 font_.fontInfo().setNoun(FONT_TOGGLE);
538                 break;
539
540         case INHERIT:
541                 font_.fontInfo().setEmph(FONT_INHERIT);
542                 font_.fontInfo().setUnderbar(FONT_INHERIT);
543                 font_.fontInfo().setNoun(FONT_INHERIT);
544                 break;
545         }
546 }
547
548
549 ColorCode GuiCharacter::getColor() const
550 {
551         return font_.fontInfo().color();
552 }
553
554
555 void GuiCharacter::setColor(ColorCode val)
556 {
557         switch (val) {
558         case Color_ignore:
559         case Color_none:
560         case Color_black:
561         case Color_white:
562         case Color_red:
563         case Color_green:
564         case Color_blue:
565         case Color_cyan:
566         case Color_magenta:
567         case Color_yellow:
568         case Color_inherit:
569                 font_.fontInfo().setColor(val);
570                 break;
571         default:
572                 break;
573         }
574 }
575
576
577 string GuiCharacter::getLanguage() const
578 {
579         if (reset_lang_)
580                 return "reset";
581         if (font_.language())
582                 return font_.language()->lang();
583         return "ignore";
584 }
585
586
587 void GuiCharacter::setLanguage(string const & val)
588 {
589         if (val == "ignore")
590                 font_.setLanguage(ignore_language);
591         else if (val == "reset") {
592                 reset_lang_ = true;
593                 // Ignored in getLanguage, but needed for dispatchParams
594                 font_.setLanguage(buffer().params().language);
595         } else {
596                 font_.setLanguage(languages.getLanguage(val));
597         }
598 }
599
600
601 Dialog * createGuiCharacter(GuiView & lv) { return new GuiCharacter(lv); }
602
603
604 } // namespace frontend
605 } // namespace lyx
606
607 #include "GuiCharacter_moc.cpp"