kde-workspace/kcontrol/kfontinst/kcmfontinst/FontList.cpp
Ivailo Monev 094b5e0d52 kcontrol: remove writing systems support from fonts control module
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2021-06-16 09:58:33 +03:00

2053 lines
63 KiB
C++

/*
* KFontInst - KDE Font Installer
*
* Copyright 2003-2007 Craig Drummond <craig@kde.org>
*
* ----
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "FontList.h"
#include <KGlobal>
#include <KStandardDirs>
#include <KLocale>
#include <KMimeType>
#include <KMenu>
#include <KIcon>
#include <KIconLoader>
#include <kde_file.h>
#include <KMessageBox>
#include <KColorScheme>
#include <QtCore/QProcess>
#include <QtGui/QFont>
#include <QtCore/QMap>
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtGui/QPixmap>
#include <QtGui/qevent.h>
#include <QtCore/QDateTime>
#include <QtGui/QHeaderView>
#include <QtGui/QPainter>
#include <QtGui/QMenu>
#include <QtCore/QTimer>
#include <QtGui/QApplication>
#include <QtDBus/QDBusServiceWatcher>
#include <stdlib.h>
#include <unistd.h>
#include <utime.h>
#include "FcEngine.h"
#include "Fc.h"
#include "KfiConstants.h"
#include "GroupList.h"
#include "FontInstInterface.h"
#include "XmlStrings.h"
#include "Family.h"
#include "Style.h"
#include "File.h"
namespace KFI
{
const QStringList CFontList::fontMimeTypes(QStringList() << "application/x-font-ttf"
<< "application/x-font-otf"
<< "application/x-font-type1"
<< "application/x-font-pcf"
<< "application/x-font-bdf"
<< "application/vnd.kde.fontspackage");
static const int constMaxSlowed = 250;
static void decompose(const QString &name, QString &family, QString &style)
{
int commaPos=name.lastIndexOf(',');
family=-1==commaPos ? name : name.left(commaPos);
style=-1==commaPos ? KFI_WEIGHT_REGULAR : name.mid(commaPos+2);
}
static void addFont(CFontItem *font, CJobRunner::ItemList &urls, QStringList &fontNames,
QSet<Misc::TFont> *fonts, QSet<CFontItem *> &usedFonts,
bool getEnabled, bool getDisabled)
{
if(!usedFonts.contains(font) &&
( (getEnabled && font->isEnabled()) ||
(getDisabled && !font->isEnabled()) ) )
{
urls.append(CJobRunner::Item(font->url(), font->name(), !font->isEnabled()));
fontNames.append(font->name());
usedFonts.insert(font);
if(fonts)
fonts->insert(Misc::TFont(font->family(), font->styleInfo()));
}
}
static QString replaceEnvVar(const QString &text)
{
QString mod(text);
int endPos(text.indexOf('/'));
if(endPos==-1)
endPos=text.length()-1;
else
endPos--;
if(endPos>0)
{
QString envVar(text.mid(1, endPos));
const char *val=getenv(envVar.toLatin1().constData());
if(val)
mod=Misc::fileSyntax(QFile::decodeName(val)+mod.mid(endPos+1));
}
return mod;
}
//
// Convert from list such as:
//
// Arial
// Arial, Bold
// Courier
// Times
// Times, Italic
//
// To:
//
// Arial (Regular, Bold)
// Coutier
// Times (Regular, Italic)
QStringList CFontList::compact(const QStringList &fonts)
{
QString lastFamily,
entry;
QStringList::ConstIterator it(fonts.begin()),
end(fonts.end());
QStringList compacted;
QSet<QString> usedStyles;
for(; it!=end; ++it)
{
QString family,
style;
decompose(*it, family, style);
if(family!=lastFamily)
{
usedStyles.clear();
if(entry.length())
{
entry+=')';
compacted.append(entry);
}
entry=QString(family+" (");
lastFamily=family;
}
if(!usedStyles.contains(style))
{
usedStyles.clear();
if(entry.length() && '('!=entry[entry.length()-1])
entry+=", ";
entry+=style;
usedStyles.insert(style);
}
}
if(entry.length())
{
entry+=')';
compacted.append(entry);
}
return compacted;
}
QString capitaliseFoundry(const QString &foundry)
{
QString f(foundry.toLower());
if(f==QLatin1String("ibm"))
return QLatin1String("IBM");
else if(f==QLatin1String("urw"))
return QLatin1String("URW");
else if(f==QLatin1String("itc"))
return QLatin1String("ITC");
else if(f==QLatin1String("nec"))
return QLatin1String("NEC");
else if(f==QLatin1String("b&h"))
return QLatin1String("B&H");
else if(f==QLatin1String("dec"))
return QLatin1String("DEC");
else
{
QChar *ch(f.data());
int len(f.length());
bool isSpace(true);
while(len--)
{
if (isSpace)
*ch=ch->toUpper();
isSpace=ch->isSpace();
++ch;
}
}
return f;
}
inline bool isSysFolder(const QString &sect)
{
return i18n(KFI_KIO_FONTS_SYS)==sect || KFI_KIO_FONTS_SYS==sect;
}
CFontItem::CFontItem(CFontModelItem *p, const Style &s, bool sys)
: CFontModelItem(p),
itsStyleName(FC::createStyleName(s.value())),
itsStyle(s)
{
refresh();
if(!Misc::root())
setIsSystem(sys);
}
void CFontItem::refresh()
{
FileCont::ConstIterator it(itsStyle.files().begin()),
end(itsStyle.files().end());
itsEnabled=false;
for(; it!=end; ++it)
if(!Misc::isHidden(Misc::getFile((*it).path())))
{
itsEnabled=true;
break;
}
}
CFamilyItem::CFamilyItem(CFontList &p, const Family &f, bool sys)
: CFontModelItem(NULL),
itsStatus(ENABLED),
itsRealStatus(ENABLED),
itsRegularFont(NULL),
itsParent(p)
{
itsName=f.name();
addFonts(f.styles(), sys);
//updateStatus();
}
CFamilyItem::~CFamilyItem()
{
qDeleteAll(itsFonts);
itsFonts.clear();
}
bool CFamilyItem::addFonts(const StyleCont &styles, bool sys)
{
StyleCont::ConstIterator it(styles.begin()),
end(styles.end());
bool modified=false;
for(; it!=end; ++it)
{
CFontItem *font=findFont((*it).value(), sys);
if(!font)
{
// New font style!
itsFonts.append(new CFontItem(this, *it, sys));
modified=true;
}
else
{
int before=(*it).files().size();
font->addFiles((*it).files());
if((*it).files().size()!=before)
{
modified=true;
font->refresh();
}
}
}
return modified;
}
CFontItem * CFamilyItem::findFont(quint32 style, bool sys)
{
CFontItemCont::ConstIterator fIt(itsFonts.begin()),
fEnd(itsFonts.end());
for(; fIt!=fEnd; ++fIt)
if((*(*fIt)).styleInfo()==style && (*(*fIt)).isSystem()==sys)
return (*fIt);
return NULL;
}
void CFamilyItem::getFoundries(QSet<QString> &foundries) const
{
CFontItemCont::ConstIterator it(itsFonts.begin()),
end(itsFonts.end());
for(; it!=end; ++it)
{
FileCont::ConstIterator fIt((*it)->files().begin()),
fEnd((*it)->files().end());
for(; fIt!=fEnd; ++fIt)
if(!(*fIt).foundry().isEmpty())
foundries.insert(capitaliseFoundry((*fIt).foundry()));
}
}
bool CFamilyItem::usable(const CFontItem *font, bool root)
{
return ( root ||
(font->isSystem() && itsParent.allowSys()) ||
(!font->isSystem() && itsParent.allowUser()));
}
void CFamilyItem::addFont(CFontItem *font, bool update)
{
itsFonts.append(font);
if(update)
{
updateStatus();
updateRegularFont(font);
}
}
void CFamilyItem::removeFont(CFontItem *font, bool update)
{
itsFonts.removeAll(font);
if(update)
updateStatus();
if(itsRegularFont==font)
{
itsRegularFont=NULL;
if(update)
updateRegularFont(NULL);
}
delete font;
}
void CFamilyItem::refresh()
{
updateStatus();
itsRegularFont=NULL;
updateRegularFont(NULL);
}
bool CFamilyItem::updateStatus()
{
bool root(Misc::root());
EStatus oldStatus(itsStatus);
CFontItemCont::ConstIterator it(itsFonts.begin()),
end(itsFonts.end());
int en(0), dis(0), allEn(0), allDis(0);
bool oldSys(isSystem()),
sys(false);
itsFontCount=0;
for(; it!=end; ++it)
if(usable(*it, root))
{
if((*it)->isEnabled())
en++;
else
dis++;
if(!sys)
sys=(*it)->isSystem();
itsFontCount++;
}
else
if((*it)->isEnabled())
allEn++;
else
allDis++;
allEn+=en;
allDis+=dis;
itsStatus=en && dis
? PARTIAL
: en
? ENABLED
: DISABLED;
itsRealStatus=allEn && allDis
? PARTIAL
: allEn
? ENABLED
: DISABLED;
if(!root)
setIsSystem(sys);
return itsStatus!=oldStatus || isSystem()!=oldSys;
}
bool CFamilyItem::updateRegularFont(CFontItem *font)
{
static const quint32 constRegular=FC::createStyleVal(FC_WEIGHT_REGULAR, KFI_FC_WIDTH_NORMAL, FC_SLANT_ROMAN);
CFontItem *oldFont(itsRegularFont);
bool root(Misc::root());
if(font && usable(font, root))
{
if(itsRegularFont)
{
int regDiff=abs((long)(itsRegularFont->styleInfo()-constRegular)),
fontDiff=abs((long)(font->styleInfo()-constRegular));
if(fontDiff<regDiff)
itsRegularFont=font;
}
else
itsRegularFont=font;
}
else // This case happens when the regular font is deleted...
{
CFontItemCont::ConstIterator it(itsFonts.begin()),
end(itsFonts.end());
quint32 current=0x0FFFFFFF;
for(; it!=end; ++it)
if(usable(*it, root))
{
quint32 diff=abs((long) ((*it)->styleInfo()-constRegular));
if(diff<current)
{
itsRegularFont=(*it);
current=diff;
}
}
}
return oldFont!=itsRegularFont;
}
CFontList::CFontList(QWidget *parent)
: QAbstractItemModel(parent),
itsAllowSys(true),
itsAllowUser(true),
itsSlowUpdates(false)
{
FontInst::registerTypes();
QDBusServiceWatcher *watcher = new QDBusServiceWatcher(QLatin1String(OrgKdeFontinstInterface::staticInterfaceName()),
QDBusConnection::sessionBus(),
QDBusServiceWatcher::WatchForOwnerChange, this);
connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), SLOT(dbusServiceOwnerChanged(QString,QString,QString)));
connect(CJobRunner::dbus(), SIGNAL(fontsAdded(KFI::Families)), SLOT(fontsAdded(KFI::Families)));
connect(CJobRunner::dbus(), SIGNAL(fontsRemoved(KFI::Families)), SLOT(fontsRemoved(KFI::Families)));
connect(CJobRunner::dbus(), SIGNAL(fontList(int,QList<KFI::Families>)), SLOT(fontList(int,QList<KFI::Families>)));
}
CFontList::~CFontList()
{
qDeleteAll(itsFamilies);
itsFamilies.clear();
itsFamilyHash.clear();
}
void CFontList::dbusServiceOwnerChanged(const QString &name, const QString &from, const QString &to)
{
Q_UNUSED(from);
Q_UNUSED(to);
if(name==QLatin1String(OrgKdeFontinstInterface::staticInterfaceName()))
load();
}
void CFontList::fontList(int pid, const QList<KFI::Families> &families)
{
// printf("**** fontList:%d/%d %d\n", pid, getpid(), families.count());
if(pid==getpid())
{
QList<KFI::Families>::ConstIterator it(families.begin()),
end(families.end());
int count(families.size());
for(int i=0; it!=end; ++it, ++i)
{
fontsAdded(*it);
emit listingPercent(i*100/count);
}
emit listingPercent(100);
}
}
void CFontList::unsetSlowUpdates()
{
setSlowUpdates(false);
}
void CFontList::load()
{
for(int t=0; t<NUM_MSGS_TYPES; ++t)
for(int f=0; f<FontInst::FOLDER_COUNT; ++f)
itsSlowedMsgs[t][f].clear();
setSlowUpdates(false);
emit layoutAboutToBeChanged();
// beginRemoveRows(QModelIndex(), 0, itsFamilies.count());
itsFamilies.clear();
itsFamilyHash.clear();
// endRemoveRows();
emit layoutChanged();
emit listingPercent(0);
CJobRunner::startDbusService();
CJobRunner::dbus()->list(FontInst::SYS_MASK|FontInst::USR_MASK, getpid());
}
void CFontList::setSlowUpdates(bool slow)
{
if(itsSlowUpdates!=slow)
{
if(!slow)
for(int i=0; i<FontInst::FOLDER_COUNT; ++i)
actionSlowedUpdates(i==FontInst::FOLDER_SYS);
itsSlowUpdates=slow;
}
}
int CFontList::columnCount(const QModelIndex &) const
{
return NUM_COLS;
}
QVariant CFontList::data(const QModelIndex &, int) const
{
return QVariant();
}
Qt::ItemFlags CFontList::flags(const QModelIndex &index) const
{
return !index.isValid()
? Qt::ItemIsEnabled | Qt::ItemIsDropEnabled
: Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
}
Qt::DropActions CFontList::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
QMimeData * CFontList::mimeData(const QModelIndexList &indexes) const
{
QMimeData *mimeData = new QMimeData();
QByteArray encodedData;
QModelIndexList::ConstIterator it(indexes.begin()),
end(indexes.end());
QSet<QString> families;
QDataStream ds(&encodedData, QIODevice::WriteOnly);
for(; it!=end; ++it)
if((*it).isValid())
{
if((static_cast<CFontModelItem *>((*it).internalPointer()))->isFont())
{
CFontItem *font=static_cast<CFontItem *>((*it).internalPointer());
families.insert(font->family());
}
else
{
CFamilyItem *fam=static_cast<CFamilyItem *>((*it).internalPointer());
families.insert(fam->name());
}
}
ds << families;
mimeData->setData(KFI_FONT_DRAG_MIME, encodedData);
return mimeData;
}
QStringList CFontList::mimeTypes() const
{
QStringList types;
types << "text/uri-list";
return types;
}
QVariant CFontList::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal)
switch(role)
{
case Qt::DisplayRole:
switch(section)
{
case COL_FONT:
return i18n("Font");
case COL_STATUS:
return i18n("Status");
default:
break;
}
break;
// case Qt::DecorationRole:
// if(COL_STATUS==section)
// return SmallIcon("fontstatus");
// break;
case Qt::TextAlignmentRole:
return Qt::AlignLeft;
case Qt::ToolTipRole:
if(COL_STATUS==section)
return i18n("This column shows the status of the font family, and of the "
"individual font styles.");
break;
case Qt::WhatsThisRole:
return whatsThis();
default:
break;
}
return QVariant();
}
QModelIndex CFontList::index(int row, int column, const QModelIndex &parent) const
{
if(parent.isValid()) // Then font...
{
CFamilyItem *fam=static_cast<CFamilyItem*>(parent.internalPointer());
if(row<fam->fonts().count())
return createIndex(row, column, fam->fonts().at(row));
}
else // Family....
if(row<itsFamilies.count())
return createIndex(row, column, itsFamilies.at(row));
return QModelIndex();
}
QModelIndex CFontList::parent(const QModelIndex &index) const
{
if(!index.isValid())
return QModelIndex();
CFontModelItem *mi=static_cast<CFontModelItem *>(index.internalPointer());
if(mi->isFamily())
return QModelIndex();
else
{
CFontItem *font=static_cast<CFontItem *>(index.internalPointer());
return createIndex(itsFamilies.indexOf(((CFamilyItem *)font->parent())), 0, font->parent());
}
}
int CFontList::rowCount(const QModelIndex &parent) const
{
if(parent.isValid())
{
CFontModelItem *mi=static_cast<CFontModelItem *>(parent.internalPointer());
if(mi->isFont())
return 0;
CFamilyItem *fam=static_cast<CFamilyItem *>(parent.internalPointer());
return fam->fonts().count();
}
else
return itsFamilies.count();
}
void CFontList::refresh(bool allowSys, bool allowUser)
{
itsAllowSys=allowSys;
itsAllowUser=allowUser;
CFamilyItemCont::ConstIterator it(itsFamilies.begin()),
end(itsFamilies.end());
for(; it!=end; ++it)
(*it)->refresh();
}
void CFontList::getFamilyStats(QSet<QString> &enabled, QSet<QString> &disabled, QSet<QString> &partial)
{
CFamilyItemCont::ConstIterator it(itsFamilies.begin()),
end(itsFamilies.end());
for(; it!=end; ++it)
{
switch((*it)->realStatus())
{
case CFamilyItem::ENABLED:
enabled.insert((*it)->name());
break;
case CFamilyItem::PARTIAL:
partial.insert((*it)->name());
break;
case CFamilyItem::DISABLED:
disabled.insert((*it)->name());
break;
}
}
}
void CFontList::getFoundries(QSet<QString> &foundries) const
{
CFamilyItemCont::ConstIterator it(itsFamilies.begin()),
end(itsFamilies.end());
for(; it!=end; ++it)
(*it)->getFoundries(foundries);
}
QString CFontList::whatsThis() const
{
return i18n("<p>This list shows your installed fonts. The fonts are grouped by family, and the"
" number in square brackets represents the number of styles in which the family is"
" available. e.g.</p>"
"<ul>"
"<li>Times [4]"
"<ul><li>Regular</li>"
"<li>Bold</li>"
"<li>Bold Italic</li>"
"<li>Italic</li>"
"</ul>"
"</li>"
"</ul>");
}
void CFontList::fontsAdded(const KFI::Families &families)
{
// printf("**** FONT ADDED:%d\n", families.items.count());
if(itsSlowUpdates)
storeSlowedMessage(families, MSG_ADD);
else
addFonts(families.items, families.isSystem && !Misc::root());
}
void CFontList::fontsRemoved(const KFI::Families &families)
{
// printf("**** FONT REMOVED:%d\n", families.items.count());
if(itsSlowUpdates)
storeSlowedMessage(families, MSG_DEL);
else
removeFonts(families.items, families.isSystem && !Misc::root());
}
void CFontList::storeSlowedMessage(const Families &families, EMsgType type)
{
int folder=families.isSystem ? FontInst::FOLDER_SYS : FontInst::FOLDER_USER;
bool playOld=false;
for(int i=0; i<NUM_MSGS_TYPES && !playOld; ++i)
if(itsSlowedMsgs[i][folder].count()>constMaxSlowed)
playOld=true;
if(playOld)
actionSlowedUpdates(families.isSystem);
FamilyCont::ConstIterator family(families.items.begin()),
fend(families.items.end());
for(; family!=fend; ++family)
{
FamilyCont::ConstIterator f=itsSlowedMsgs[type][folder].find(*family);
if(f!=itsSlowedMsgs[type][folder].end())
{
StyleCont::ConstIterator style((*family).styles().begin()),
send((*family).styles().end());
for(; style!=send; ++style)
{
StyleCont::ConstIterator st=(*f).styles().find(*style);
if(st==(*f).styles().end())
(*f).add(*style);
else
(*st).addFiles((*style).files());
}
}
else
itsSlowedMsgs[type][folder].insert(*family);
}
}
void CFontList::actionSlowedUpdates(bool sys)
{
int folder=sys ? FontInst::FOLDER_SYS : FontInst::FOLDER_USER;
for(int i=0; i<NUM_MSGS_TYPES; ++i)
if(!itsSlowedMsgs[i][folder].isEmpty())
{
if(MSG_ADD==i)
addFonts(itsSlowedMsgs[i][folder], sys && !Misc::root());
else
removeFonts(itsSlowedMsgs[i][folder], sys && !Misc::root());
itsSlowedMsgs[i][folder].clear();
}
}
void CFontList::addFonts(const FamilyCont &families, bool sys)
{
// bool emitLayout=!itsSlowUpdates || itsFamilies.isEmpty();
//
// if(emitLayout)
// emit layoutAboutToBeChanged();
FamilyCont::ConstIterator family(families.begin()),
end(families.end());
int famRowFrom=itsFamilies.count();
QSet<CFamilyItem *> modifiedFamilies;
for(; family!=end; ++family)
{
if((*family).styles().count()>0)
{
CFamilyItem *famItem=findFamily((*family).name());
if(famItem)
{
int rowFrom=famItem->fonts().count();
if(famItem->addFonts((*family).styles(), sys))
{
int rowTo=famItem->fonts().count();
if(rowTo!=rowFrom)
{
beginInsertRows(createIndex(famItem->rowNumber(), 0, famItem), rowFrom, rowTo);
endInsertRows();
}
modifiedFamilies.insert(famItem);
}
}
else
{
famItem=new CFamilyItem(*this, *family, sys);
itsFamilies.append(famItem);
itsFamilyHash[famItem->name()]=famItem;
modifiedFamilies.insert(famItem);
}
}
}
int famRowTo=itsFamilies.count();
if(famRowTo!=famRowFrom)
{
beginInsertRows(QModelIndex(), famRowFrom, famRowTo);
endInsertRows();
}
if(!modifiedFamilies.isEmpty())
{
QSet<CFamilyItem *>::Iterator it(modifiedFamilies.begin()),
end(modifiedFamilies.end());
for(; it!=end; ++it)
(*it)->refresh();
}
// if(emitLayout)
// emit layoutChanged();
}
void CFontList::removeFonts(const FamilyCont &families, bool sys)
{
// if(!itsSlowUpdates)
// emit layoutAboutToBeChanged();
FamilyCont::ConstIterator family(families.begin()),
end(families.end());
QSet<CFamilyItem *> modifiedFamilies;
for(; family!=end; ++family)
{
if((*family).styles().count()>0)
{
CFamilyItem *famItem=findFamily((*family).name());
if(famItem)
{
StyleCont::ConstIterator it((*family).styles().begin()),
end((*family).styles().end());
for(; it!=end; ++it)
{
CFontItem *fontItem=famItem->findFont((*it).value(), sys);
if(fontItem)
{
int before=fontItem->files().count();
fontItem->removeFiles((*it).files());
if(fontItem->files().count()!=before)
{
if(fontItem->files().isEmpty())
{
int row=-1;
if(1!=famItem->fonts().count())
{
row=fontItem->rowNumber();
beginRemoveRows(createIndex(famItem->rowNumber(), 0, famItem), row, row);
}
famItem->removeFont(fontItem, false);
if(-1!=row)
endRemoveRows();
}
else
fontItem->refresh();
}
}
}
if(famItem->fonts().isEmpty())
{
int row=famItem->rowNumber();
beginRemoveRows(QModelIndex(), row, row);
itsFamilyHash.remove(famItem->name());
itsFamilies.removeAt(row);
endRemoveRows();
}
else
modifiedFamilies.insert(famItem);
}
}
}
if(!modifiedFamilies.isEmpty())
{
QSet<CFamilyItem *>::Iterator it(modifiedFamilies.begin()),
end(modifiedFamilies.end());
for(; it!=end; ++it)
(*it)->refresh();
}
// if(!itsSlowUpdates)
// emit layoutChanged();
}
CFamilyItem * CFontList::findFamily(const QString &familyName)
{
CFamilyItemHash::Iterator it=itsFamilyHash.find(familyName);
return it==itsFamilyHash.end() ? 0L : *it;
}
inline bool matchString(const QString &str, const QString &pattern)
{
return pattern.isEmpty() || -1!=str.indexOf(pattern, 0, Qt::CaseInsensitive);
}
CFontListSortFilterProxy::CFontListSortFilterProxy(QObject *parent, QAbstractItemModel *model)
: QSortFilterProxyModel(parent),
itsGroup(NULL),
itsFilterCriteria(CFontFilter::CRIT_FAMILY),
itsFcQuery(NULL)
{
setSourceModel(model);
setSortCaseSensitivity(Qt::CaseInsensitive);
setFilterKeyColumn(0);
setDynamicSortFilter(false);
itsTimer=new QTimer(this);
connect(itsTimer, SIGNAL(timeout()), SLOT(timeout()));
connect(model, SIGNAL(layoutChanged()), SLOT(invalidate()));
itsTimer->setSingleShot(true);
}
QVariant CFontListSortFilterProxy::data(const QModelIndex &idx, int role) const
{
if (!idx.isValid())
return QVariant();
static const int constMaxFiles=20;
QModelIndex index(mapToSource(idx));
CFontModelItem *mi=static_cast<CFontModelItem *>(index.internalPointer());
if(!mi)
return QVariant();
switch(role)
{
case Qt::ToolTipRole:
if(CFontFilter::CRIT_FILENAME==itsFilterCriteria || CFontFilter::CRIT_LOCATION==itsFilterCriteria ||
CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria)
{
if(mi->isFamily())
{
CFamilyItem *fam=static_cast<CFamilyItem *>(index.internalPointer());
CFontItemCont::ConstIterator it(fam->fonts().begin()),
end(fam->fonts().end());
FileCont allFiles;
QString tip("<b>"+fam->name()+"</b>");
bool markMatch(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria);
tip+="<p style='white-space:pre'><table>";
for(; it!=end; ++it)
allFiles+=(*it)->files();
//qSort(allFiles);
FileCont::ConstIterator fit(allFiles.begin()),
fend(allFiles.end());
for(int i=0; fit!=fend && i<constMaxFiles; ++fit, ++i)
if(markMatch && itsFcQuery && (*fit).path()==itsFcQuery->file())
tip+="<tr><td><b>"+Misc::contractHome((*fit).path())+"</b></td></tr>";
else
tip+="<tr><td>"+Misc::contractHome((*fit).path())+"</td></tr>";
if(allFiles.count()>constMaxFiles)
tip+="<tr><td><i>"+i18n("...plus %1 more", allFiles.count()-constMaxFiles)+"</td></tr>";
tip+="</table></p>";
return tip;
}
else
{
CFontItem *font=static_cast<CFontItem *>(index.internalPointer());
QString tip("<b>"+font->name()+"</b>");
const FileCont &files(font->files());
bool markMatch(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria);
tip+="<p style='white-space:pre'><table>";
//qSort(files);
FileCont::ConstIterator fit(files.begin()),
fend(files.end());
for(int i=0; fit!=fend && i<constMaxFiles; ++fit, ++i)
if(markMatch && itsFcQuery && (*fit).path()==itsFcQuery->file())
tip+="<tr><td><b>"+Misc::contractHome((*fit).path())+"</b></td></tr>";
else
tip+="<tr><td>"+Misc::contractHome((*fit).path() )+"</td></tr>";
if(files.count()>constMaxFiles)
tip+="<tr><td><i>"+i18n("...plus %1 more", files.count()-constMaxFiles)+"</td></tr></li>";
tip+="</table></p>";
return tip;
}
}
break;
case Qt::FontRole:
if(COL_FONT==index.column() && mi->isSystem())
{
QFont font;
font.setItalic(true);
return font;
}
break;
case Qt::ForegroundRole:
if(COL_FONT==index.column() &&
( (mi->isFont() && !(static_cast<CFontItem *>(index.internalPointer()))->isEnabled()) ||
(mi->isFamily() && CFamilyItem::DISABLED==(static_cast<CFamilyItem *>(index.internalPointer()))->status())) )
return KColorScheme(QPalette::Active).foreground(KColorScheme::NegativeText).color();
break;
case Qt::DisplayRole:
if(COL_FONT==index.column())
{
if(mi->isFamily())
{
CFamilyItem *fam=static_cast<CFamilyItem *>(index.internalPointer());
return i18n("%1 [%2]", fam->name(), fam->fontCount());
}
else
return (static_cast<CFontItem *>(index.internalPointer()))->style();
}
break;
case Qt::DecorationRole:
if(mi->isFamily())
{
CFamilyItem *fam=static_cast<CFamilyItem *>(index.internalPointer());
switch(index.column())
{
case COL_STATUS:
switch(fam->status())
{
case CFamilyItem::PARTIAL:
return SmallIcon("dialog-ok", 0, KIconLoader::DisabledState);
case CFamilyItem::ENABLED:
return SmallIcon("dialog-ok");
case CFamilyItem::DISABLED:
return SmallIcon("dialog-cancel");
}
break;
default:
break;
}
}
else if(COL_STATUS==index.column())
return SmallIcon( (static_cast<CFontItem *>(index.internalPointer()))->isEnabled()
? "dialog-ok" : "dialog-cancel", 10);
break;
case Qt::SizeHintRole:
if(mi->isFamily())
return SmallIcon("dialog-ok").size()+QSize(0, 4);
default:
break;
}
return QVariant();
}
bool CFontListSortFilterProxy::acceptFont(CFontItem *fnt, bool checkFontText) const
{
if(itsGroup && (CGroupListItem::ALL!=itsGroup->type() || (!filterText().isEmpty() && checkFontText)))
{
bool fontMatch(!checkFontText);
if(!fontMatch)
switch(itsFilterCriteria)
{
case CFontFilter::CRIT_FONTCONFIG:
fontMatch=itsFcQuery
? fnt->name()==itsFcQuery->font() // || fnt->files().contains(itsFcQuery->file())
: false;
break;
case CFontFilter::CRIT_STYLE:
fontMatch=matchString(fnt->style(), itsFilterText);
break;
case CFontFilter::CRIT_FOUNDRY:
{
FileCont::ConstIterator it(fnt->files().begin()),
end(fnt->files().end());
for(; it!=end && !fontMatch; ++it)
fontMatch=0==(*it).foundry().compare(itsFilterText, Qt::CaseInsensitive);
break;
}
case CFontFilter::CRIT_FILENAME:
{
FileCont::ConstIterator it(fnt->files().begin()),
end(fnt->files().end());
for(; it!=end && !fontMatch; ++it)
{
QString file(Misc::getFile((*it).path()));
int pos(Misc::isHidden(file) ? 1 : 0);
if(pos==file.indexOf(itsFilterText, pos, Qt::CaseInsensitive))
fontMatch=true;
}
break;
}
case CFontFilter::CRIT_LOCATION:
{
FileCont::ConstIterator it(fnt->files().begin()),
end(fnt->files().end());
for(; it!=end && !fontMatch; ++it)
if(0==Misc::getDir((*it).path()).indexOf(itsFilterText, 0, Qt::CaseInsensitive))
fontMatch=true;
break;
}
case CFontFilter::CRIT_FILETYPE:
{
FileCont::ConstIterator it(fnt->files().begin()),
end(fnt->files().end());
QStringList::ConstIterator mimeEnd(itsFilterTypes.constEnd());
for(; it!=end && !fontMatch; ++it)
{
QStringList::ConstIterator mime(itsFilterTypes.constBegin());
for(; mime!=mimeEnd; ++mime)
if(Misc::checkExt((*it).path(), *mime))
fontMatch=true;
}
break;
}
default:
break;
}
return fontMatch && itsGroup->hasFont(fnt);
}
return true;
}
bool CFontListSortFilterProxy::acceptFamily(CFamilyItem *fam) const
{
CFontItemCont::ConstIterator it(fam->fonts().begin()),
end(fam->fonts().end());
bool familyMatch(CFontFilter::CRIT_FAMILY==itsFilterCriteria &&
matchString(fam->name(), itsFilterText));
for(; it!=end; ++it)
if(acceptFont(*it, !familyMatch))
return true;
return false;
}
bool CFontListSortFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QModelIndex index(sourceModel()->index(sourceRow, 0, sourceParent));
if(index.isValid())
{
CFontModelItem *mi=static_cast<CFontModelItem *>(index.internalPointer());
if(mi->isFont())
{
CFontItem *font=static_cast<CFontItem *>(index.internalPointer());
return acceptFont(font, !(CFontFilter::CRIT_FAMILY==itsFilterCriteria &&
matchString(font->family(), itsFilterText)));
}
else
return acceptFamily(static_cast<CFamilyItem *>(index.internalPointer()));
}
return false;
}
bool CFontListSortFilterProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
if(left.isValid() && right.isValid())
{
CFontModelItem *lmi=static_cast<CFontModelItem *>(left.internalPointer()),
*rmi=static_cast<CFontModelItem *>(right.internalPointer());
if(lmi->isFont()<rmi->isFont())
return true;
if(lmi->isFont())
{
CFontItem *lfi=static_cast<CFontItem *>(left.internalPointer()),
*rfi=static_cast<CFontItem *>(right.internalPointer());
if(COL_STATUS==filterKeyColumn())
{
if(lfi->isEnabled()<rfi->isEnabled() ||
(lfi->isEnabled()==rfi->isEnabled() &&
lfi->styleInfo()<rfi->styleInfo()))
return true;
}
else
if(lfi->styleInfo()<rfi->styleInfo())
return true;
}
else
{
CFamilyItem *lfi=static_cast<CFamilyItem *>(left.internalPointer()),
*rfi=static_cast<CFamilyItem *>(right.internalPointer());
if(COL_STATUS==filterKeyColumn())
{
if(lfi->status()<rfi->status() ||
(lfi->status()==rfi->status() && QString::localeAwareCompare(lfi->name(), rfi->name())<0))
return true;
}
else
if(QString::localeAwareCompare(lfi->name(), rfi->name())<0)
return true;
}
}
return false;
}
void CFontListSortFilterProxy::setFilterGroup(CGroupListItem *grp)
{
if(grp!=itsGroup)
{
// bool wasNull=!itsGroup;
itsGroup=grp;
// if(!(wasNull && itsGroup && CGroupListItem::ALL==itsGroup->type()))
clear();
}
}
void CFontListSortFilterProxy::setFilterText(const QString &text)
{
if(text!=itsFilterText)
{
//
// If we are filtering on file location, then expand ~ to /home/user, etc.
if (CFontFilter::CRIT_LOCATION==itsFilterCriteria && !text.isEmpty() && ('~'==text[0] || '$'==text[0]))
if('~'==text[0])
itsFilterText=1==text.length()
? QDir::homePath()
: QString(text).replace(0, 1, QDir::homePath());
else
itsFilterText=replaceEnvVar(text);
else
itsFilterText=text;
if(itsFilterText.isEmpty())
{
itsTimer->stop();
timeout();
}
else
itsTimer->start(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria ? 750 : 400);
}
}
void CFontListSortFilterProxy::setFilterCriteria(CFontFilter::ECriteria crit, const QStringList &ft)
{
if(crit!=itsFilterCriteria || ft!=itsFilterTypes)
{
itsFilterCriteria=crit;
itsFilterTypes=ft;
if(CFontFilter::CRIT_LOCATION==itsFilterCriteria)
setFilterText(itsFilterText);
itsTimer->stop();
timeout();
}
}
void CFontListSortFilterProxy::timeout()
{
if(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria)
{
int commaPos=itsFilterText.indexOf(',');
QString query(itsFilterText);
if(-1!=commaPos)
{
QString style(query.mid(commaPos+1));
query=query.left(commaPos);
query=query.trimmed();
query+=":style=";
style=style.trimmed();
query+=style;
}
else
query=query.trimmed();
if(!itsFcQuery)
{
itsFcQuery=new CFcQuery(this);
connect(itsFcQuery, SIGNAL(finished()), SLOT(fcResults()));
}
itsFcQuery->run(query);
}
else
{
clear();
emit refresh();
}
}
void CFontListSortFilterProxy::fcResults()
{
if(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria)
{
clear();
emit refresh();
}
}
CFontListView::CFontListView(QWidget *parent, CFontList *model)
: QTreeView(parent),
itsProxy(new CFontListSortFilterProxy(this, model)),
itsModel(model),
itsAllowDrops(false)
{
setModel(itsProxy);
itsModel=model;
header()->setStretchLastSection(false);
resizeColumnToContents(COL_STATUS);
header()->setResizeMode(COL_STATUS, QHeaderView::Fixed);
header()->setResizeMode(COL_FONT, QHeaderView::Stretch);
setSelectionMode(QAbstractItemView::ExtendedSelection);
setSelectionBehavior(QAbstractItemView::SelectRows);
setSortingEnabled(true);
sortByColumn(COL_FONT, Qt::AscendingOrder);
setAllColumnsShowFocus(true);
setAlternatingRowColors(true);
setAcceptDrops(true);
setDropIndicatorShown(false);
setDragEnabled(true);
setDragDropMode(QAbstractItemView::DragDrop);
header()->setClickable(true);
header()->setSortIndicatorShown(true);
connect(this, SIGNAL(collapsed(QModelIndex)), SLOT(itemCollapsed(QModelIndex)));
connect(header(), SIGNAL(sectionClicked(int)), SLOT(setSortColumn(int)));
connect(itsProxy, SIGNAL(refresh()), SIGNAL(refresh()));
connect(itsModel, SIGNAL(listingPercent(int)), SLOT(listingPercent(int)));
setWhatsThis(model->whatsThis());
header()->setWhatsThis(whatsThis());
itsMenu=new QMenu(this);
itsDeleteAct=itsMenu->addAction(KIcon("edit-delete"), i18n("Delete"),
this, SIGNAL(del()));
itsMenu->addSeparator();
itsEnableAct=itsMenu->addAction(KIcon("enablefont"), i18n("Enable"),
this, SIGNAL(enable()));
itsDisableAct=itsMenu->addAction(KIcon("disablefont"), i18n("Disable"),
this, SIGNAL(disable()));
if(!Misc::app(KFI_VIEWER).isEmpty() || !Misc::app(KFI_VIEWER).isEmpty())
itsMenu->addSeparator();
itsPrintAct=Misc::app(KFI_VIEWER).isEmpty() ? 0L : itsMenu->addAction(KIcon("document-print"), i18n("Print..."),
this, SIGNAL(print()));
itsViewAct=Misc::app(KFI_VIEWER).isEmpty() ? 0L : itsMenu->addAction(KIcon("kfontview"), i18n("Open in Font Viewer"),
this, SLOT(view()));
itsMenu->addSeparator();
itsMenu->addAction(KIcon("view-refresh"), i18n("Reload"), model, SLOT(load()));
}
void CFontListView::getFonts(CJobRunner::ItemList &urls, QStringList &fontNames, QSet<Misc::TFont> *fonts,
bool selected, bool getEnabled, bool getDisabled)
{
QModelIndexList selectedItems(selected ? selectedIndexes() : allIndexes());
QSet<CFontItem *> usedFonts;
foreach(QModelIndex index, selectedItems) {
if(index.isValid())
{
QModelIndex realIndex(itsProxy->mapToSource(index));
if(realIndex.isValid())
{
if((static_cast<CFontModelItem *>(realIndex.internalPointer()))->isFont())
{
CFontItem *font=static_cast<CFontItem *>(realIndex.internalPointer());
addFont(font, urls, fontNames, fonts, usedFonts,
getEnabled, getDisabled);
}
else
{
CFamilyItem *fam=static_cast<CFamilyItem *>(realIndex.internalPointer());
for(int ch=0; ch<fam->fontCount(); ++ch)
{
QModelIndex child(itsProxy->mapToSource(index.child(ch, 0)));
if(child.isValid() &&
(static_cast<CFontModelItem *>(child.internalPointer()))->isFont())
{
CFontItem *font=static_cast<CFontItem *>(child.internalPointer());
addFont(font, urls, fontNames, fonts, usedFonts,
getEnabled, getDisabled);
}
}
}
}
}
}
fontNames=CFontList::compact(fontNames);
}
QSet<QString> CFontListView::getFiles()
{
QModelIndexList items(allIndexes());
QSet<QString> files;
foreach(QModelIndex index, items) {
if(index.isValid())
{
QModelIndex realIndex(itsProxy->mapToSource(index));
if(realIndex.isValid())
if((static_cast<CFontModelItem *>(realIndex.internalPointer()))->isFont())
{
CFontItem *font=static_cast<CFontItem *>(realIndex.internalPointer());
FileCont::ConstIterator it(font->files().begin()),
end(font->files().end());
for(; it!=end; ++it)
{
QStringList assoc;
files.insert((*it).path());
Misc::getAssociatedFiles((*it).path(), assoc);
QStringList::ConstIterator ait(assoc.constBegin()),
aend(assoc.constEnd());
for(; ait!=aend; ++ait)
files.insert(*ait);
}
}
}
}
return files;
}
void CFontListView::getPrintableFonts(QSet<Misc::TFont> &items, bool selected)
{
QModelIndexList selectedItems(selected ? selectedIndexes() : allIndexes());
foreach(QModelIndex index, selectedItems)
{
CFontItem *font=NULL;
if(index.isValid() && 0==index.column())
{
QModelIndex realIndex(itsProxy->mapToSource(index));
if(realIndex.isValid())
{
if((static_cast<CFontModelItem *>(realIndex.internalPointer()))->isFont())
font=static_cast<CFontItem *>(realIndex.internalPointer());
else
{
CFamilyItem *fam=static_cast<CFamilyItem *>(realIndex.internalPointer());
font=fam->regularFont();
}
}
}
if(font && !font->isBitmap() && font->isEnabled())
items.insert(Misc::TFont(font->family(), font->styleInfo()));
}
}
void CFontListView::setFilterGroup(CGroupListItem *grp)
{
CGroupListItem *oldGrp(itsProxy->filterGroup());
itsProxy->setFilterGroup(grp);
itsAllowDrops=grp && !grp->isCustom();
if(!Misc::root())
{
bool refreshStats(false);
if(!grp || !oldGrp)
refreshStats=true;
else
{
// Check to see whether we have changed from listing all fonts,
// listing just system or listing personal fonts.
CGroupListItem::EType aType(CGroupListItem::CUSTOM==grp->type() ||
CGroupListItem::ALL==grp->type() ||
CGroupListItem::UNCLASSIFIED==grp->type()
? CGroupListItem::CUSTOM : grp->type()),
bType(CGroupListItem::CUSTOM==oldGrp->type() ||
CGroupListItem::ALL==oldGrp->type() ||
CGroupListItem::UNCLASSIFIED==oldGrp->type()
? CGroupListItem::CUSTOM : oldGrp->type());
refreshStats=aType!=bType;
}
if(refreshStats)
itsModel->refresh(!grp || !grp->isPersonal(),
!grp || !grp->isSystem());
}
// when switching groups, for some reason it is not always sorted.
setSortingEnabled(true);
}
void CFontListView::listingPercent(int percent)
{
// when the font list is first loaded, for some reason it is not always sorted.
// re-enabling sorting here seems to fix the issue - BUG 221610
if(100==percent)
setSortingEnabled(true);
}
void CFontListView::refreshFilter()
{
itsProxy->clear();
}
void CFontListView::filterText(const QString &text)
{
itsProxy->setFilterText(text);
}
void CFontListView::filterCriteria(int crit, const QStringList &ft)
{
itsProxy->setFilterCriteria((CFontFilter::ECriteria)crit, ft);
}
void CFontListView::stats(int &enabled, int &disabled, int &partial)
{
enabled=disabled=partial=0;
for(int i=0; i<itsProxy->rowCount(); ++i)
{
QModelIndex idx(itsProxy->index(i, 0, QModelIndex()));
if(!idx.isValid())
break;
QModelIndex sourceIdx(itsProxy->mapToSource(idx));
if(!sourceIdx.isValid())
break;
if((static_cast<CFontModelItem *>(sourceIdx.internalPointer()))->isFamily())
switch((static_cast<CFamilyItem *>(sourceIdx.internalPointer()))->status())
{
case CFamilyItem::ENABLED:
enabled++;
break;
case CFamilyItem::DISABLED:
disabled++;
break;
case CFamilyItem::PARTIAL:
partial++;
break;
}
}
}
void CFontListView::selectedStatus(bool &enabled, bool &disabled)
{
QModelIndexList selected(selectedIndexes());
enabled=disabled=false;
foreach(QModelIndex index, selected)
{
QModelIndex realIndex(itsProxy->mapToSource(index));
if(realIndex.isValid())
{
if((static_cast<CFontModelItem *>(realIndex.internalPointer()))->isFamily())
{
switch((static_cast<CFamilyItem *>(realIndex.internalPointer()))->status())
{
case CFamilyItem::ENABLED:
enabled=true;
break;
case CFamilyItem::DISABLED:
disabled=true;
break;
case CFamilyItem::PARTIAL:
enabled=true;
disabled=true;
break;
}
}
else
{
if((static_cast<CFontItem *>(realIndex.internalPointer()))->isEnabled())
enabled=true;
else
disabled=true;
}
}
if(enabled && disabled)
break;
}
}
QModelIndexList CFontListView::allFonts()
{
QModelIndexList rv;
int rowCount(itsProxy->rowCount());
for(int i=0; i<rowCount; ++i)
{
QModelIndex idx(itsProxy->index(i, 0, QModelIndex()));
int childRowCount(itsProxy->rowCount(idx));
for(int j=0; j<childRowCount; ++j)
{
QModelIndex child(itsProxy->index(j, 0, idx));
if(child.isValid())
rv.append(itsProxy->mapToSource(child));
}
}
return rv;
}
void CFontListView::selectFirstFont()
{
if(0==selectedIndexes().count())
for(int i=0; i<NUM_COLS; ++i)
{
QModelIndex idx(itsProxy->index(0, i, QModelIndex()));
if(idx.isValid())
selectionModel()->select(idx, QItemSelectionModel::Select);
}
}
void CFontListView::setSortColumn(int col)
{
if(col!=itsProxy->filterKeyColumn())
{
itsProxy->setFilterKeyColumn(col);
itsProxy->clear();
}
}
void CFontListView::selectionChanged(const QItemSelection &selected,
const QItemSelection &deselected)
{
QAbstractItemView::selectionChanged(selected, deselected);
if(itsModel->slowUpdates())
return;
emit itemsSelected(getSelectedItems());
}
QModelIndexList CFontListView::getSelectedItems()
{
//
// Go throgh current selection, and for any 'font' items that are selected,
// ensure 'family' item is not...
QModelIndexList selectedItems(selectedIndexes()),
deselectList;
QSet<CFontModelItem *> selectedFamilies;
bool enabled;
foreach(QModelIndex index, selectedItems) {
if(index.isValid())
{
QModelIndex realIndex(itsProxy->mapToSource(index));
if(realIndex.isValid())
{
if((static_cast<CFontModelItem *>(realIndex.internalPointer()))->isFont())
{
CFontItem *font=static_cast<CFontItem *>(realIndex.internalPointer());
enabled = font->isEnabled();
if(!selectedFamilies.contains(font->parent()))
{
selectedFamilies.insert(font->parent());
for(int i=0; i<NUM_COLS; ++i)
deselectList.append(itsProxy->mapFromSource(
itsModel->createIndex(font->parent()->rowNumber(),
i, font->parent())));
}
}
else
{
switch((static_cast<CFamilyItem *>(realIndex.internalPointer()))->status())
{
case CFamilyItem::ENABLED:
enabled = true;
break;
case CFamilyItem::DISABLED:
enabled = false;
break;
case CFamilyItem::PARTIAL:
enabled = true;
break;
}
}
}
}
}
if(deselectList.count()) {
foreach(QModelIndex index, deselectList) {
selectionModel()->select(index, QItemSelectionModel::Deselect);
}
}
QModelIndexList sel;
QSet<void *> pointers;
selectedItems=selectedIndexes();
foreach(QModelIndex index, selectedItems)
{
QModelIndex idx(itsProxy->mapToSource(index));
if(!pointers.contains(idx.internalPointer()))
{
pointers.insert(idx.internalPointer());
sel.append(idx);
}
}
return sel;
}
void CFontListView::itemCollapsed(const QModelIndex &idx)
{
if(idx.isValid())
{
QModelIndex index(itsProxy->mapToSource(idx));
if(index.isValid() && (static_cast<CFontModelItem *>(index.internalPointer()))->isFamily())
{
CFamilyItem *fam=static_cast<CFamilyItem *>(index.internalPointer());
CFontItemCont::ConstIterator it(fam->fonts().begin()),
end(fam->fonts().end());
for(; it!=end; ++it)
for(int i=0; i<NUM_COLS; ++i)
selectionModel()->select(itsProxy->mapFromSource(itsModel->createIndex((*it)->rowNumber(),
i, *it)),
QItemSelectionModel::Deselect);
}
}
}
static bool isScalable(const QString &str)
{
QByteArray cFile(QFile::encodeName(str));
return Misc::checkExt(cFile, "ttf") || Misc::checkExt(cFile, "otf") || Misc::checkExt(cFile, "ttc") ||
Misc::checkExt(cFile, "pfa") || Misc::checkExt(cFile, "pfb");
}
void CFontListView::view()
{
// Number of fonts user has selected, before we ask if they really want to view them all...
static const int constMaxBeforePrompt=10;
QModelIndexList selectedItems(selectedIndexes());
QSet<CFontItem *> fonts;
foreach(QModelIndex index, selectedItems)
{
QModelIndex realIndex(itsProxy->mapToSource(index));
if(realIndex.isValid())
{
if((static_cast<CFontModelItem *>(realIndex.internalPointer()))->isFont())
{
CFontItem *font(static_cast<CFontItem *>(realIndex.internalPointer()));
fonts.insert(font);
}
else
{
CFontItem *font((static_cast<CFamilyItem *>(realIndex.internalPointer()))->regularFont());
if(font)
fonts.insert(font);
}
}
}
if(fonts.count() &&
(fonts.count()<constMaxBeforePrompt ||
KMessageBox::Yes==KMessageBox::questionYesNo(this, i18n("Open all %1 fonts in font viewer?", fonts.count()))))
{
QSet<CFontItem *>::ConstIterator it(fonts.begin()),
end(fonts.end());
QStringList args;
for(; it!=end; ++it)
{
QString file;
int index(0);
if(!(*it)->isEnabled())
{
// For a disabled font, we need to find the first scalable font entry in its file list...
FileCont::ConstIterator fit((*it)->files().begin()),
fend((*it)->files().end());
for(; fit!=fend; ++fit)
if(isScalable((*fit).path()))
{
file=(*fit).path();
index=(*fit).index();
break;
}
if(file.isEmpty())
{
file=(*it)->fileName();
index=(*it)->index();
}
}
args << FC::encode((*it)->family(), (*it)->styleInfo(), file, index).url();
}
QProcess::startDetached(Misc::app(KFI_VIEWER), args);
}
}
QModelIndexList CFontListView::allIndexes()
{
QModelIndexList rv;
int rowCount(itsProxy->rowCount());
for(int i=0; i<rowCount; ++i)
{
QModelIndex idx(itsProxy->index(i, 0, QModelIndex()));
int childRowCount(itsProxy->rowCount(idx));
rv.append(idx);
for(int j=0; j<childRowCount; ++j)
{
QModelIndex child(itsProxy->index(j, 0, idx));
if(child.isValid())
rv.append(child);
}
}
return rv;
}
void CFontListView::startDrag(Qt::DropActions supportedActions)
{
QModelIndexList indexes(selectedIndexes());
if (indexes.count())
{
QMimeData *data = model()->mimeData(indexes);
if (!data)
return;
QModelIndex index(itsProxy->mapToSource(indexes.first()));
const char *icon="application-x-font-pcf";
if(index.isValid())
{
CFontItem *font=(static_cast<CFontModelItem *>(index.internalPointer()))->isFont()
? static_cast<CFontItem *>(index.internalPointer())
: (static_cast<CFamilyItem *>(index.internalPointer()))->regularFont();
if(font && !font->isBitmap())
// if("application/x-font-type1"==font->mimetype())
// icon="application-x-font-type1";
// else
icon="application-x-font-ttf";
}
QPoint hotspot;
QPixmap pix(DesktopIcon(icon, KIconLoader::SizeMedium));
hotspot.setX(0); // pix.width()/2);
hotspot.setY(0); // pix.height()/2);
QDrag *drag = new QDrag(this);
drag->setPixmap(pix);
drag->setMimeData(data);
drag->setHotSpot(hotspot);
drag->start(supportedActions);
}
}
void CFontListView::dragEnterEvent(QDragEnterEvent *event)
{
if(itsAllowDrops && event->mimeData()->hasFormat(QLatin1String("text/uri-list"))) // "application/x-kde-urilist" ??
event->acceptProposedAction();
}
void CFontListView::dropEvent(QDropEvent *event)
{
if(itsAllowDrops && event->mimeData()->hasFormat(QLatin1String("text/uri-list")))
{
event->acceptProposedAction();
QList<QUrl> urls(event->mimeData()->urls());
QList<QUrl>::ConstIterator it(urls.begin()),
end(urls.end());
QStringList::ConstIterator mtEnd(CFontList::fontMimeTypes.constEnd());
QSet<KUrl> kurls;
for(; it!=end; ++it)
{
KMimeType::Ptr mime=KMimeType::findByUrl(*it, 0, false, true);
QStringList::ConstIterator mt(CFontList::fontMimeTypes.constBegin());
for(; mt!=mtEnd; ++mt)
if(mime->is(*mt))
{
kurls.insert(*it);
break;
}
}
if(kurls.count())
emit fontsDropped(kurls);
}
}
void CFontListView::contextMenuEvent(QContextMenuEvent *ev)
{
bool valid(indexAt(ev->pos()).isValid());
itsDeleteAct->setEnabled(valid);
bool en(false),
dis(false);
QModelIndexList selectedItems(selectedIndexes());
foreach(QModelIndex index, selectedItems)
{
QModelIndex realIndex(itsProxy->mapToSource(index));
if(realIndex.isValid())
{
if((static_cast<CFontModelItem *>(realIndex.internalPointer()))->isFont())
{
if((static_cast<CFontItem *>(realIndex.internalPointer())->isEnabled()))
en=true;
else
dis=true;
}
else
{
switch((static_cast<CFamilyItem *>(realIndex.internalPointer()))->status())
{
case CFamilyItem::ENABLED:
en=true;
break;
case CFamilyItem::DISABLED:
dis=true;
break;
case CFamilyItem::PARTIAL:
en=dis=true;
break;
}
}
}
if(en && dis)
break;
}
itsEnableAct->setEnabled(dis);
itsDisableAct->setEnabled(en);
if(itsPrintAct)
itsPrintAct->setEnabled(en|dis);
if(itsViewAct)
itsViewAct->setEnabled(en|dis);
itsMenu->popup(ev->globalPos());
}
bool CFontListView::viewportEvent(QEvent *event)
{
executeDelayedItemsLayout();
return QTreeView::viewportEvent(event);
}
}
#include "moc_FontList.cpp"