2 * KFontInst - KDE Font Installer
4 * Copyright 2003-2007 Craig Drummond <craig@kde.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
24 #include "FontViewPart.h"
26 #include "KfiConstants.h"
28 #include "PreviewSelectAction.h"
29 #include <QtGui/QGridLayout>
30 #include <QtGui/QBoxLayout>
31 #include <QtGui/QPushButton>
32 #include <QtGui/QFrame>
33 #include <QtCore/QFile>
34 #include <QtGui/QLabel>
35 #include <QtGui/QValidator>
36 #include <QtCore/QRegExp>
37 #include <QtCore/QTimer>
38 #include <QtGui/QApplication>
39 #include <QtGui/QGroupBox>
40 #include <QtCore/QProcess>
41 #include <KDE/KLocale>
42 #include <KDE/KIO/NetAccess>
43 #include <KDE/KIO/Job>
44 #include <KDE/KIO/JobUiDelegate>
45 #include <KDE/KGlobal>
46 #include <KDE/KActionCollection>
47 #include <KDE/KComponentData>
48 #include <KDE/KMessageBox>
49 #include <KDE/KIntNumInput>
50 #include <KDE/KInputDialog>
51 #include <KDE/KDialog>
53 #include <KDE/KMimeType>
54 //#include <KDE/KFileMetaInfo>
56 #include <KDE/KTempDir>
57 #include <KDE/KStandardDirs>
58 #include <KDE/KPluginFactory>
59 #include <KDE/KPluginLoader>
60 #include <KDE/KStandardAction>
61 #include <fontconfig/fontconfig.h>
63 // Enable the following to allow printing of non-installed fonts. Does not seem to work :-(
64 //#define KFI_PRINT_APP_FONTS
69 K_PLUGIN_FACTORY(CFontViewPartFactory
, registerPlugin
<CFontViewPart
>();)
70 K_EXPORT_PLUGIN(CFontViewPartFactory("kfontview"))
72 CFontViewPart::CFontViewPart(QWidget
*parentWidget
, QObject
*parent
, const QList
<QVariant
> &)
73 : KParts::ReadOnlyPart(parent
),
74 itsConfig(KGlobal::config()),
78 // create browser extension (for printing when embedded into browser)
79 itsExtension
= new BrowserExtension(this);
81 itsFrame
=new QFrame(parentWidget
);
83 QFrame
*previewFrame
=new QFrame(itsFrame
);
84 QWidget
*controls
=new QWidget(itsFrame
);
85 // QGroupBox *metaBox=new QGroupBox(i18n("Information:"), controls);
87 itsFaceWidget
=new QWidget(controls
);
89 QBoxLayout
*mainLayout
=new QBoxLayout(QBoxLayout::TopToBottom
, itsFrame
);
91 mainLayout
->setMargin(KDialog::marginHint());
92 mainLayout
->setSpacing(KDialog::spacingHint());
94 QBoxLayout
*previewLayout
=new QBoxLayout(QBoxLayout::LeftToRight
, previewFrame
),
95 *controlsLayout
=new QBoxLayout(QBoxLayout::LeftToRight
, controls
),
96 *faceLayout
=new QBoxLayout(QBoxLayout::LeftToRight
, itsFaceWidget
);
97 // QBoxLayout *metaLayout=new QBoxLayout(QBoxLayout::LeftToRight, metaBox);
99 // itsMetaLabel=new QLabel(metaBox);
100 // itsMetaLabel->setAlignment(Qt::AlignTop);
101 // metaLayout->addWidget(itsMetaLabel);
102 previewLayout
->setMargin(0);
103 previewLayout
->setSpacing(0);
104 faceLayout
->setMargin(0);
105 faceLayout
->setSpacing(KDialog::spacingHint());
106 controlsLayout
->setMargin(0);
107 previewLayout
->setSpacing(0);
109 itsFrame
->setFrameShape(QFrame::NoFrame
);
110 itsFrame
->setFocusPolicy(Qt::ClickFocus
);
111 previewFrame
->setFrameShape(QFrame::StyledPanel
);
112 previewFrame
->setFrameShadow(QFrame::Sunken
);
113 setComponentData(KComponentData(KFI_NAME
));
115 itsPreview
=new CFontPreview(previewFrame
);
116 itsPreview
->setSizePolicy(QSizePolicy::MinimumExpanding
, QSizePolicy::MinimumExpanding
);
117 itsFaceLabel
=new QLabel(i18n("Show Face:"), itsFaceWidget
);
118 itsFaceSelector
=new KIntNumInput(1, itsFaceWidget
);
119 itsFaceSelector
->setSliderEnabled(false);
120 itsInstallButton
=new QPushButton(i18n("Install..."), controls
);
121 itsInstallButton
->setEnabled(false);
122 previewLayout
->addWidget(itsPreview
);
123 faceLayout
->addWidget(itsFaceLabel
);
124 faceLayout
->addWidget(itsFaceSelector
);
125 faceLayout
->addItem(new QSpacerItem(KDialog::spacingHint(), 0, QSizePolicy::Fixed
, QSizePolicy::Fixed
));
126 itsFaceWidget
->hide();
128 itsPreview
->engine()->readConfig(*itsConfig
);
129 CFcEngine::setTextCol(QApplication::palette().color(QPalette::Active
, QPalette::Text
));
130 connect(itsPreview
, SIGNAL(doZoomIn()), SLOT(zoomIn()));
131 connect(itsPreview
, SIGNAL(doZoomOut()), SLOT(zoomOut()));
133 //controlsLayout->addWidget(metaBox);
134 //controlsLayout->addStretch(2);
135 controlsLayout
->addWidget(itsFaceWidget
);
136 controlsLayout
->addStretch(1);
137 controlsLayout
->addWidget(itsInstallButton
);
138 mainLayout
->addWidget(previewFrame
);
139 mainLayout
->addWidget(controls
);
140 connect(itsPreview
, SIGNAL(status(bool)), SLOT(previewStatus(bool)));
141 connect(itsInstallButton
, SIGNAL(clicked()), SLOT(install()));
142 connect(itsFaceSelector
, SIGNAL(valueChanged(int)), SLOT(showFace(int)));
144 itsChangeTextAction
=actionCollection()->addAction("changeText");
145 itsChangeTextAction
->setIcon(KIcon("edit-rename"));
146 itsChangeTextAction
->setText(i18n("Change Text..."));
147 connect(itsChangeTextAction
, SIGNAL(triggered(bool)), SLOT(changeText()));
149 CPreviewSelectAction
*displayTypeAction
=new CPreviewSelectAction(this, CPreviewSelectAction::BlocksAndScripts
);
150 actionCollection()->addAction("displayType", displayTypeAction
);
151 connect(displayTypeAction
, SIGNAL(range(const QList
<CFcEngine::TRange
> &)),
152 SLOT(displayType(const QList
<CFcEngine::TRange
> &)));
154 itsZoomInAction
=actionCollection()->addAction(KStandardAction::ZoomIn
, this, SLOT(zoomIn()));
155 itsZoomOutAction
=actionCollection()->addAction(KStandardAction::ZoomOut
, this, SLOT(zoomOut()));
157 itsZoomInAction
->setEnabled(false);
158 itsZoomOutAction
->setEnabled(false);
160 setXMLFile("kfontviewpart.rc");
162 itsExtension
->enablePrint(false);
165 CFontViewPart::~CFontViewPart()
171 bool CFontViewPart::openUrl(const KUrl
&url
)
173 if (!url
.isValid() || !closeUrl())
176 // itsMetaLabel->setText(QString());
177 // itsMetaInfo.clear();
179 if(KFI_KIO_FONTS_PROTOCOL
==url
.protocol() || KIO::NetAccess::mostLocalUrl(url
, itsFrame
).isLocalFile())
183 setLocalFilePath(this->url().path());
190 return ReadOnlyPart::openUrl(url
);
193 bool CFontViewPart::openFile()
195 // NOTE: Can't do the real open here, as we don't seem to be able to use KIO::NetAccess functions
196 // during initial start-up. Bug report 111535 indicates that calling "konqueror <font>" crashes.
197 itsInstallButton
->setEnabled(false);
198 QTimer::singleShot(0, this, SLOT(timeout()));
202 void CFontViewPart::timeout()
204 if(!itsInstallButton
)
207 bool isFonts(KFI_KIO_FONTS_PROTOCOL
==url().protocol()),
210 KUrl
displayUrl(url()),
214 quint32
styleInfo(KFI_NO_STYLE_INFO
);
222 FcInitReinitialize();
225 // This is a fonts:/Url. Check to see whether we were passed any details in the query...
226 QString path
=url().queryItem(KFI_FILE_QUERY
)/*,
227 mime=url().queryItem(KFI_MIME_QUERY)*/;
229 name
=url().queryItem(KFI_NAME_QUERY
);
230 styleInfo
=Misc::getIntQueryVal(url(), KFI_STYLE_QUERY
, KFI_NO_STYLE_INFO
);
231 fileIndex
=Misc::getIntQueryVal(url(), KFI_KIO_FACE
, -1);
233 if(name
.isEmpty() && path
.isEmpty())
235 // OK, no useable info in the query - stat fonts:/ to get the required info...
236 KIO::UDSEntry udsEntry
;
238 if(KIO::NetAccess::stat(url(), udsEntry
, NULL
))
240 name
=udsEntry
.stringValue(KIO::UDSEntry::UDS_NAME
);
241 styleInfo
=udsEntry
.numberValue(UDS_EXTRA_FC_STYLE
);
242 isDisabled
=udsEntry
.numberValue(KIO::UDSEntry::UDS_HIDDEN
, 0) ? true : false;
243 //mime=udsEntry.stringValue(KIO::UDSEntry::UDS_MIME_TYPE);
246 else if(!path
.isEmpty())
248 // Its a disabled font, so we can get the file name and index from the query...
249 fileUrl
=KUrl::fromPath(path
);
250 name
=url().fileName();
255 displayUrl
.setFileName(name
.replace("%20", " "));
256 displayUrl
.setQuery(QString());
259 // What query to pass to meta info?
260 // if(path.isEmpty())
262 // itsMetaUrl.removeQueryItem(KFI_NAME_QUERY);
263 // itsMetaUrl.addQueryItem(KFI_NAME_QUERY, name);
264 // itsMetaUrl.removeQueryItem(KFI_STYLE_QUERY);
265 // if(KFI_NO_STYLE_INFO!=styleInfo)
266 // itsMetaUrl.addQueryItem(KFI_STYLE_QUERY, QString().setNum(styleInfo));
270 // itsMetaUrl.removeQueryItem(KFI_FILE_QUERY);
271 // itsMetaUrl.addQueryItem(KFI_FILE_QUERY, path);
272 // itsMetaUrl.removeQueryItem(KFI_KIO_FACE);
274 // itsMetaUrl.addQueryItem(KFI_KIO_FACE, QString().setNum(fileIndex));
277 // itsMetaUrl.removeQueryItem(KFI_MIME_QUERY);
278 // itsMetaUrl.addQueryItem(KFI_MIME_QUERY, mime);
282 QString
path(url().path());
284 // Is this a fonts/package file? If so, extract 1 scalable font...
285 if(Misc::isPackage(path
))
289 if(zip
.open(QIODevice::ReadOnly
))
291 const KArchiveDirectory
*zipDir
=zip
.directory();
295 QStringList
fonts(zipDir
->entries());
299 QStringList::ConstIterator
it(fonts
.begin()),
304 const KArchiveEntry
*entry
=zipDir
->entry(*it
);
306 if(entry
&& entry
->isFile())
309 itsTempDir
=new KTempDir(KStandardDirs::locateLocal("tmp", KFI_TMP_DIR_PREFIX
));
310 itsTempDir
->setAutoRemove(true);
312 ((KArchiveFile
*)entry
)->copyTo(itsTempDir
->name());
314 QString
mime(KMimeType::findByPath(itsTempDir
->name()+entry
->name())->name());
316 if(mime
=="application/x-font-ttf" || mime
=="application/x-font-otf" ||
317 mime
=="application/x-font-type1")
319 setLocalFilePath(itsTempDir
->name()+entry
->name());
320 // itsMetaUrl=KUrl::fromPath(localFilePath());
324 ::unlink(QFile::encodeName(itsTempDir
->name()+entry
->name()).data());
333 itsInstallButton
->setEnabled(false);
337 emit
setWindowCaption(Misc::prettyUrl(displayUrl
));
339 if(isFonts
&& -1!=fileIndex
)
340 itsPreview
->showFont(fileUrl
, QString(), styleInfo
, fileIndex
);
342 itsPreview
->showFont(isFonts
? url() : KUrl::fromPath(localFilePath()), isDisabled
? QString() : name
, styleInfo
);
344 if(!isFonts
&& itsPreview
->engine()->getNumIndexes()>1)
347 itsFaceSelector
->setRange(1, itsPreview
->engine()->getNumIndexes(), 1);
348 itsFaceSelector
->blockSignals(true);
349 itsFaceSelector
->setValue(1);
350 itsFaceSelector
->blockSignals(false);
353 itsFaceWidget
->setVisible(showFs
);
356 void CFontViewPart::previewStatus(bool st
)
358 bool printable(false);
361 if(KFI_KIO_FONTS_PROTOCOL
==url().protocol())
362 printable
=!Misc::isHidden(url());
363 #ifdef KFI_PRINT_APP_FONTS
366 // TODO: Make this work! Plus, printing of disabled TTF/OTF's should also be possible!
367 KMimeType::Ptr mime
=KMimeType::findByUrl(KUrl::fromPath(localFilePath()), 0, false, true);
369 printable
=mime
->is("application/x-font-ttf") || mime
->is("application/x-font-otf");
373 itsChangeTextAction
->setEnabled(st
);
374 itsExtension
->enablePrint(st
&& printable
);
375 itsZoomInAction
->setEnabled(st
&& !itsPreview
->engine()->atMax());
376 itsZoomOutAction
->setEnabled(st
&& !itsPreview
->engine()->atMin());
379 // getMetaInfo(itsFaceSelector->isVisible() && itsFaceSelector->value()>0
380 // ? itsFaceSelector->value()-1 : 0);
383 KMessageBox::error(itsFrame
, i18n("Could not read font."));
386 void CFontViewPart::install()
388 if(!itsProc
|| QProcess::NotRunning
==itsProc
->state())
393 itsProc
=new QProcess(this);
397 args
<< "--embed" << QString().sprintf("0x%x", (unsigned int)(itsFrame
->window()->winId()))
398 << "--caption" << KGlobal::caption().toUtf8()
399 << "--icon" << "kfontview"
400 << url().prettyUrl();
402 connect(itsProc
, SIGNAL(finished(int, QProcess::ExitStatus
)), SLOT(installlStatus()));
403 itsProc
->start(KFI_INSTALLER
, args
);
404 itsInstallButton
->setEnabled(false);
408 void CFontViewPart::installlStatus()
413 void CFontViewPart::changeText()
416 QRegExpValidator
validator(QRegExp(".*"), 0L);
417 QString
oldStr(itsPreview
->engine()->getPreviewString()),
418 newStr(KInputDialog::getText(i18n("Preview String"),
419 i18n("Please enter new string:"),
420 oldStr
, &status
, itsFrame
, &validator
));
422 if(status
&& newStr
!=oldStr
)
424 itsPreview
->engine()->setPreviewString(newStr
);
425 itsPreview
->engine()->writeConfig(*itsConfig
);
426 itsPreview
->showFont();
430 void CFontViewPart::print()
432 QString
exe(KStandardDirs::findExe(QLatin1String(KFI_PRINTER
), KStandardDirs::installPath("libexec")));
435 KMessageBox::error(itsFrame
, i18n("Failed to locate font printer."));
440 if(KFI_KIO_FONTS_PROTOCOL
==url().protocol())
444 itsPreview
->engine()->getInfo(url(), 0, info
);
446 args
<< "--embed" << QString().sprintf("0x%x", (unsigned int)(itsFrame
->window()->winId()))
447 << "--caption" << KGlobal::caption().toUtf8()
448 << "--icon" << "kfontview"
450 << "--pfont" << QString(info
.family
+','+QString().setNum(info
.styleInfo
));
452 #ifdef KFI_PRINT_APP_FONTS
454 args
<< "--embed" << QString().sprintf("0x%x", (unsigned int)(itsFrame
->window()->winId()))
455 << "--caption" << KGlobal::caption().toUtf8()
456 << "--icon" << "kfontview"
459 << QString().setNum(KFI_NO_STYLE_INFO
);
463 QProcess::startDetached(exe
, args
);
467 void CFontViewPart::displayType(const QList
<CFcEngine::TRange
> &range
)
469 itsPreview
->setUnicodeRange(range
);
470 itsChangeTextAction
->setEnabled(0==range
.count());
473 void CFontViewPart::statResult(KJob
*job
)
475 bool exists
=!job
->error();
477 if(!Misc::root() && !exists
&& !itsStatName
.isEmpty())
479 // OK, file does not exist in fonts:/System, try fonts:/Personal
480 stat(QString(KFI_KIO_FONTS_PROTOCOL
":/")+i18n(KFI_KIO_FONTS_USER
)+QChar('/')+itsStatName
);
481 itsStatName
=QString();
485 itsInstallButton
->setEnabled(!exists
);
488 void CFontViewPart::showFace(int face
)
490 itsPreview
->showFace(face
-1);
493 void CFontViewPart::zoomIn()
495 itsPreview
->zoomIn();
496 itsZoomInAction
->setEnabled(!itsPreview
->engine()->atMax());
497 itsZoomOutAction
->setEnabled(!itsPreview
->engine()->atMin());
500 void CFontViewPart::zoomOut()
502 itsPreview
->zoomOut();
503 itsZoomInAction
->setEnabled(!itsPreview
->engine()->atMax());
504 itsZoomOutAction
->setEnabled(!itsPreview
->engine()->atMin());
508 void CFontViewPart::getMetaInfo(int face
)
510 if(itsMetaInfo
[face
].isEmpty())
512 // Pass as much inofmration as possible to analyzer...
513 if(KFI_KIO_FONTS_PROTOCOL
!=itsMetaUrl
.protocol())
515 itsMetaUrl
.removeQueryItem(KFI_KIO_FACE
);
517 itsMetaUrl
.addQueryItem(KFI_KIO_FACE
, QString().setNum(face
));
520 KFileMetaInfo
meta(itsMetaUrl
);
522 if(meta
.isValid() && meta
.keys().count())
524 QStringList
keys(meta
.keys());
525 QStringList::const_iterator
it(keys
.begin()),
528 itsMetaInfo
[face
]="<table>";
531 KFileMetaInfoItem
mi(meta
.item(*it
));
533 itsMetaInfo
[face
]+="<tr><td><b>"+mi
.name()+"</b></td></tr><tr><td>"+
534 mi
.value().toString()+"</td></tr>";
537 itsMetaInfo
[face
]+="</table>";
538 itsMetaLabel
->setText(itsMetaInfo
[face
]);
541 itsMetaLabel
->setText(i18n("<p>No information</p>"));
544 itsMetaLabel
->setText(itsMetaInfo
[face
]);
548 void CFontViewPart::stat(const QString
&path
)
554 itsStatName
=itsPreview
->engine()->getName(url());
555 statUrl
=Misc::root() ? KUrl(QString(KFI_KIO_FONTS_PROTOCOL
":/")+itsStatName
)
556 : KUrl(QString(KFI_KIO_FONTS_PROTOCOL
":/")+i18n(KFI_KIO_FONTS_SYS
)+QChar('/')+itsStatName
);
561 KIO::StatJob
* job
= KIO::stat(statUrl
, KIO::HideProgressInfo
);
562 job
->ui()->setWindow(itsFrame
->parentWidget());
563 job
->setSide(KIO::StatJob::SourceSide
);
564 connect(job
, SIGNAL(result (KJob
*)), this, SLOT(statResult(KJob
*)));
567 BrowserExtension::BrowserExtension(CFontViewPart
*parent
)
568 : KParts::BrowserExtension(parent
)
570 setURLDropHandlingEnabled(true);
573 void BrowserExtension::enablePrint(bool enable
)
575 if(enable
!=isActionEnabled("print"))
576 emit
enableAction("print", enable
);
579 void BrowserExtension::print()
581 static_cast<CFontViewPart
*>(parent())->print();
586 #include "FontViewPart.moc"