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);
+ 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") == QStringLiteral("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(0L)
{
setModal(true);
if(NULL==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);
// itsStatusLabel->setWordWrap(true);
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("Cancel?
Are you sure you wish to cancel?
"), 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=0L;
else
{
page=new QFrame(itsStack);
layout=new QGridLayout(page);
QLabel *finishedLabel=new QLabel(i18n("Finished
"
"Please note that any open applications will need to be "
"restarted in order for any changes to be noticed.
"),
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, SIGNAL(serviceOwnerChanged(QString,QString,QString)), SLOT(dbusServiceOwnerChanged(QString,QString,QString)));
connect(dbus(), SIGNAL(status(int,int)), SLOT(dbusStatus(int,int)));
setMinimumSize(420, 160);
}
CJobRunner::~CJobRunner()
{
delete itsTempDir;
}
void CJobRunner::getAssociatedUrls(const QUrl &url, QList &list, bool afmAndPfm, QWidget *widget)
{
QString ext(url.path());
int dotPos(ext.lastIndexOf('.'));
bool check(false);
if(-1==dotPos) // Hmm, no extension - check anyway...
check=true;
else // Cool, got an extension - see if it is a Type1 font...
{
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", NULL},
*pfm[]={"pfm", "PFM", "Pfm", NULL};
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)
qSort(itsUrls.begin(), itsUrls.end()); // Sort list of fonts so that we have type1 fonts followed by their metrics...
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, SLOT(doNext()));
QTimer::singleShot(constInterfaceCheck, this, SLOT(checkInterface()));
itsActionLabel->startAnimation();
int rv=QDialog::exec();
if(itsTempDir)
{
delete itsTempDir;
itsTempDir=0L;
}
return rv;
}
void CJobRunner::doNext()
{
if(itsIt==itsEnd/* || CMD_UPDATE==itsCmd*/)
{
if(itsModified)
{
// Force reconfig if command was already set to update...
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()) // Failed to download...
dbusStatus(getpid(), constDownloadFailed);
else
{
// Create AFM if this is a PFM, and the previous was not the AFM for this font...
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);
// To 'Move' a disabled font, we first need to enable it. To accomplish this, JobRunner creates a 'fake' entry
// with the filename "--"
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);
// Keep copy of this iterator - so that can check whether AFM should be created.
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();
*/
}
// itsIt will equal itsEnd if user decided to cancel the current op
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 we're installing a Type1 font, and its already installed - then we need to skip past AFM/PFM
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) // Did we error on a pfa/pfb? if so, exclude the afm/pfm...
{
QString currentName((*itsIt).fileName);
++itsIt;
// Skip afm/pfm
if(itsIt!=itsEnd && (*itsIt).fileName==currentName && (Item::TYPE1_AFM==(*itsIt).type || Item::TYPE1_PFM==(*itsIt).type))
++itsIt;
// Skip pfm/afm
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();
// Now continue...
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("Error
")+QLatin1String("")+msg+QLatin1String("
"));
itsButtonBox->setStandardButtons(QDialogButtonBox::Cancel);
itsSkipButton->show();
itsAutoSkipButton->show();
break;
case PAGE_ERROR:
itsErrorLabel->setText(i18n("Error
")+QLatin1String("")+msg+QLatin1String("
"));
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(); // Yipee! no need to download!!
else
{
// Need to do actual download...
if(!itsTempDir)
{
itsTempDir=new QTemporaryDir(QDir::tempPath() + "/fontinst");
itsTempDir->setAutoRemove(true);
}
QString tempName(itsTempDir->path()+QLatin1Char('/')+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 %1", urlStr);
case FontInst::STATUS_SERVICE_DIED:
return i18n("System backend died. Please try again.
%1", urlStr);
case FontInst::STATUS_BITMAPS_DISABLED:
return i18n("%1 is a bitmap font, and these have been disabled on your system.", urlStr);
case FontInst::STATUS_ALREADY_INSTALLED:
return i18n("%1 contains the font %2, which is already installed on your system.", urlStr,
FC::getName(itsCurrentFile));
case FontInst::STATUS_NOT_FONT_FILE:
return i18n("%1 is not a font.", urlStr);
case FontInst::STATUS_PARTIAL_DELETE:
return i18n("Could not remove all files associated with %1", urlStr);
case FontInst::STATUS_NO_SYS_CONNECTION:
return i18n("Failed to start the system daemon.
%1", urlStr);
case KIO::ERR_FILE_ALREADY_EXIST:
{
QString name(Misc::modifyName(Misc::getFile((*itsIt).fileName))),
destFolder(Misc::getDestFolder(folderName(itsDestIsSystem), name));
return i18n("%1 already exists.", destFolder+name);
}
case KIO::ERR_DOES_NOT_EXIST:
return i18n("%1 does not exist.", urlStr);
case KIO::ERR_WRITE_ACCESS_DENIED:
return i18n("Permission denied.
%1", urlStr);
case KIO::ERR_UNSUPPORTED_ACTION:
return i18n("Unsupported action.
%1", urlStr);
case KIO::ERR_COULD_NOT_AUTHENTICATE:
return i18n("Authentication failed.
%1", urlStr);
default:
return i18n("Unexpected error while processing: %1", 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=fileName.left(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
*
* ----
*
* 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 "FontInstInterface.h"
#include "FontinstIface.h"
#include "FontInst.h"
#include
#include
#include
#include "config-fontinst.h"
#include "debug.h"
#define KFI_DBUG qCDebug(KCM_KFONTINST_KIO) << '(' << time(NULL) << ')'
namespace KFI
{
FontInstInterface::FontInstInterface()
: itsInterface(new OrgKdeFontinstInterface(OrgKdeFontinstInterface::staticInterfaceName(),
FONTINST_PATH,
QDBusConnection::sessionBus(), 0L))
, itsActive(false)
{
KFI_DBUG;
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(itsInterface, SIGNAL(status(int,int)), SLOT(status(int,int)));
connect(itsInterface, SIGNAL(fontList(int,QList)), SLOT(fontList(int,QList)));
connect(itsInterface, SIGNAL(fontStat(int,KFI::Family)), SLOT(fontStat(int,KFI::Family)));
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(OrgKdeFontinstInterface::staticInterfaceName()))
- QProcess::startDetached(QLatin1String(KFONTINST_LIB_EXEC_DIR"/fontinst"));
+ QProcess::startDetached(QLatin1String(KFONTINST_LIB_EXEC_DIR"/fontinst"), QStringList());
}
FontInstInterface::~FontInstInterface()
{
KFI_DBUG;
}
int FontInstInterface::install(const QString &file, bool toSystem)
{
KFI_DBUG;
itsInterface->install(file, true, toSystem, getpid(), true);
return waitForResponse();
}
int FontInstInterface::uninstall(const QString &name, bool fromSystem)
{
KFI_DBUG;
itsInterface->uninstall(name, fromSystem, getpid(), true);
return waitForResponse();
}
int FontInstInterface::reconfigure()
{
KFI_DBUG;
itsInterface->reconfigure(getpid(), false);
return waitForResponse();
}
Families FontInstInterface::list(bool system)
{
KFI_DBUG;
Families rv;
itsInterface->list(system ? FontInst::SYS_MASK : FontInst::USR_MASK, getpid());
if(FontInst::STATUS_OK==waitForResponse())
{
rv=itsFamilies;
itsFamilies=Families();
}
return rv;
}
Family FontInstInterface::statFont(const QString &file, bool system)
{
KFI_DBUG;
Family rv;
itsInterface->statFont(file, system ? FontInst::SYS_MASK : FontInst::USR_MASK, getpid());
if(FontInst::STATUS_OK==waitForResponse())
{
rv=*itsFamilies.items.begin();
itsFamilies=Families();
}
return rv;
}
QString FontInstInterface::folderName(bool sys)
{
if(!itsInterface)
return QString();
QDBusPendingReply reply=itsInterface->folderName(sys);
reply.waitForFinished();
return reply.isError() ? QString() : reply.argumentAt<0>();
}
int FontInstInterface::waitForResponse()
{
KFI_DBUG;
itsStatus=FontInst::STATUS_OK;
itsFamilies=Families();
itsActive=true;
itsEventLoop.exec();
KFI_DBUG << "Loop finished";
return itsStatus;
}
void FontInstInterface::dbusServiceOwnerChanged(const QString &name, const QString &from, const QString &to)
{
if(itsActive && to.isEmpty() && !from.isEmpty() && name==QLatin1String(OrgKdeFontinstInterface::staticInterfaceName()))
{
KFI_DBUG << "Service died :-(";
itsStatus=FontInst::STATUS_SERVICE_DIED;
itsEventLoop.quit();
}
}
void FontInstInterface::status(int pid, int value)
{
if(itsActive && pid==getpid())
{
KFI_DBUG << "Status:" << value;
itsStatus=value;
itsEventLoop.quit();
}
}
void FontInstInterface::fontList(int pid, const QList &families)
{
if(itsActive && pid==getpid())
{
KFI_DBUG;
itsFamilies=1==families.count() ? *families.begin() : Families();
itsStatus=1==families.count() ? (int)FontInst::STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST;
itsEventLoop.quit();
}
}
void FontInstInterface::fontStat(int pid, const KFI::Family &font)
{
if(itsActive && pid==getpid())
{
KFI_DBUG;
itsFamilies=Families(font, false);
itsStatus=font.styles().count()>0 ? (int)FontInst::STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST;
itsEventLoop.quit();
}
}
}
diff --git a/kcms/kfontinst/viewpart/FontViewPart.cpp b/kcms/kfontinst/viewpart/FontViewPart.cpp
index c0c64ae5b..488c8d0c4 100644
--- a/kcms/kfontinst/viewpart/FontViewPart.cpp
+++ b/kcms/kfontinst/viewpart/FontViewPart.cpp
@@ -1,578 +1,578 @@
/*
* KFontInst - KDE Font Installer
*
* Copyright 2003-2007 Craig Drummond
*
* ----
*
* 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 "FontViewPart.h"
#include "Misc.h"
#include "KfiConstants.h"
#include "FcEngine.h"
#include "PreviewSelectAction.h"
#include "FontInstInterface.h"
#include "FontInst.h"
#include "config-workspace.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include "config-fontinst.h"
// Enable the following to allow printing of non-installed fonts. Does not seem to work :-(
//#define KFI_PRINT_APP_FONTS
namespace KFI
{
static QString getFamily(const QString &font)
{
int commaPos=font.lastIndexOf(',');
return -1==commaPos ? font : font.left(commaPos);
}
K_PLUGIN_FACTORY(CFontViewPartFactory, registerPlugin();)
K_EXPORT_PLUGIN(CFontViewPartFactory("kfontview"))
CFontViewPart::CFontViewPart(QWidget *parentWidget, QObject *parent, const QList &)
: KParts::ReadOnlyPart(parent),
itsConfig(KSharedConfig::openConfig()),
itsProc(NULL),
itsTempDir(NULL),
itsInterface(new FontInstInterface()),
itsOpening(false)
{
// create browser extension (for printing when embedded into browser)
itsExtension = new BrowserExtension(this);
itsFrame=new QFrame(parentWidget);
QFrame *previewFrame=new QFrame(itsFrame);
QWidget *controls=new QWidget(itsFrame);
// QGroupBox *metaBox=new QGroupBox(i18n("Information:"), controls);
itsFaceWidget=new QWidget(controls);
QBoxLayout *mainLayout=new QBoxLayout(QBoxLayout::TopToBottom, itsFrame);
QBoxLayout *previewLayout=new QBoxLayout(QBoxLayout::LeftToRight, previewFrame),
*controlsLayout=new QBoxLayout(QBoxLayout::LeftToRight, controls),
*faceLayout=new QBoxLayout(QBoxLayout::LeftToRight, itsFaceWidget);
// QBoxLayout *metaLayout=new QBoxLayout(QBoxLayout::LeftToRight, metaBox);
// itsMetaLabel=new QLabel(metaBox);
// itsMetaLabel->setAlignment(Qt::AlignTop);
// metaLayout->addWidget(itsMetaLabel);
previewLayout->setMargin(0);
previewLayout->setSpacing(0);
faceLayout->setMargin(0);
controlsLayout->setMargin(0);
previewLayout->setSpacing(0);
itsFrame->setFrameShape(QFrame::NoFrame);
itsFrame->setFocusPolicy(Qt::ClickFocus);
previewFrame->setFrameShape(QFrame::StyledPanel);
previewFrame->setFrameShadow(QFrame::Sunken);
KAboutData aboutData(KFI_NAME, i18n("FontViewPart"), WORKSPACE_VERSION_STRING);
setComponentData(aboutData);
itsPreview=new CFontPreview(previewFrame);
itsPreview->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
itsFaceLabel=new QLabel(i18n("Show Face:"), itsFaceWidget);
itsFaceSelector=new QSpinBox(itsFaceWidget);
itsFaceSelector->setValue(1);
itsInstallButton=new QPushButton(i18n("Install..."), controls);
itsInstallButton->setEnabled(false);
previewLayout->addWidget(itsPreview);
faceLayout->addWidget(itsFaceLabel);
faceLayout->addWidget(itsFaceSelector);
faceLayout->addItem(new QSpacerItem(faceLayout->spacing(), 0, QSizePolicy::Fixed, QSizePolicy::Fixed));
itsFaceWidget->hide();
itsPreview->engine()->readConfig(*itsConfig);
//controlsLayout->addWidget(metaBox);
//controlsLayout->addStretch(2);
controlsLayout->addWidget(itsFaceWidget);
controlsLayout->addStretch(1);
controlsLayout->addWidget(itsInstallButton);
mainLayout->addWidget(previewFrame);
mainLayout->addWidget(controls);
connect(itsPreview, SIGNAL(status(bool)), SLOT(previewStatus(bool)));
connect(itsInstallButton, SIGNAL(clicked()), SLOT(install()));
connect(itsFaceSelector, SIGNAL(valueChanged(int)), SLOT(showFace(int)));
itsChangeTextAction=actionCollection()->addAction("changeText");
itsChangeTextAction->setIcon(QIcon::fromTheme("edit-rename"));
itsChangeTextAction->setText(i18n("Change Text..."));
connect(itsChangeTextAction, SIGNAL(triggered(bool)), SLOT(changeText()));
CPreviewSelectAction *displayTypeAction=new CPreviewSelectAction(this, CPreviewSelectAction::BlocksAndScripts);
actionCollection()->addAction("displayType", displayTypeAction);
connect(displayTypeAction, SIGNAL(range(QList)),
SLOT(displayType(QList)));
QAction *zoomIn=actionCollection()->addAction(KStandardAction::ZoomIn, itsPreview, SLOT(zoomIn())),
*zoomOut=actionCollection()->addAction(KStandardAction::ZoomOut, itsPreview, SLOT(zoomOut()));
connect(itsPreview, SIGNAL(atMax(bool)), zoomIn, SLOT(setDisabled(bool)));
connect(itsPreview, SIGNAL(atMin(bool)), zoomOut, SLOT(setDisabled(bool)));
setXMLFile("kfontviewpart.rc");
setWidget(itsFrame);
itsExtension->enablePrint(false);
FontInst::registerTypes();
connect(itsInterface, SIGNAL(status(int,int)), SLOT(dbusStatus(int,int)));
connect(itsInterface, SIGNAL(fontStat(int,KFI::Family)), SLOT(fontStat(int,KFI::Family)));
}
CFontViewPart::~CFontViewPart()
{
delete itsTempDir;
itsTempDir=NULL;
delete itsInterface;
itsInterface=NULL;
}
static inline QUrl mostLocalUrl(const QUrl &url, QWidget *widget)
{
auto job = KIO::mostLocalUrl(url);
KJobWidgets::setWindow(job, widget);
job->exec();
return job->mostLocalUrl();
}
bool CFontViewPart::openUrl(const QUrl &url)
{
if (!url.isValid() || !closeUrl())
return false;
// itsMetaLabel->setText(QString());
// itsMetaInfo.clear();
itsFontDetails=FC::decode(url);
if(!itsFontDetails.family.isEmpty() ||
KFI_KIO_FONTS_PROTOCOL==url.scheme() || mostLocalUrl(url, itsFrame).isLocalFile())
{
setUrl(url);
emit started(0);
setLocalFilePath(this->url().path());
bool ret=openFile();
if (ret)
emit completed();
return ret;
}
else
return ReadOnlyPart::openUrl(url);
}
bool CFontViewPart::openFile()
{
// NOTE: Can't do the real open here, as we don't seem to be able to use KIO::NetAccess functions
// during initial start-up. Bug report 111535 indicates that calling "konqueror " crashes.
itsInstallButton->setEnabled(false);
QTimer::singleShot(0, this, SLOT(timeout()));
return true;
}
static inline bool statUrl(const QUrl &url, KIO::UDSEntry *udsEntry)
{
auto job = KIO::stat(url);
job->exec();
if (job->error())
return false;
*udsEntry = job->statResult();
return true;
}
void CFontViewPart::timeout()
{
if(!itsInstallButton)
return;
bool isFonts(KFI_KIO_FONTS_PROTOCOL==url().scheme()),
showFs(false),
package(false);
int fileIndex(-1);
QString fontFile;
// itsMetaUrl=url();
delete itsTempDir;
itsTempDir=NULL;
itsOpening=true;
if(!itsFontDetails.family.isEmpty())
{
emit setWindowCaption(FC::createName(itsFontDetails.family, itsFontDetails.styleInfo));
fontFile=FC::getFile(url());
fileIndex=FC::getIndex(url());
}
else if(isFonts)
{
KIO::UDSEntry udsEntry;
bool found = statUrl(url(), &udsEntry);
if(!found)
{
// Check if url is "fonts:/ if so try fonts:/System/, then fonts:/Personal
QStringList pathList(url().adjusted(QUrl::StripTrailingSlash).path().split('/', QString::SkipEmptyParts));
if(pathList.count()==1)
{
found = statUrl(QUrl(QString("fonts:/"+i18n(KFI_KIO_FONTS_SYS)+'/'+pathList[0])), &udsEntry);
if (!found)
found = statUrl(QUrl(QString("fonts:/"+i18n(KFI_KIO_FONTS_USER)+'/'+pathList[0])), &udsEntry);
}
}
if(found)
{
if(udsEntry.numberValue(KIO::UDSEntry::UDS_HIDDEN, 0))
{
fontFile=udsEntry.stringValue(UDS_EXTRA_FILE_NAME);
fileIndex=udsEntry.numberValue(UDS_EXTRA_FILE_FACE, 0);
}
itsFontDetails.family=getFamily(udsEntry.stringValue(KIO::UDSEntry::UDS_NAME));
itsFontDetails.styleInfo=udsEntry.numberValue(UDS_EXTRA_FC_STYLE);
emit setWindowCaption(udsEntry.stringValue(KIO::UDSEntry::UDS_NAME));
}
else
{
previewStatus(false);
return;
}
}
else
{
QString path(localFilePath());
// Is this a application/vnd.kde.fontspackage file? If so, extract 1 scalable font...
if((package=Misc::isPackage(path)))
{
KZip zip(path);
if(zip.open(QIODevice::ReadOnly))
{
const KArchiveDirectory *zipDir=zip.directory();
if(zipDir)
{
QStringList fonts(zipDir->entries());
if(fonts.count())
{
QStringList::ConstIterator it(fonts.begin()),
end(fonts.end());
for(; it!=end; ++it)
{
const KArchiveEntry *entry=zipDir->entry(*it);
if(entry && entry->isFile())
{
delete itsTempDir;
itsTempDir=new QTemporaryDir(QDir::tempPath() + "/" KFI_TMP_DIR_PREFIX);
itsTempDir->setAutoRemove(true);
((KArchiveFile *)entry)->copyTo(itsTempDir->path());
QMimeDatabase db;
QString mime(db.mimeTypeForFile(itsTempDir->path()+QLatin1Char('/')+entry->name()).name());
if(mime=="application/x-font-ttf" || mime=="application/x-font-otf" ||
mime=="application/x-font-type1")
{
fontFile=itsTempDir->path()+QLatin1Char('/')+entry->name();
//setLocalFilePath(itsTempDir->path()+QLatin1Char('/')+entry->name());
// itsMetaUrl=QUrl::fromLocalFile(localFilePath());
break;
}
else
::unlink(QFile::encodeName(itsTempDir->path()+QLatin1Char('/')+entry->name()).data());
}
}
}
}
}
}
}
itsInstallButton->setEnabled(false);
if(itsFontDetails.family.isEmpty())
emit setWindowCaption(url().toDisplayString());
else
FcInitReinitialize();
itsPreview->showFont(!package && itsFontDetails.family.isEmpty()
? localFilePath()
: fontFile.isEmpty()
? itsFontDetails.family
: fontFile,
itsFontDetails.styleInfo, fileIndex);
if(!isFonts && itsPreview->engine()->getNumIndexes()>1)
{
showFs=true;
itsFaceSelector->setRange(1, itsPreview->engine()->getNumIndexes());
itsFaceSelector->setSingleStep(1);
itsFaceSelector->blockSignals(true);
itsFaceSelector->setValue(1);
itsFaceSelector->blockSignals(false);
}
itsFaceWidget->setVisible(showFs);
}
void CFontViewPart::previewStatus(bool st)
{
if(itsOpening)
{
bool printable(false);
if(st)
{
checkInstallable();
if(Misc::app(KFI_PRINTER).isEmpty())
printable=false;
if(KFI_KIO_FONTS_PROTOCOL==url().scheme())
printable=!Misc::isHidden(url());
else if(!FC::decode(url()).family.isEmpty())
printable=!Misc::isHidden(FC::getFile(url()));
#ifdef KFI_PRINT_APP_FONTS
else
{
// TODO: Make this work! Plus, printing of disabled TTF/OTF's should also be possible!
KMimeType::Ptr mime=KMimeType::findByUrl(QUrl::fromLocalFile(localFilePath()), 0, false, true);
printable=mime->is("application/x-font-ttf") || mime->is("application/x-font-otf");
}
#endif
}
itsExtension->enablePrint(st && printable);
itsOpening=false;
}
itsChangeTextAction->setEnabled(st);
// if(st)
// getMetaInfo(itsFaceSelector->isVisible() && itsFaceSelector->value()>0
// ? itsFaceSelector->value()-1 : 0);
// else
if(!st)
KMessageBox::error(itsFrame, i18n("Could not read font."));
}
void CFontViewPart::install()
{
if(!itsProc || QProcess::NotRunning==itsProc->state())
{
QStringList args;
if(!itsProc)
itsProc=new QProcess(this);
else
itsProc->kill();
QString title = QGuiApplication::applicationDisplayName();
if (title.isEmpty())
title = QCoreApplication::applicationName();
args << "--embed" << QString().sprintf("0x%x", (unsigned int)(itsFrame->window()->winId()))
<< "--qwindowtitle" << title
<< "--qwindowicon" << "kfontview"
<< url().toDisplayString();
connect(itsProc, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(installlStatus()));
itsProc->start(Misc::app(KFI_INSTALLER), args);
itsInstallButton->setEnabled(false);
}
}
void CFontViewPart::installlStatus()
{
checkInstallable();
}
void CFontViewPart::dbusStatus(int pid, int status)
{
if(pid==getpid() && FontInst::STATUS_OK!=status)
itsInstallButton->setEnabled(false);
}
void CFontViewPart::fontStat(int pid, const KFI::Family &font)
{
if(pid==getpid())
itsInstallButton->setEnabled(!Misc::app(KFI_INSTALLER).isEmpty() && font.styles().count()==0);
}
void CFontViewPart::changeText()
{
bool status;
QString oldStr(itsPreview->engine()->getPreviewString()),
newStr(QInputDialog::getText(itsFrame, i18n("Preview String"),
i18n("Please enter new string:"),
QLineEdit::Normal,
oldStr, &status));
if(status && newStr!=oldStr)
{
itsPreview->engine()->setPreviewString(newStr);
itsPreview->engine()->writeConfig(*itsConfig);
itsPreview->showFont();
}
}
void CFontViewPart::print()
{
QStringList args;
QString title = QGuiApplication::applicationDisplayName();
if (title.isEmpty())
title = QCoreApplication::applicationName();
if(!itsFontDetails.family.isEmpty())
{
args << "--embed" << QString().sprintf("0x%x", (unsigned int)(itsFrame->window()->winId()))
<< "--qwindowtitle" << title
<< "--qwindowicon" << "kfontview"
<< "--size" << "0"
<< "--pfont" << QString(itsFontDetails.family+','+QString().setNum(itsFontDetails.styleInfo));
}
#ifdef KFI_PRINT_APP_FONTS
else
args << "--embed" << QString().sprintf("0x%x", (unsigned int)(itsFrame->window()->winId()))
<< "--qwindowtitle" << title
<< "--qwindowicon" << "kfontview"
<< "--size " << "0"
<< localFilePath()
<< QString().setNum(KFI_NO_STYLE_INFO);
#endif
if(args.count())
QProcess::startDetached(Misc::app(KFI_PRINTER), args);
}
void CFontViewPart::displayType(const QList &range)
{
itsPreview->setUnicodeRange(range);
itsChangeTextAction->setEnabled(0==range.count());
}
void CFontViewPart::showFace(int face)
{
itsPreview->showFace(face-1);
}
void CFontViewPart::checkInstallable()
{
if(itsFontDetails.family.isEmpty())
{
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(OrgKdeFontinstInterface::staticInterfaceName()))
- QProcess::startDetached(QLatin1String(KFONTINST_LIB_EXEC_DIR"/fontinst"));
+ QProcess::startDetached(QLatin1String(KFONTINST_LIB_EXEC_DIR"/fontinst"), QStringList());
itsInstallButton->setEnabled(false);
itsInterface->statFont(itsPreview->engine()->descriptiveName(), FontInst::SYS_MASK|FontInst::USR_MASK, getpid());
}
}
#if 0
void CFontViewPart::getMetaInfo(int face)
{
if(itsMetaInfo[face].isEmpty())
{
// Pass as much inofmration as possible to analyzer...
if(KFI_KIO_FONTS_PROTOCOL!=itsMetaUrl.protocol())
{
itsMetaUrl.removeQueryItem(KFI_KIO_FACE);
if(face>0)
itsMetaUrl.addQueryItem(KFI_KIO_FACE, QString().setNum(face));
}
KFileMetaInfo meta(itsMetaUrl);
if(meta.isValid() && meta.keys().count())
{
QStringList keys(meta.keys());
QStringList::const_iterator it(keys.begin()),
end(keys.end());
itsMetaInfo[face]="";
for(; it!=end; ++it)
{
KFileMetaInfoItem mi(meta.item(*it));
itsMetaInfo[face]+=""+mi.name()+" |
"+
mi.value().toString()+" |
";
}
itsMetaInfo[face]+="
";
itsMetaLabel->setText(itsMetaInfo[face]);
}
else
itsMetaLabel->setText(i18n("No information
"));
}
else
itsMetaLabel->setText(itsMetaInfo[face]);
}
#endif
BrowserExtension::BrowserExtension(CFontViewPart *parent)
: KParts::BrowserExtension(parent)
{
setURLDropHandlingEnabled(true);
}
void BrowserExtension::enablePrint(bool enable)
{
if(enable!=isActionEnabled("print") && (!enable || !Misc::app(KFI_PRINTER).isEmpty()))
emit enableAction("print", enable);
}
void BrowserExtension::print()
{
if(!Misc::app(KFI_PRINTER).isEmpty())
static_cast(parent())->print();
}
}
#include "FontViewPart.moc"