* 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 "JobRunner.h"
#include "KfiConstants.h"
#include "Misc.h"
#include "Fc.h"
#include "ActionLabel.h"
#include <QTemporaryDir>
#include <KSharedConfig>
#include <KConfigGroup>
#include <kio/global.h>
#include <KIO/StatJob>
#include <KIO/FileCopyJob>
#include <KJobWidgets>
#include <QGridLayout>
#include <QProgressBar>
#include <QLabel>
#include <QX11Info>
#include <QStackedWidget>
#include <QCheckBox>
#include <QStyleOption>
#include <QStyle>
#include <QCloseEvent>
#include <QTimer>
#include <QDebug>
#include <QProcess>
#include <QDBusServiceWatcher>
#include <fontconfig/fontconfig.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <unistd.h>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
#include <X11/Xlib.h>
#include "config-fontinst.h"
#define CFG_GROUP "Runner Dialog"
#define CFG_DONT_SHOW_FINISHED_MSG "DontShowFinishedMsg"
namespace KFI
{
Q_GLOBAL_STATIC(FontInstInterface, theInterface)
FontInstInterface * CJobRunner::dbus()
{
return theInterface;
}
QString CJobRunner::folderName(bool sys)
{
if(!theInterface)
return QString();
QDBusPendingReply<QString> reply=theInterface->folderName(sys);
reply.waitForFinished();
return reply.isError() ? QString() : reply.argumentAt<0>();
}
void CJobRunner::startDbusService()
{
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(OrgKdeFontinstInterface::staticInterfaceName())) {
const QString fontinst = QStringLiteral(KFONTINST_LIB_EXEC_DIR"/fontinst");
qDebug() << "Service " << OrgKdeFontinstInterface::staticInterfaceName() << " not registered, starting" << fontinst;
QProcess::startDetached(fontinst, QStringList());
}
}
static const int constDownloadFailed=-1;
static const int constInterfaceCheck=5*1000;
static void decode(const QUrl &url, Misc::TFont &font, bool &system)
{
font=FC::decode(url);
QUrlQuery query(url);
system = (query.hasQueryItem("sys") && query.queryItemValue("sys") == QLatin1String("true"));
}
QUrl CJobRunner::encode(const QString &family, quint32 style, bool system)
{
QUrl url(FC::encode(family, style));
url.addQueryItem("sys", system ? "true" : "false");
return url;
}
enum EPages
{
PAGE_PROGRESS,
PAGE_SKIP,
PAGE_ERROR,
PAGE_CANCEL,
PAGE_COMPLETE
};
enum Response
{
RESP_CONTINUE,
RESP_AUTO,
RESP_CANCEL
};
static void addIcon(QGridLayout *layout, QFrame *page, const char *iconName, int iconSize)
{
QLabel *icon=new QLabel(page);
icon->setPixmap(QIcon::fromTheme(iconName).pixmap(iconSize));
icon->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
layout->addWidget(icon, 0, 0);
}
CJobRunner::CJobRunner(QWidget *parent, int xid)
: QDialog(parent),
itsIt(itsUrls.end()),
itsEnd(itsIt),
itsAutoSkip(false),
itsCancelClicked(false),
itsModified(false),
itsTempDir(nullptr)
{
setModal(true);
if(nullptr==parent && 0!=xid)
XSetTransientForHint(QX11Info::display(), winId(), xid);
itsButtonBox = new QDialogButtonBox;
connect(itsButtonBox, &QDialogButtonBox::clicked, this, &CJobRunner::slotButtonClicked);
itsSkipButton = new QPushButton(i18n("Skip"));
itsButtonBox->addButton(itsSkipButton, QDialogButtonBox::ActionRole);
itsSkipButton->hide();
itsAutoSkipButton = new QPushButton(i18n("AutoSkip"));
itsButtonBox->addButton(itsAutoSkipButton, QDialogButtonBox::ActionRole);
itsAutoSkipButton->hide();
itsStack = new QStackedWidget(this);
QVBoxLayout *mainLayout = new QVBoxLayout;
setLayout(mainLayout);
mainLayout->addWidget(itsStack);
mainLayout->addWidget(itsButtonBox);
QStyleOption option;
option.initFrom(this);
int iconSize=style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, this);
QFrame *page = new QFrame(itsStack);
QGridLayout *layout=new QGridLayout(page);
itsStatusLabel=new QLabel(page);
itsProgress=new QProgressBar(page);
layout->addWidget(itsActionLabel = new CActionLabel(this), 0, 0, 2, 1);
layout->addWidget(itsStatusLabel, 0, 1);
layout->addWidget(itsProgress, 1, 1);
layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 2, 0);
itsStack->insertWidget(PAGE_PROGRESS, page);
page=new QFrame(itsStack);
layout=new QGridLayout(page);
itsSkipLabel=new QLabel(page);
itsSkipLabel->setWordWrap(true);
addIcon(layout, page, "dialog-error", iconSize);
layout->addWidget(itsSkipLabel, 0, 1);
layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0);
itsStack->insertWidget(PAGE_SKIP, page);
page=new QFrame(itsStack);
layout=new QGridLayout(page);
itsErrorLabel=new QLabel(page);
itsErrorLabel->setWordWrap(true);
addIcon(layout, page, "dialog-error", iconSize);
layout->addWidget(itsErrorLabel, 0, 1);
layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0);
itsStack->insertWidget(PAGE_ERROR, page);
page=new QFrame(itsStack);
layout=new QGridLayout(page);
QLabel *cancelLabel=new QLabel(i18n("<h3>Cancel?</h3><p>Are you sure you wish to cancel?</p>"), page);
cancelLabel->setWordWrap(true);
addIcon(layout, page, "dialog-warning", iconSize);
layout->addWidget(cancelLabel, 0, 1);
layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0);
itsStack->insertWidget(PAGE_CANCEL, page);
if(KSharedConfig::openConfig(KFI_UI_CFG_FILE)->group(CFG_GROUP).readEntry(CFG_DONT_SHOW_FINISHED_MSG, false))
itsDontShowFinishedMsg= nullptr;
else
{
page=new QFrame(itsStack);
layout=new QGridLayout(page);
QLabel *finishedLabel=new QLabel(i18n("<h3>Finished</h3>"
"<p>Please note that any open applications will need to be "
"restarted in order for any changes to be noticed.</p>"),
page);
finishedLabel->setWordWrap(true);
addIcon(layout, page, "dialog-information", iconSize);
layout->addWidget(finishedLabel, 0, 1);
layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0);
itsDontShowFinishedMsg = new QCheckBox(i18n("Do not show this message again"), page);
itsDontShowFinishedMsg->setChecked(false);
layout->addItem(new QSpacerItem(0, layout->spacing(), QSizePolicy::Fixed, QSizePolicy::Fixed), 2, 0);
layout->addWidget(itsDontShowFinishedMsg, 3, 1);
layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 4, 0);
itsStack->insertWidget(PAGE_COMPLETE, page);
}
QDBusServiceWatcher *watcher = new QDBusServiceWatcher(QLatin1String(OrgKdeFontinstInterface::staticInterfaceName()),
QDBusConnection::sessionBus(),
QDBusServiceWatcher::WatchForOwnerChange, this);
connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &CJobRunner::dbusServiceOwnerChanged);
connect(dbus(), &OrgKdeFontinstInterface::status, this, &CJobRunner::dbusStatus);
setMinimumSize(420, 160);
}
CJobRunner::~CJobRunner()
{
delete itsTempDir;
}
void CJobRunner::getAssociatedUrls(const QUrl &url, QList<QUrl> &list, bool afmAndPfm, QWidget *widget)
{
QString ext(url.path());
int dotPos(ext.lastIndexOf('.'));
bool check(false);
if(-1==dotPos)
check=true;
else
{
ext=ext.mid(dotPos+1);
check=0==ext.compare("pfa", Qt::CaseInsensitive) ||
0==ext.compare("pfb", Qt::CaseInsensitive);
}
if(check)
{
const char *afm[]={"afm", "AFM", "Afm", nullptr},
*pfm[]={"pfm", "PFM", "Pfm", nullptr};
bool gotAfm(false),
localFile(url.isLocalFile());
int e;
for(e=0; afm[e]; ++e)
{
QUrl statUrl(url);
statUrl.setPath(Misc::changeExt(url.path(), afm[e]));
bool urlExists = false;
if (localFile) {
urlExists = Misc::fExists(statUrl.toLocalFile());
} else {
auto job = KIO::stat(statUrl);
KJobWidgets::setWindow(job, widget);
job->exec();
urlExists = !job->error();
}
if (urlExists)
{
list.append(statUrl);
gotAfm=true;
break;
}
}
if(afmAndPfm || !gotAfm)
for(e=0; pfm[e]; ++e)
{
QUrl statUrl(url);
statUrl.setPath(Misc::changeExt(url.path(), pfm[e]));
bool urlExists = false;
if (localFile) {
urlExists = Misc::fExists(statUrl.toLocalFile());
} else {
auto job = KIO::stat(statUrl);
KJobWidgets::setWindow(job, widget);
job->exec();
urlExists = !job->error();
}
if (urlExists)
{
list.append(statUrl);
break;
}
}
}
}
static void addEnableActions(CJobRunner::ItemList &urls)
{
CJobRunner::ItemList modified;
CJobRunner::ItemList::ConstIterator it(urls.constBegin()),
end(urls.constEnd());
for(; it!=end; ++it)
{
if((*it).isDisabled)
{
CJobRunner::Item item(*it);
item.fileName=QLatin1String("--");
modified.append(item);
}
modified.append(*it);
}
urls=modified;
}
int CJobRunner::exec(ECommand cmd, const ItemList &urls, bool destIsSystem)
{
itsAutoSkip=itsCancelClicked=itsModified=false;
switch(cmd)
{
case CMD_INSTALL:
setWindowTitle(i18n("Installing"));
break;
case CMD_DELETE:
setWindowTitle(i18n("Uninstalling"));
break;
case CMD_ENABLE:
setWindowTitle(i18n("Enabling"));
break;
case CMD_MOVE:
setWindowTitle(i18n("Moving"));
break;
case CMD_UPDATE:
setWindowTitle(i18n("Updating"));
itsModified=true;
break;
case CMD_REMOVE_FILE:
setWindowTitle(i18n("Removing"));
break;
default:
case CMD_DISABLE:
setWindowTitle(i18n("Disabling"));
}
itsDestIsSystem=destIsSystem;
itsUrls=urls;
if(CMD_INSTALL==cmd)
std::sort(itsUrls.begin(), itsUrls.end());
else if(CMD_MOVE==cmd)
addEnableActions(itsUrls);
itsIt=itsUrls.constBegin();
itsEnd=itsUrls.constEnd();
itsPrev=itsEnd;
itsProgress->setValue(0);
itsProgress->setRange(0, itsUrls.count()+1);
itsProgress->show();
itsCmd=cmd;
itsCurrentFile=QString();
itsStatusLabel->setText(QString());
setPage(PAGE_PROGRESS);
QTimer::singleShot(0, this, &CJobRunner::doNext);
QTimer::singleShot(constInterfaceCheck, this, &CJobRunner::checkInterface);
itsActionLabel->startAnimation();
int rv=QDialog::exec();
if(itsTempDir)
{
delete itsTempDir;
itsTempDir= nullptr;
}
return rv;
}
void CJobRunner::doNext()
{
if(itsIt==itsEnd)
{
if(itsModified)
{
dbus()->reconfigure(getpid(), CMD_UPDATE==itsCmd);
itsCmd=CMD_UPDATE;
itsStatusLabel->setText(i18n("Updating font configuration. Please wait..."));
itsProgress->setValue(itsProgress->maximum());
emit configuring();
}
else
{
itsActionLabel->stopAnimation();
if(PAGE_ERROR!=itsStack->currentIndex())
reject();
}
}
else
{
Misc::TFont font;
bool system;
switch(itsCmd)
{
case CMD_INSTALL:
{
itsCurrentFile=fileName((*itsIt));
if(itsCurrentFile.isEmpty())
dbusStatus(getpid(), constDownloadFailed);
else
{
bool createAfm=Item::TYPE1_PFM==(*itsIt).type &&
(itsPrev==itsEnd || (*itsIt).fileName!=(*itsPrev).fileName || Item::TYPE1_AFM!=(*itsPrev).type);
dbus()->install(itsCurrentFile, createAfm, itsDestIsSystem, getpid(), false);
}
break;
}
case CMD_DELETE:
decode(*itsIt, font, system);
dbus()->uninstall(font.family, font.styleInfo, system, getpid(), false);
break;
case CMD_ENABLE:
decode(*itsIt, font, system);
dbus()->enable(font.family, font.styleInfo, system, getpid(), false);
break;
case CMD_DISABLE:
decode(*itsIt, font, system);
dbus()->disable(font.family, font.styleInfo, system, getpid(), false);
break;
case CMD_MOVE:
decode(*itsIt, font, system);
if((*itsIt).fileName==QLatin1String("--"))
{
setWindowTitle(i18n("Enabling"));
dbus()->enable(font.family, font.styleInfo, system, getpid(), false);
}
else
{
if(itsPrev!=itsEnd && (*itsPrev).fileName==QLatin1String("--"))
setWindowTitle(i18n("Moving"));
dbus()->move(font.family, font.styleInfo, itsDestIsSystem, getpid(), false);
}
break;
case CMD_REMOVE_FILE:
decode(*itsIt, font, system);
dbus()->removeFile(font.family, font.styleInfo, (*itsIt).fileName, system, getpid(), false);
break;
default:
break;
}
itsStatusLabel->setText(CMD_INSTALL==itsCmd ? (*itsIt).url() : FC::createName(FC::decode(*itsIt)));
itsProgress->setValue(itsProgress->value()+1);
itsPrev=itsIt;
}
}
void CJobRunner::checkInterface()
{
if(itsIt==itsUrls.constBegin() && !FontInst::isStarted(dbus()))
{
setPage(PAGE_ERROR, i18n("Unable to start backend."));
itsActionLabel->stopAnimation();
itsIt=itsEnd;
}
}
void CJobRunner::dbusServiceOwnerChanged(const QString &name, const QString &from, const QString &to)
{
if(to.isEmpty() && !from.isEmpty() && name==QLatin1String(OrgKdeFontinstInterface::staticInterfaceName()) && itsIt!=itsEnd)
{
setPage(PAGE_ERROR, i18n("Backend died, but has been restarted. Please try again."));
itsActionLabel->stopAnimation();
itsIt=itsEnd;
}
}
void CJobRunner::dbusStatus(int pid, int status)
{
if(pid!=getpid())
return;
if(CMD_UPDATE==itsCmd)
{
setPage(PAGE_COMPLETE);
return;
}
itsLastDBusStatus=status;
if(itsCancelClicked)
{
itsActionLabel->stopAnimation();
setPage(PAGE_CANCEL);
return;
if(RESP_CANCEL==itsResponse)
itsIt=itsEnd;
itsCancelClicked=false;
setPage(PAGE_PROGRESS);
itsActionLabel->startAnimation();
*/
}
if(itsIt==itsEnd)
{
doNext();
}
else if (0==status)
{
itsModified=true;
++itsIt;
doNext();
}
else
{
bool cont(itsAutoSkip && itsUrls.count()>1);
QString currentName((*itsIt).fileName);
if(!cont)
{
itsActionLabel->stopAnimation();
if(FontInst::STATUS_SERVICE_DIED==status)
{
setPage(PAGE_ERROR, errorString(status));
itsIt=itsEnd;
}
else
{
ItemList::ConstIterator lastPartOfCurrent(itsIt),
next(itsIt==itsEnd ? itsEnd : itsIt+1);
if(next!=itsEnd && Item::TYPE1_FONT==(*itsIt).type &&
(*next).fileName==currentName && (Item::TYPE1_AFM==(*next).type || Item::TYPE1_PFM==(*next).type))
{
next++;
if(next!=itsEnd && (*next).fileName==currentName && (Item::TYPE1_AFM==(*next).type || Item::TYPE1_PFM==(*next).type))
next++;
}
if(1==itsUrls.count() || next==itsEnd)
setPage(PAGE_ERROR, errorString(status));
else
{
setPage(PAGE_SKIP, errorString(status));
return;
}
}
}
contineuToNext(cont);
}
}
void CJobRunner::contineuToNext(bool cont)
{
itsActionLabel->startAnimation();
if(cont)
{
if(CMD_INSTALL==itsCmd && Item::TYPE1_FONT==(*itsIt).type)
{
QString currentName((*itsIt).fileName);
++itsIt;
if(itsIt!=itsEnd && (*itsIt).fileName==currentName && (Item::TYPE1_AFM==(*itsIt).type || Item::TYPE1_PFM==(*itsIt).type))
++itsIt;
if(itsIt!=itsEnd && (*itsIt).fileName==currentName && (Item::TYPE1_AFM==(*itsIt).type || Item::TYPE1_PFM==(*itsIt).type))
++itsIt;
}
else
++itsIt;
}
else
{
itsUrls.empty();
itsIt=itsEnd=itsUrls.constEnd();
}
doNext();
}
void CJobRunner::slotButtonClicked(QAbstractButton *button)
{
switch(itsStack->currentIndex())
{
case PAGE_PROGRESS:
if(itsIt!=itsEnd)
itsCancelClicked=true;
break;
case PAGE_SKIP:
setPage(PAGE_PROGRESS);
if (button == itsSkipButton) {
contineuToNext(true);
} else if (button == itsAutoSkipButton) {
itsAutoSkip=true;
contineuToNext(true);
} else {
contineuToNext(false);
}
break;
case PAGE_CANCEL:
if(button == itsButtonBox->button(QDialogButtonBox::Yes))
itsIt=itsEnd;
itsCancelClicked=false;
setPage(PAGE_PROGRESS);
itsActionLabel->startAnimation();
dbusStatus(getpid(), itsLastDBusStatus);
break;
case PAGE_COMPLETE:
if(itsDontShowFinishedMsg)
{
KConfigGroup grp(KSharedConfig::openConfig(KFI_UI_CFG_FILE)->group(CFG_GROUP));
grp.writeEntry(CFG_DONT_SHOW_FINISHED_MSG, itsDontShowFinishedMsg->isChecked());
}
case PAGE_ERROR:
QDialog::accept();
break;
}
}
void CJobRunner::closeEvent(QCloseEvent *e)
{
if(PAGE_COMPLETE!=itsStack->currentIndex())
{
e->ignore();
slotButtonClicked(PAGE_CANCEL==itsStack->currentIndex() ?
itsButtonBox->button(QDialogButtonBox::No) :
itsButtonBox->button(QDialogButtonBox::Cancel));
}
}
void CJobRunner::setPage(int page, const QString &msg)
{
itsStack->setCurrentIndex(page);
switch(page)
{
case PAGE_PROGRESS:
itsButtonBox->setStandardButtons(QDialogButtonBox::Cancel);
itsSkipButton->hide();
itsAutoSkipButton->hide();
break;
case PAGE_SKIP:
itsSkipLabel->setText(i18n("<h3>Error</h3>")+QLatin1String("<p>")+msg+QLatin1String("</p>"));
itsButtonBox->setStandardButtons(QDialogButtonBox::Cancel);
itsSkipButton->show();
itsAutoSkipButton->show();
break;
case PAGE_ERROR:
itsErrorLabel->setText(i18n("<h3>Error</h3>")+QLatin1String("<p>")+msg+QLatin1String("</p>"));
itsButtonBox->setStandardButtons(QDialogButtonBox::Cancel);
itsSkipButton->hide();
itsAutoSkipButton->hide();
break;
case PAGE_CANCEL:
itsButtonBox->setStandardButtons(QDialogButtonBox::Yes|QDialogButtonBox::No);
itsSkipButton->hide();
itsAutoSkipButton->hide();
break;
case PAGE_COMPLETE:
if(!itsDontShowFinishedMsg || itsDontShowFinishedMsg->isChecked()) {
QDialog::accept();
} else {
itsButtonBox->setStandardButtons(QDialogButtonBox::Close);
itsSkipButton->hide();
itsAutoSkipButton->hide();
}
break;
}
}
QString CJobRunner::fileName(const QUrl &url)
{
if(url.isLocalFile())
return url.toLocalFile();
else
{
auto job = KIO::mostLocalUrl(url);
job->exec();
QUrl local = job->mostLocalUrl();
if(local.isLocalFile())
return local.toLocalFile();
else
{
if(!itsTempDir)
{
itsTempDir=new QTemporaryDir(QDir::tempPath() + "/fontinst");
itsTempDir->setAutoRemove(true);
}
QString tempName(itsTempDir->filePath(Misc::getFile(url.path())));
auto job = KIO::file_copy(url, QUrl::fromLocalFile(tempName), -1, KIO::Overwrite);
if (job->exec())
return tempName;
else
return QString();
}
}
}
QString CJobRunner::errorString(int value) const
{
Misc::TFont font(FC::decode(*itsIt));
QString urlStr;
if(CMD_REMOVE_FILE==itsCmd)
urlStr=(*itsIt).fileName;
else if(font.family.isEmpty())
urlStr=(*itsIt).url();
else
urlStr=FC::createName(font.family, font.styleInfo);
switch(value)
{
case constDownloadFailed:
return i18n("Failed to download <i>%1</i>", urlStr);
case FontInst::STATUS_SERVICE_DIED:
return i18n("System backend died. Please try again.<br><i>%1</i>", urlStr);
case FontInst::STATUS_BITMAPS_DISABLED:
return i18n("<i>%1</i> is a bitmap font, and these have been disabled on your system.", urlStr);
case FontInst::STATUS_ALREADY_INSTALLED:
return i18n("<i>%1</i> contains the font <b>%2</b>, which is already installed on your system.", urlStr,
FC::getName(itsCurrentFile));
case FontInst::STATUS_NOT_FONT_FILE:
return i18n("<i>%1</i> is not a font.", urlStr);
case FontInst::STATUS_PARTIAL_DELETE:
return i18n("Could not remove all files associated with <i>%1</i>", urlStr);
case FontInst::STATUS_NO_SYS_CONNECTION:
return i18n("Failed to start the system daemon.<br><i>%1</i>", urlStr);
case KIO::ERR_FILE_ALREADY_EXIST:
{
QString name(Misc::modifyName(Misc::getFile((*itsIt).fileName))),
destFolder(Misc::getDestFolder(folderName(itsDestIsSystem), name));
return i18n("<i>%1</i> already exists.", destFolder+name);
}
case KIO::ERR_DOES_NOT_EXIST:
return i18n("<i>%1</i> does not exist.", urlStr);
case KIO::ERR_WRITE_ACCESS_DENIED:
return i18n("Permission denied.<br><i>%1</i>", urlStr);
case KIO::ERR_UNSUPPORTED_ACTION:
return i18n("Unsupported action.<br><i>%1</i>", urlStr);
case KIO::ERR_CANNOT_AUTHENTICATE:
return i18n("Authentication failed.<br><i>%1</i>", urlStr);
default:
return i18n("Unexpected error while processing: <i>%1</i>", urlStr);
}
}
CJobRunner::Item::Item(const QUrl &u, const QString &n, bool dis)
: QUrl(u), name(n), fileName(Misc::getFile(u.path())), isDisabled(dis)
{
type=Misc::checkExt(fileName, "pfa") || Misc::checkExt(fileName, "pfb")
? TYPE1_FONT
: Misc::checkExt(fileName, "afm")
? TYPE1_AFM
: Misc::checkExt(fileName, "pfm")
? TYPE1_PFM
: OTHER_FONT;
if(OTHER_FONT!=type)
{
int pos(fileName.lastIndexOf('.'));
if(-1!=pos)
fileName.truncate(pos);
}
}
CJobRunner::Item::Item(const QString &file, const QString &family, quint32 style, bool system)
: QUrl(CJobRunner::encode(family, style, system)), fileName(file), type(OTHER_FONT)
{
}
bool CJobRunner::Item::operator<(const Item &o) const
{
int nameComp(fileName.compare(o.fileName));
return nameComp<0 || (0==nameComp && type<o.type);
}
}