kfontcombo.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (c) 2001 Malte Starostik <malte@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2 as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include <tqfontdatabase.h> 00021 #include <tqlistbox.h> 00022 #include <tqpainter.h> 00023 #include <tqregexp.h> 00024 00025 #include <kcharsets.h> 00026 #include <kconfig.h> 00027 #include <kglobal.h> 00028 #include <kfontdialog.h> 00029 00030 #include "kfontcombo.h" 00031 #include "kfontcombo.moc" 00032 00033 #include <ft2build.h> 00034 #include <fontconfig/fontconfig.h> 00035 #include <X11/Xlib.h> 00036 #include <X11/Xatom.h> 00037 #include <X11/Intrinsic.h> 00038 #include <X11/StringDefs.h> 00039 #include <X11/Shell.h> 00040 00041 #include <X11/Xft/Xft.h> 00042 00043 00044 struct KFontComboPrivate 00045 { 00046 KFontComboPrivate() 00047 : bold(false), 00048 italic(false), 00049 underline(false), 00050 strikeOut(false), 00051 modified(false), 00052 size(0), 00053 lineSpacing(0) 00054 { 00055 } 00056 00057 bool bold : 1; 00058 bool italic : 1; 00059 bool underline : 1; 00060 bool strikeOut : 1; 00061 bool displayFonts : 1; 00062 bool modified : 1; 00063 int size; 00064 int lineSpacing; 00065 TQString defaultFamily; 00066 }; 00067 00068 class KFontListItem : public TQListBoxItem 00069 { 00070 public: 00071 KFontListItem(const TQString &fontName, KFontCombo *combo); 00072 virtual ~KFontListItem(); 00073 00074 virtual int width(const TQListBox *) const; 00075 virtual int height(const TQListBox *) const; 00076 00077 void updateFont(); 00078 00079 protected: 00080 virtual void paint(TQPainter *p); 00081 00082 private: 00083 void createFont(); 00084 00085 private: 00086 KFontCombo *m_combo; 00087 TQString m_fontName; 00088 TQFont *m_font; 00089 bool m_canPaintName; 00090 }; 00091 00092 KFontListItem::KFontListItem(const TQString &fontName, KFontCombo *combo) 00093 : TQListBoxItem(combo->listBox()), 00094 m_combo(combo), 00095 m_fontName(fontName), 00096 m_font(0), 00097 m_canPaintName(true) 00098 { 00099 setText(fontName); 00100 } 00101 00102 KFontListItem::~KFontListItem() 00103 { 00104 delete m_font; 00105 } 00106 00107 int KFontListItem::width(const TQListBox *lb) const 00108 { 00109 if (m_font) 00110 return TQFontMetrics(*m_font).width(text()) + 6; 00111 return lb->fontMetrics().width(text()) + 6; 00112 } 00113 00114 int KFontListItem::height(const TQListBox *lb) const 00115 { 00116 if (m_combo->d->displayFonts) 00117 return m_combo->d->lineSpacing + 2; 00118 TQFontMetrics fm(lb->fontMetrics()); 00119 return fm.lineSpacing() + 2; 00120 } 00121 00122 void KFontListItem::paint(TQPainter *p) 00123 { 00124 if (m_combo->d->displayFonts) 00125 { 00126 if (!m_font) 00127 createFont(); 00128 00129 TQString t = m_fontName; 00130 if (p->device() != m_combo) 00131 { 00132 if (m_canPaintName) 00133 p->setFont(*m_font); 00134 else 00135 t = TQString::fromLatin1("(%1)").arg(m_fontName); 00136 } 00137 TQFontMetrics fm(p->fontMetrics()); 00138 p->drawText(3, (m_combo->d->lineSpacing + fm.ascent() + fm.leading() / 2) / 2, t); 00139 } 00140 else 00141 { 00142 TQFontMetrics fm(p->fontMetrics()); 00143 p->drawText(3, fm.ascent() + fm.leading() / 2, m_fontName); 00144 } 00145 } 00146 00147 void KFontListItem::updateFont() 00148 { 00149 if (!m_font) 00150 return; 00151 00152 m_font->setBold(m_combo->d->bold); 00153 m_font->setItalic(m_combo->d->italic); 00154 m_font->setUnderline(m_combo->d->underline); 00155 m_font->setStrikeOut(m_combo->d->strikeOut); 00156 m_font->setPointSize(m_combo->d->size); 00157 } 00158 00159 void KFontListItem::createFont() 00160 { 00161 if (m_font) 00162 return; 00163 00164 m_font = new TQFont(m_fontName); 00165 TQFontMetrics fm(*m_font); 00166 for (unsigned int i = 0; i < m_fontName.length(); ++i) 00167 if (!fm.inFont(m_fontName[i])) 00168 { 00169 m_canPaintName = false; 00170 break; 00171 } 00172 updateFont(); 00173 } 00174 00175 KFontCombo::KFontCombo(TQWidget *parent, const char *name) 00176 : KComboBox(true, parent, name) 00177 { 00178 init(); 00179 TQStringList families; 00180 KFontChooser::getFontList(families, 0); 00181 setFonts(families); 00182 } 00183 00184 KFontCombo::KFontCombo(const TQStringList &fonts, TQWidget *parent, const char *name) 00185 : KComboBox(true, parent, name) 00186 { 00187 init(); 00188 setFonts(fonts); 00189 } 00190 00191 void KFontCombo::setFonts(const TQStringList &fonts) 00192 { 00193 clear(); 00194 for (TQStringList::ConstIterator it = fonts.begin(); it != fonts.end(); ++it) 00195 new KFontListItem(*it, this); 00196 } 00197 00198 /* 00199 * Maintenance note: Keep in sync with KFontAction::setFont() 00200 */ 00201 void KFontCombo::setCurrentFont(const TQString &family) 00202 { 00203 TQString lowerName = family.lower(); 00204 int c = count(); 00205 for(int i = 0; i < c; i++) 00206 { 00207 if (text(i).lower() == lowerName) 00208 { 00209 setCurrentItem(i); 00210 d->defaultFamily = text(i); 00211 d->modified = false; 00212 return; 00213 } 00214 } 00215 int x = lowerName.find(" ["); 00216 if (x>-1) 00217 { 00218 lowerName = lowerName.left(x); 00219 for(int i = 0; i < c; i++) 00220 { 00221 if (text(i).lower() == lowerName) 00222 { 00223 setCurrentItem(i); 00224 d->defaultFamily = text(i); 00225 d->modified = false; 00226 return; 00227 } 00228 } 00229 } 00230 00231 lowerName += " ["; 00232 for(int i = 0; i < c; i++) 00233 { 00234 if (text(i).lower().startsWith(lowerName)) 00235 { 00236 setCurrentItem(i); 00237 d->defaultFamily = text(i); 00238 d->modified = false; 00239 return; 00240 } 00241 } 00242 00243 // nothing matched yet, try a fontconfig reverse lookup and 00244 // check again to solve an alias 00245 FcPattern *pattern = NULL; 00246 FcConfig *config = NULL; 00247 FcResult result; 00248 TQString realFamily; 00249 TQRegExp regExp("[-:]"); 00250 pattern = FcNameParse( (unsigned char*) family.ascii() ); 00251 FcDefaultSubstitute(pattern); 00252 FcConfigSubstitute (config, pattern, FcMatchPattern); 00253 pattern = FcFontMatch(NULL, pattern, &result); 00254 realFamily = (char*)FcNameUnparse(pattern); 00255 realFamily.remove(realFamily.find(regExp), realFamily.length()); 00256 00257 if ( !realFamily.isEmpty() && realFamily != family ) 00258 setCurrentFont( realFamily ); 00259 } 00260 00261 void KFontCombo::slotModified( int ) 00262 { 00263 d->modified = 1; 00264 } 00265 00266 TQString KFontCombo::currentFont() const 00267 { 00268 if (d->modified) 00269 return currentText(); 00270 return d->defaultFamily; 00271 } 00272 00273 void KFontCombo::setCurrentItem(int i) 00274 { 00275 d->modified = true; 00276 TQComboBox::setCurrentItem(i); 00277 } 00278 00279 void KFontCombo::init() 00280 { 00281 d = new KFontComboPrivate; 00282 d->displayFonts = displayFonts(); 00283 setInsertionPolicy(NoInsertion); 00284 setAutoCompletion(true); 00285 setSize(12); 00286 connect( this, TQT_SIGNAL(highlighted(int)), TQT_SLOT(slotModified(int))); 00287 } 00288 00289 KFontCombo::~KFontCombo() 00290 { 00291 delete d; 00292 } 00293 00294 void KFontCombo::setBold(bool bold) 00295 { 00296 if (d->bold == bold) 00297 return; 00298 d->bold = bold; 00299 updateFonts(); 00300 } 00301 00302 bool KFontCombo::bold() const 00303 { 00304 return d->bold; 00305 } 00306 00307 void KFontCombo::setItalic(bool italic) 00308 { 00309 if (d->italic == italic) 00310 return; 00311 d->italic = italic; 00312 updateFonts(); 00313 } 00314 00315 bool KFontCombo::italic() const 00316 { 00317 return d->italic; 00318 } 00319 00320 void KFontCombo::setUnderline(bool underline) 00321 { 00322 if (d->underline == underline) 00323 return; 00324 d->underline = underline; 00325 updateFonts(); 00326 } 00327 00328 bool KFontCombo::underline() const 00329 { 00330 return d->underline; 00331 } 00332 00333 void KFontCombo::setStrikeOut(bool strikeOut) 00334 { 00335 if (d->strikeOut == strikeOut) 00336 return; 00337 d->strikeOut = strikeOut; 00338 updateFonts(); 00339 } 00340 00341 bool KFontCombo::strikeOut() const 00342 { 00343 return d->strikeOut; 00344 } 00345 00346 void KFontCombo::setSize(int size) 00347 { 00348 if (d->size == size) 00349 return; 00350 d->size = size; 00351 TQFont f; 00352 f.setPointSize(size); 00353 TQFontMetrics fm(f); 00354 d->lineSpacing = fm.lineSpacing(); 00355 updateFonts(); 00356 } 00357 00358 int KFontCombo::size() const 00359 { 00360 return d->size; 00361 } 00362 00363 void KFontCombo::updateFonts() 00364 { 00365 if (!d->displayFonts) 00366 return; 00367 00368 for (unsigned int i = 0; i < listBox()->count(); ++i) 00369 { 00370 KFontListItem *item = static_cast<KFontListItem *>(listBox()->item(i)); 00371 item->updateFont(); 00372 } 00373 } 00374 00375 bool KFontCombo::displayFonts() 00376 { 00377 KConfigGroupSaver saver(KGlobal::config(), "KDE"); 00378 return KGlobal::config()->readBoolEntry("DisplayFontItems", true); 00379 } 00380 00381 void KFontCombo::virtual_hook( int id, void* data ) 00382 { KComboBox::virtual_hook( id, data ); } 00383