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