1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /***************************************************************************
8 fontcombo.cpp - description
9 -------------------
10 begin : Die Jun 17 2003
11 copyright : (C) 2003 by Franz Schmid
12 email : Franz.Schmid@altmuehlnet.de
13 ***************************************************************************/
14
15 /***************************************************************************
16 * *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 ***************************************************************************/
23
24 #include <QAbstractItemView>
25 #include <QEvent>
26 #include <QFont>
27 #include <QFontInfo>
28 #include <QGridLayout>
29 #include <QLabel>
30 #include <QPixmap>
31 #include <QStringList>
32 #include <QToolTip>
33
34 #include "fontcombo.h"
35 #include "iconmanager.h"
36 #include "prefsmanager.h"
37 #include "scpage.h"
38 #include "scribusapp.h"
39 #include "scribusdoc.h"
40 #include "util.h"
41
42 #include "fonts/scface.h"
43
FontCombo(QWidget * pa)44 FontCombo::FontCombo(QWidget* pa) : QComboBox(pa),
45 prefsManager(PrefsManager::instance())
46 {
47 iconSetChange();
48 setEditable(true);
49 setValidator(new FontComboValidator(this));
50 setInsertPolicy(QComboBox::NoInsert);
51 setItemDelegate(new FontFamilyDelegate(this));
52 RebuildList(nullptr);
53
54 connect(ScQApp, SIGNAL(iconSetChanged()), this, SLOT(iconSetChange()));
55 }
56
iconSetChange()57 void FontCombo::iconSetChange()
58 {
59 IconManager& iconManager = IconManager::instance();
60 ttfFont = iconManager.loadPixmap("font_truetype16.png");
61 otfFont = iconManager.loadPixmap("font_otf16.png");
62 psFont = iconManager.loadPixmap("font_type1_16.png");
63 substFont = iconManager.loadPixmap("font_subst16.png");
64 }
65
RebuildList(ScribusDoc * currentDoc,bool forAnnotation,bool forSubstitute)66 void FontCombo::RebuildList(ScribusDoc *currentDoc, bool forAnnotation, bool forSubstitute)
67 {
68 clear();
69 QMap<QString, QString> rlist;
70 SCFontsIterator it(prefsManager.appPrefs.fontPrefs.AvailFonts);
71 for ( ; it.hasNext(); it.next())
72 {
73 if (it.current().usable())
74 {
75 if (currentDoc != nullptr)
76 {
77 if (currentDoc->documentFileName() == it.current().localForDocument() || it.current().localForDocument().isEmpty())
78 rlist.insert(it.currentKey().toLower(), it.currentKey());
79 }
80 else
81 rlist.insert(it.currentKey().toLower(), it.currentKey());
82 }
83 }
84 for (QMap<QString,QString>::Iterator it2 = rlist.begin(); it2 != rlist.end(); ++it2)
85 {
86 ScFace fon = prefsManager.appPrefs.fontPrefs.AvailFonts[it2.value()];
87 if (! fon.usable() )
88 continue;
89 ScFace::FontType type = fon.type();
90 if ((forAnnotation) && ((type == ScFace::TYPE1) || (type == ScFace::OTF) || fon.subset()))
91 continue;
92 if (forSubstitute && fon.isReplacement())
93 continue;
94 if (fon.isReplacement())
95 addItem(substFont, it2.value());
96 else if (type == ScFace::OTF)
97 addItem(otfFont, it2.value());
98 else if (type == ScFace::TYPE1)
99 addItem(psFont, it2.value());
100 else if (type == ScFace::TTF)
101 addItem(ttfFont, it2.value());
102 }
103 QAbstractItemView *tmpView = view();
104 int tmpWidth = tmpView->sizeHintForColumn(0);
105 if (tmpWidth > 0)
106 tmpView->setMinimumWidth(tmpWidth + 24);
107 }
108
FontComboH(QWidget * parent,bool labels)109 FontComboH::FontComboH(QWidget* parent, bool labels) :
110 QWidget(parent),
111 prefsManager(PrefsManager::instance()),
112 showLabels(labels)
113 {
114 currDoc = nullptr;
115 ttfFont = IconManager::instance().loadPixmap("font_truetype16.png");
116 otfFont = IconManager::instance().loadPixmap("font_otf16.png");
117 psFont = IconManager::instance().loadPixmap("font_type1_16.png");
118 substFont = IconManager::instance().loadPixmap("font_subst16.png");
119 fontComboLayout = new QGridLayout(this);
120 fontComboLayout->setContentsMargins(0, 0, 0, 0);
121 if (showLabels)
122 fontComboLayout->setSpacing(6);
123 else
124 fontComboLayout->setSpacing(3);
125 int col = 0;
126 if (showLabels)
127 {
128 fontFaceLabel = new QLabel(this);
129 fontStyleLabel = new QLabel(this);
130 fontComboLayout->addWidget(fontFaceLabel, 0, 0);
131 fontComboLayout->addWidget(fontStyleLabel, 1, 0);
132 fontComboLayout->setColumnStretch(1, 10);
133 col = 1;
134 }
135 fontFamily = new QComboBox(this);
136 fontFamily->setEditable(true);
137 fontFamily->setValidator(new FontComboValidator(fontFamily));
138 fontFamily->setInsertPolicy(QComboBox::NoInsert);
139 fontFamily->setItemDelegate(new FontFamilyDelegate(this));
140 fontComboLayout->addWidget(fontFamily, 0, col);
141 fontStyle = new QComboBox(this);
142 fontComboLayout->addWidget(fontStyle, 1, col);
143 isForAnnotation = true; // this is merely to ensure that the list is rebuilt
144 rebuildList(nullptr);
145 connect(fontFamily, SIGNAL(activated(int)), this, SLOT(familySelected(int)));
146 connect(fontStyle, SIGNAL(activated(int)), this, SLOT(styleSelected(int)));
147 languageChange();
148 }
149
changeEvent(QEvent * e)150 void FontComboH::changeEvent(QEvent *e)
151 {
152 if (e->type() == QEvent::LanguageChange)
153 languageChange();
154 else
155 QWidget::changeEvent(e);
156 }
157
languageChange()158 void FontComboH::languageChange()
159 {
160 if (showLabels)
161 {
162 fontFaceLabel->setText( tr("Family:"));
163 fontStyleLabel->setText( tr("Style:"));
164 }
165 fontFamily->setToolTip( tr("Font Family of Selected Text or Text Frame"));
166 fontStyle->setToolTip( tr("Font Style of Selected Text or Text Frame"));
167 }
168
familySelected(int id)169 void FontComboH::familySelected(int id)
170 {
171 disconnect(fontStyle, SIGNAL(activated(int)), this, SLOT(styleSelected(int)));
172 QString curr = fontStyle->currentText();
173 fontStyle->clear();
174 QString fntFamily = fontFamily->itemText(id);
175 QStringList slist, styleList = prefsManager.appPrefs.fontPrefs.AvailFonts.fontMap[fntFamily];
176 for (QStringList::ConstIterator it = styleList.constBegin(); it != styleList.constEnd(); ++it)
177 {
178 SCFonts::ConstIterator fIt = prefsManager.appPrefs.fontPrefs.AvailFonts.find(fntFamily + " " + *it);
179 if (fIt != prefsManager.appPrefs.fontPrefs.AvailFonts.constEnd())
180 {
181 if (!fIt->usable() || fIt->isReplacement())
182 continue;
183 slist.append(*it);
184 }
185 }
186 slist.sort();
187 fontStyle->addItems(slist);
188 if (slist.contains(curr))
189 setCurrentComboItem(fontStyle, curr);
190 else if (slist.contains("Regular"))
191 setCurrentComboItem(fontStyle, "Regular");
192 else if (slist.contains("Roman"))
193 setCurrentComboItem(fontStyle, "Roman");
194 emit fontSelected(fontFamily->itemText(id) + " " + fontStyle->currentText());
195 connect(fontStyle, SIGNAL(activated(int)), this, SLOT(styleSelected(int)));
196 }
197
styleSelected(int id)198 void FontComboH::styleSelected(int id)
199 {
200 emit fontSelected(fontFamily->currentText() + " " + fontStyle->itemText(id));
201 }
202
currentFont()203 QString FontComboH::currentFont()
204 {
205 return fontFamily->currentText() + " " + fontStyle->currentText();
206 }
207
setCurrentFont(const QString & f)208 void FontComboH::setCurrentFont(const QString& f)
209 {
210 QString family = prefsManager.appPrefs.fontPrefs.AvailFonts[f].family();
211 QString style = prefsManager.appPrefs.fontPrefs.AvailFonts[f].style();
212 // If we already have the correct font+style, nothing to do
213 if ((fontFamily->currentText() == family) && (fontStyle->currentText() == style))
214 return;
215 bool familySigBlocked = fontFamily->blockSignals(true);
216 bool styleSigBlocked = fontStyle->blockSignals(true);
217 setCurrentComboItem(fontFamily, family);
218 fontStyle->clear();
219 QStringList slist = prefsManager.appPrefs.fontPrefs.AvailFonts.fontMap[family];
220 slist.sort();
221 QStringList ilist;
222 if (currDoc != nullptr)
223 {
224 for (QStringList::ConstIterator it3 = slist.constBegin(); it3 != slist.constEnd(); ++it3)
225 {
226 SCFonts::ConstIterator fIt = prefsManager.appPrefs.fontPrefs.AvailFonts.find(family + " " + *it3);
227 if (fIt != prefsManager.appPrefs.fontPrefs.AvailFonts.constEnd())
228 {
229 if (!fIt->usable() || fIt->isReplacement())
230 continue;
231 if ((currDoc->documentFileName() == fIt->localForDocument()) || (fIt->localForDocument().isEmpty()))
232 ilist.append(*it3);
233 }
234 }
235 fontStyle->addItems(ilist);
236 }
237 else
238 fontStyle->addItems(slist);
239 setCurrentComboItem(fontStyle, style);
240 fontFamily->blockSignals(familySigBlocked);
241 fontStyle->blockSignals(styleSigBlocked);
242 }
243
rebuildList(ScribusDoc * currentDoc,bool forAnnotation,bool forSubstitute)244 void FontComboH::rebuildList(ScribusDoc *currentDoc, bool forAnnotation, bool forSubstitute)
245 {
246 // if we already have the proper fonts loaded, we need to do nothing
247 if ((currDoc == currentDoc) && (forAnnotation == isForAnnotation) && (isForSubstitute == forSubstitute))
248 return;
249 currDoc = currentDoc;
250 isForAnnotation = forAnnotation;
251 isForSubstitute = forSubstitute;
252 bool familySigBlocked = fontFamily->blockSignals(true);
253 bool styleSigBlocked = fontStyle->blockSignals(true);
254 fontFamily->clear();
255 fontStyle->clear();
256 QStringList rlist = prefsManager.appPrefs.fontPrefs.AvailFonts.fontMap.keys();
257 QMap<QString, ScFace::FontType> flist;
258 flist.clear();
259 for (QStringList::ConstIterator it2 = rlist.constBegin(); it2 != rlist.constEnd(); ++it2)
260 {
261 if (currentDoc != nullptr)
262 {
263 QStringList slist = prefsManager.appPrefs.fontPrefs.AvailFonts.fontMap[*it2];
264 slist.sort();
265 for (QStringList::ConstIterator it3 = slist.constBegin(); it3 != slist.constEnd(); ++it3)
266 {
267 if ( prefsManager.appPrefs.fontPrefs.AvailFonts.contains(*it2 + " " + *it3))
268 {
269 const ScFace& fon(prefsManager.appPrefs.fontPrefs.AvailFonts[*it2 + " " + *it3]);
270 ScFace::FontType type = fon.type();
271 if (!fon.usable() || fon.isReplacement() || !(currentDoc->documentFileName() == fon.localForDocument() || fon.localForDocument().isEmpty()))
272 continue;
273 if ((forAnnotation) && ((type == ScFace::TYPE1) || (type == ScFace::OTF) || (fon.subset())))
274 continue;
275 if ((forSubstitute) && fon.isReplacement())
276 continue;
277 flist.insert(*it2, fon.type());
278 break;
279 }
280 }
281 }
282 else
283 {
284 QMap<QString, QStringList>::ConstIterator fmIt = prefsManager.appPrefs.fontPrefs.AvailFonts.fontMap.find(*it2);
285 if (fmIt == prefsManager.appPrefs.fontPrefs.AvailFonts.fontMap.constEnd())
286 continue;
287 if (fmIt->count() <= 0)
288 continue;
289 QString fullFontName = (*it2) + " " + fmIt->at(0);
290 ScFace fon = prefsManager.appPrefs.fontPrefs.AvailFonts[fullFontName];
291 if ( !fon.usable() || fon.isReplacement() )
292 continue;
293 ScFace::FontType type = fon.type();
294 if ((forAnnotation) && ((type == ScFace::TYPE1) || (type == ScFace::OTF) || (fon.subset())))
295 continue;
296 if ((forSubstitute) && fon.isReplacement())
297 continue;
298 flist.insert(*it2, fon.type());
299 }
300 }
301 for (QMap<QString, ScFace::FontType>::Iterator it2a = flist.begin(); it2a != flist.end(); ++it2a)
302 {
303 ScFace::FontType type = it2a.value();
304 // Replacement fonts were systematically discarded in previous code
305 /*if (fon.isReplacement())
306 fontFamily->addItem(substFont, it2a.value());
307 else */
308 if (type == ScFace::OTF)
309 fontFamily->addItem(otfFont, it2a.key());
310 else if (type == ScFace::TYPE1)
311 fontFamily->addItem(psFont, it2a.key());
312 else if (type == ScFace::TTF)
313 fontFamily->addItem(ttfFont, it2a.key());
314 }
315 QString family = fontFamily->currentText();
316 QStringList slist = prefsManager.appPrefs.fontPrefs.AvailFonts.fontMap[family];
317 slist.sort();
318 QStringList ilist;
319 if (currentDoc != nullptr)
320 {
321 for (QStringList::ConstIterator it = slist.constBegin(); it != slist.constEnd(); ++it)
322 {
323 SCFonts::ConstIterator fIt = prefsManager.appPrefs.fontPrefs.AvailFonts.find(family + " " + *it);
324 if (fIt != prefsManager.appPrefs.fontPrefs.AvailFonts.constEnd())
325 {
326 if (!fIt->usable() || fIt->isReplacement())
327 continue;
328 ilist.append(*it);
329 }
330 }
331 fontStyle->addItems(ilist);
332 }
333 else
334 fontStyle->addItems(slist);
335 fontFamily->blockSignals(familySigBlocked);
336 fontStyle->blockSignals(styleSigBlocked);
337 }
338
339 // This code borrowed from Qt project qfontcombobox.cpp
340
writingSystemFromScript(QLocale::Script script)341 static QFontDatabase::WritingSystem writingSystemFromScript(QLocale::Script script)
342 {
343 switch (script) {
344 case QLocale::ArabicScript:
345 return QFontDatabase::Arabic;
346 case QLocale::CyrillicScript:
347 return QFontDatabase::Cyrillic;
348 case QLocale::GurmukhiScript:
349 return QFontDatabase::Gurmukhi;
350 case QLocale::SimplifiedHanScript:
351 return QFontDatabase::SimplifiedChinese;
352 case QLocale::TraditionalHanScript:
353 return QFontDatabase::TraditionalChinese;
354 case QLocale::LatinScript:
355 return QFontDatabase::Latin;
356 case QLocale::ArmenianScript:
357 return QFontDatabase::Armenian;
358 case QLocale::BengaliScript:
359 return QFontDatabase::Bengali;
360 case QLocale::DevanagariScript:
361 return QFontDatabase::Devanagari;
362 case QLocale::GeorgianScript:
363 return QFontDatabase::Georgian;
364 case QLocale::GreekScript:
365 return QFontDatabase::Greek;
366 case QLocale::GujaratiScript:
367 return QFontDatabase::Gujarati;
368 case QLocale::HebrewScript:
369 return QFontDatabase::Hebrew;
370 case QLocale::JapaneseScript:
371 return QFontDatabase::Japanese;
372 case QLocale::KhmerScript:
373 return QFontDatabase::Khmer;
374 case QLocale::KannadaScript:
375 return QFontDatabase::Kannada;
376 case QLocale::KoreanScript:
377 return QFontDatabase::Korean;
378 case QLocale::LaoScript:
379 return QFontDatabase::Lao;
380 case QLocale::MalayalamScript:
381 return QFontDatabase::Malayalam;
382 case QLocale::MyanmarScript:
383 return QFontDatabase::Myanmar;
384 case QLocale::TamilScript:
385 return QFontDatabase::Tamil;
386 case QLocale::TeluguScript:
387 return QFontDatabase::Telugu;
388 case QLocale::ThaanaScript:
389 return QFontDatabase::Thaana;
390 case QLocale::ThaiScript:
391 return QFontDatabase::Thai;
392 case QLocale::TibetanScript:
393 return QFontDatabase::Tibetan;
394 case QLocale::SinhalaScript:
395 return QFontDatabase::Sinhala;
396 case QLocale::SyriacScript:
397 return QFontDatabase::Syriac;
398 case QLocale::OriyaScript:
399 return QFontDatabase::Oriya;
400 case QLocale::OghamScript:
401 return QFontDatabase::Ogham;
402 case QLocale::RunicScript:
403 return QFontDatabase::Runic;
404 case QLocale::NkoScript:
405 return QFontDatabase::Nko;
406 default:
407 return QFontDatabase::Any;
408 }
409 }
410
writingSystemFromLocale()411 static QFontDatabase::WritingSystem writingSystemFromLocale()
412 {
413 QStringList uiLanguages = QLocale::system().uiLanguages();
414 QLocale::Script script;
415 if (!uiLanguages.isEmpty())
416 script = QLocale(uiLanguages.at(0)).script();
417 else
418 script = QLocale::system().script();
419
420 return writingSystemFromScript(script);
421 }
422
writingSystemForFont(const QFont & font,bool * hasLatin)423 QFontDatabase::WritingSystem writingSystemForFont(const QFont &font, bool *hasLatin)
424 {
425 QFontDatabase& fontDb = ScQApp->qtFontDatabase();
426 QList<QFontDatabase::WritingSystem> writingSystems = fontDb.writingSystems(font.family());
427
428 // this just confuses the algorithm below. Vietnamese is Latin with lots of special chars
429 writingSystems.removeOne(QFontDatabase::Vietnamese);
430 *hasLatin = writingSystems.removeOne(QFontDatabase::Latin);
431
432 if (writingSystems.isEmpty())
433 return QFontDatabase::Any;
434
435 QFontDatabase::WritingSystem system = writingSystemFromLocale();
436
437 if (writingSystems.contains(system))
438 return system;
439
440 if (system == QFontDatabase::TraditionalChinese && writingSystems.contains(QFontDatabase::SimplifiedChinese))
441 return QFontDatabase::SimplifiedChinese;
442
443 if (system == QFontDatabase::SimplifiedChinese && writingSystems.contains(QFontDatabase::TraditionalChinese))
444 return QFontDatabase::TraditionalChinese;
445
446 system = writingSystems.last();
447
448 if (!*hasLatin)
449 // we need to show something
450 return system;
451
452 if (writingSystems.count() == 1 && system > QFontDatabase::Cyrillic)
453 return system;
454
455 if (writingSystems.count() <= 2 && system > QFontDatabase::Armenian && system < QFontDatabase::Vietnamese)
456 return system;
457
458 if (writingSystems.count() <= 5 && system >= QFontDatabase::SimplifiedChinese && system <= QFontDatabase::Korean)
459 return system;
460
461 return QFontDatabase::Any;
462 }
463
getScFace(const QString & className,const QString & text)464 const ScFace& getScFace(const QString& className, const QString& text)
465 {
466 QFontDatabase& fontDb = ScQApp->qtFontDatabase();
467 SCFonts& availableFonts = PrefsManager::instance().appPrefs.fontPrefs.AvailFonts;
468
469 // Handle FontComboH class witch has only Family names in the combo class.
470 if (className == "FontComboH" || className == "SMFontComboH")
471 {
472 // SMFontComboH's "Use Parent Font" case
473 if (!availableFonts.fontMap.contains(text))
474 return ScFace::none();
475 QStringList styles = availableFonts.fontMap[text];
476 QString style = styles[0];
477 if (styles.contains("Regular"))
478 style = "Regular";
479 else if (styles.contains("Roman"))
480 style = "Roman";
481 else if (styles.contains("Medium"))
482 style = "Medium";
483 else if (styles.contains("Book"))
484 style = "Book";
485 const ScFace& fon = availableFonts.findFont(text, style);
486 if (!fontDb.families().contains(text))
487 QFontDatabase::addApplicationFont(fon.fontFilePath());
488 return fon;
489 }
490 const ScFace& scFace = availableFonts.findFont(text);
491 if (!fontDb.families().contains(scFace.family()))
492 QFontDatabase::addApplicationFont(scFace.fontFilePath());
493 return scFace;
494 }
495
FontFamilyDelegate(QObject * parent)496 FontFamilyDelegate::FontFamilyDelegate(QObject *parent)
497 : QAbstractItemDelegate(parent)
498 , writingSystem(QFontDatabase::Any)
499 {
500 pixmapCache.setCacheLimit(64*1024);
501 }
502
paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const503 void FontFamilyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
504 {
505 double pixelRatio = painter->device()->devicePixelRatioF();
506 int pixmapW = qRound(pixelRatio * option.rect.width());
507 int pixmapH = qRound(pixelRatio * option.rect.height());
508 QString text(index.data(Qt::DisplayRole).toString());
509 QString wh = QString("-w%1h%2").arg(pixmapW).arg(pixmapH);
510 QPixmap cachedPixmap;
511 QString cacheKey = text + wh;
512 if (option.state & QStyle::State_Selected)
513 cacheKey += "-selected";
514 if (pixmapCache.find(cacheKey, &cachedPixmap))
515 {
516 painter->drawPixmap(option.rect.x(), option.rect.y(), cachedPixmap);
517 return;
518 }
519
520 QFontDatabase& fontDb = ScQApp->qtFontDatabase();
521 const ScFace& scFace = getScFace(this->parent()->metaObject()->className(), text);
522
523 QPixmap pixmap(pixmapW, pixmapH);
524 QPixmap invPixmap(pixmapW, pixmapH);
525 pixmap.setDevicePixelRatio(pixelRatio);
526 invPixmap.setDevicePixelRatio(pixelRatio);
527
528 QPainter pixPainter(&pixmap);
529 QPainter invpixPainter(&invPixmap);
530
531 QRect r(0, 0, option.rect.width(), option.rect.height());
532 pixPainter.fillRect(r, option.palette.window());
533 invpixPainter.fillRect(r, option.palette.window());
534
535 QFont font = option.font;
536 font.setPointSize(QFontInfo(font).pointSize() * 3 / 2.0);
537
538 QFont font2 = option.font;
539 if (!scFace.isNone())
540 {
541 font2 = fontDb.font(scFace.family(), scFace.style(), QFontInfo(option.font).pointSize());
542 font2.setPointSize(QFontInfo(font2).pointSize() * 3 / 2.0);
543 }
544
545 bool hasLatin;
546 QFontDatabase::WritingSystem system = writingSystemForFont(font2, &hasLatin);
547 if (hasLatin)
548 font = font2;
549
550 pixPainter.setPen(QPen(option.palette.text(), 0));
551
552 invpixPainter.setBrush(option.palette.highlight());
553 invpixPainter.setPen(Qt::NoPen);
554 invpixPainter.drawRect(0, 0, option.rect.width(), option.rect.height());
555 invpixPainter.setPen(QPen(option.palette.highlightedText(), 0));
556
557 QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
558 QSize actualSize(icon.actualSize(r.size()));
559 icon.paint(&pixPainter, r, Qt::AlignLeft|Qt::AlignVCenter);
560 icon.paint(&invpixPainter, r, Qt::AlignLeft|Qt::AlignVCenter);
561 if (option.direction == Qt::RightToLeft)
562 r.setRight(r.right() - actualSize.width() - 4);
563 else
564 r.setLeft(r.left() + actualSize.width() + 4);
565
566 pixPainter.setFont(font);
567 invpixPainter.setFont(font);
568 // If the ascent of the font is larger than the height of the rect,
569 // we will clip the text, so it's better to align the tight bounding rect in this case
570 // This is specifically for fonts where the ascent is very large compared to
571 // the descent, like certain of the Stix family.
572 QFontMetricsF fontMetrics(font);
573 if (fontMetrics.ascent() > r.height())
574 {
575 QRectF tbr = fontMetrics.tightBoundingRect(text);
576 QRectF rr (r.x(), r.y() - (tbr.bottom() + r.height()/2), r.width(),(r.height() + tbr.height()));
577 pixPainter.drawText(rr, Qt::AlignVCenter|Qt::AlignLeading|Qt::TextSingleLine, text);
578 invpixPainter.drawText(rr, Qt::AlignVCenter|Qt::AlignLeading|Qt::TextSingleLine, text);
579 }
580 else
581 {
582 pixPainter.drawText(r, Qt::AlignVCenter|Qt::AlignLeading|Qt::TextSingleLine, text);
583 invpixPainter.drawText(r, Qt::AlignVCenter|Qt::AlignLeading|Qt::TextSingleLine, text);
584 }
585
586 if (writingSystem != QFontDatabase::Any)
587 system = writingSystem;
588
589 if (system != QFontDatabase::Any)
590 {
591 int w = pixPainter.fontMetrics().horizontalAdvance(text + QLatin1String(" "));
592 pixPainter.setFont(font2);
593 invpixPainter.setFont(font2);
594 QString sample = fontDb.writingSystemSample(system);
595 if (system == QFontDatabase::Arabic)
596 sample = "أبجدية عربية";
597
598 if (fontMetrics.ascent() > r.height())
599 {
600 QRectF tbr = fontMetrics.tightBoundingRect(sample);
601 QRectF rr (r.x(), r.y() - (tbr.bottom() + r.height()/2), r.width(), (r.height() + tbr.height()));
602 if (option.direction == Qt::RightToLeft)
603 rr.setRight(rr.right() - w);
604 else
605 {
606 rr.setRight(rr.right() - 4);
607 rr.setLeft(rr.left() + w);
608 }
609 pixPainter.drawText(rr, Qt::AlignVCenter|Qt::AlignRight|Qt::TextSingleLine, sample);
610 invpixPainter.drawText(rr, Qt::AlignVCenter|Qt::AlignRight|Qt::TextSingleLine, sample);
611 }
612 else
613 {
614 if (option.direction == Qt::RightToLeft)
615 r.setRight(r.right() - w);
616 else
617 {
618 r.setRight(r.right() - 4);
619 r.setLeft(r.left() + w);
620 }
621 pixPainter.drawText(r, Qt::AlignVCenter|Qt::AlignRight|Qt::TextSingleLine, sample);
622 invpixPainter.drawText(r, Qt::AlignVCenter|Qt::AlignRight|Qt::TextSingleLine, sample);
623 }
624 }
625 if (option.state & QStyle::State_Selected)
626 painter->drawPixmap(option.rect.x(), option.rect.y(), invPixmap);
627 else
628 painter->drawPixmap(option.rect.x(), option.rect.y(), pixmap);
629 pixmapCache.insert(cacheKey, pixmap);
630 pixmapCache.insert(cacheKey+"-selected", invPixmap);
631 }
632
helpEvent(QHelpEvent * event,QAbstractItemView * view,const QStyleOptionViewItem & option,const QModelIndex & index)633 bool FontFamilyDelegate::helpEvent(QHelpEvent * event, QAbstractItemView * view,
634 const QStyleOptionViewItem & option, const QModelIndex & index)
635 {
636 if (!event || !view)
637 return false;
638
639 if (event->type() == QEvent::ToolTip)
640 {
641 QString text(index.data(Qt::DisplayRole).toString());
642 QString className = this->parent()->metaObject()->className();
643 const ScFace& scFace = getScFace(className, text);
644 if (!scFace.isNone())
645 {
646 QString tooltip = scFace.family();
647 if (className == QLatin1String("FontCombo"))
648 {
649 tooltip += QLatin1String(" ");
650 tooltip += scFace.style();
651 }
652 QHelpEvent *helpEvent = static_cast<QHelpEvent*>(event);
653 QToolTip::showText(helpEvent->globalPos(), tooltip, view);
654 return true;
655 }
656 }
657
658 return QAbstractItemDelegate::helpEvent(event, view, option, index);
659 }
660
sizeHint(const QStyleOptionViewItem & option,const QModelIndex & index) const661 QSize FontFamilyDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
662 {
663 QString text(index.data(Qt::DisplayRole).toString());
664 QFont font(option.font);
665 font.setPointSize(QFontInfo(font).pointSize() * 3/2);
666 QFontMetrics fontMetrics(font);
667 return QSize(fontMetrics.horizontalAdvance(text), fontMetrics.height() + 5);
668 }
669
670
FontComboValidator(QObject * parent)671 FontComboValidator::FontComboValidator(QObject* parent)
672 : QValidator(parent)
673 {
674 }
675
validate(QString & input,int & pos) const676 QValidator::State FontComboValidator::validate(QString & input, int & pos) const
677 {
678 QComboBox* comboBox = qobject_cast<QComboBox*>(this->parent());
679 if (!comboBox)
680 return QValidator::Invalid;
681
682 int index = comboBox->findText(input, Qt::MatchFixedString);
683 if (index >= 0)
684 {
685 input = comboBox->itemText(index); // Matching is performed case insensitively
686 return QValidator::Acceptable;
687 }
688
689 for (int i = 0; i < comboBox->count(); ++i)
690 {
691 QString itemText = comboBox->itemText(i);
692 if (itemText.startsWith(input, Qt::CaseInsensitive))
693 return QValidator::Intermediate;
694 }
695
696 return QValidator::Invalid;
697 }
698