diff --git a/kcms/kfontinst/apps/Installer.cpp b/kcms/kfontinst/apps/Installer.cpp index ddd66954d..8a7c295f3 100644 --- a/kcms/kfontinst/apps/Installer.cpp +++ b/kcms/kfontinst/apps/Installer.cpp @@ -1,160 +1,162 @@ /* * 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 "Installer.h" #include "Misc.h" #include "FontsPackage.h" #include #include #include #include #include #include #include #include #include "JobRunner.h" #include "CreateParent.h" #include "config-workspace.h" namespace KFI { int CInstaller::install(const QSet &urls) { QSet::ConstIterator it(urls.begin()), end(urls.end()); bool sysInstall(false); CJobRunner *jobRunner=new CJobRunner(itsParent); CJobRunner::startDbusService(); if(!Misc::root()) { switch(KMessageBox::questionYesNoCancel(itsParent, i18n("Do you wish to install the font(s) for personal use " "(only available to you), or " "system-wide (available to all users)?"), i18n("Where to Install"), KGuiItem(i18n(KFI_KIO_FONTS_USER)), KGuiItem(i18n(KFI_KIO_FONTS_SYS)))) { case KMessageBox::No: sysInstall=true; break; case KMessageBox::Cancel: return -1; default: break; } } QSet instUrls; for(; it!=end; ++it) { auto job = KIO::mostLocalUrl(*it); job->exec(); QUrl local = job->mostLocalUrl(); bool package(false); if(local.isLocalFile()) { QString localFile(local.toLocalFile()); if(Misc::isPackage(localFile)) { instUrls+=FontsPackage::extract(localFile, &itsTempDir); package=true; } } if(!package) { QList associatedUrls; CJobRunner::getAssociatedUrls(*it, associatedUrls, false, itsParent); instUrls.insert(*it); QList::Iterator aIt(associatedUrls.begin()), aEnd(associatedUrls.end()); for(; aIt!=aEnd; ++aIt) instUrls.insert(*aIt); } } if(!instUrls.isEmpty()) { CJobRunner::ItemList list; QSet::ConstIterator it(instUrls.begin()), end(instUrls.end()); for(; it!=end; ++it) list.append(*it); return jobRunner->exec(CJobRunner::CMD_INSTALL, list, Misc::root() || sysInstall); } else return -1; } CInstaller::~CInstaller() { delete itsTempDir; } } int main(int argc, char **argv) { QApplication app(argc, argv); + app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); + KLocalizedString::setApplicationDomain(KFI_CATALOGUE); KAboutData aboutData("kfontinst", i18n("Font Installer"), WORKSPACE_VERSION_STRING, i18n("Simple font installer"), KAboutLicense::GPL, i18n("(C) Craig Drummond, 2007")); KAboutData::setApplicationData(aboutData); QGuiApplication::setWindowIcon(QIcon::fromTheme("preferences-desktop-font-installer")); QCommandLineParser parser; const QCommandLineOption embedOption(QLatin1String("embed"), i18n("Makes the dialog transient for an X app specified by winid"), QLatin1String("winid")); parser.addOption(embedOption); parser.addPositionalArgument(QLatin1String("[URL]"), i18n("URL to install")); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); QSet urls; foreach (const QString &arg, parser.positionalArguments()) urls.insert(QUrl::fromUserInput(arg, QDir::currentPath())); if (!urls.isEmpty()) { QString opt(parser.value(embedOption)); KFI::CInstaller inst(createParent(opt.size() ? opt.toInt(nullptr, 16) : 0)); return inst.install(urls); } return -1; } diff --git a/kcms/kfontinst/kcmfontinst/16-actions-disablefont.png b/kcms/kfontinst/kcmfontinst/16-actions-font-disable.png similarity index 100% rename from kcms/kfontinst/kcmfontinst/16-actions-disablefont.png rename to kcms/kfontinst/kcmfontinst/16-actions-font-disable.png diff --git a/kcms/kfontinst/kcmfontinst/16-actions-enablefont.png b/kcms/kfontinst/kcmfontinst/16-actions-font-enable.png similarity index 100% rename from kcms/kfontinst/kcmfontinst/16-actions-enablefont.png rename to kcms/kfontinst/kcmfontinst/16-actions-font-enable.png diff --git a/kcms/kfontinst/kcmfontinst/22-actions-disablefont.png b/kcms/kfontinst/kcmfontinst/22-actions-font-disable.png similarity index 100% rename from kcms/kfontinst/kcmfontinst/22-actions-disablefont.png rename to kcms/kfontinst/kcmfontinst/22-actions-font-disable.png diff --git a/kcms/kfontinst/kcmfontinst/22-actions-enablefont.png b/kcms/kfontinst/kcmfontinst/22-actions-font-enable.png similarity index 100% rename from kcms/kfontinst/kcmfontinst/22-actions-enablefont.png rename to kcms/kfontinst/kcmfontinst/22-actions-font-enable.png diff --git a/kcms/kfontinst/kcmfontinst/CMakeLists.txt b/kcms/kfontinst/kcmfontinst/CMakeLists.txt index 96ab28791..8e53ffefc 100644 --- a/kcms/kfontinst/kcmfontinst/CMakeLists.txt +++ b/kcms/kfontinst/kcmfontinst/CMakeLists.txt @@ -1,36 +1,36 @@ set(kcm_fontinst_PART_SRCS ${libkfontinstview_SRCS} ${libkfontinstjobrunner_SRCS} ${libkfontinstdbusiface_SRCS} DuplicatesDialog.cpp FontList.cpp GroupList.cpp KCmFontInst.cpp PrintDialog.cpp FontFilter.cpp FontFilterProxyStyle.cpp FcQuery.cpp PreviewList.cpp) # qt5_add_dbus_interface(kcm_fontinst_PART_SRCS ../dbus/org.kde.fontinst.xml FontinstIface) add_library(kcm_fontinst MODULE ${kcm_fontinst_PART_SRCS}) target_link_libraries(kcm_fontinst KF5::Archive KF5::KCMUtils KF5::IconThemes KF5::KIOCore KF5::KIOWidgets KF5::XmlGui KF5::NewStuff kfontinstui kfontinst ${X11_LIBRARIES} ) install(TARGETS kcm_fontinst DESTINATION ${KDE_INSTALL_PLUGINDIR} ) install( FILES fontinst.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) install( FILES kfontinst.knsrc DESTINATION ${KDE_INSTALL_KNSRCDIR} ) ecm_install_icons( ICONS 16-actions-addfont.png - 16-actions-disablefont.png - 16-actions-enablefont.png + 16-actions-font-disable.png + 16-actions-font-enable.png 16-actions-fontstatus.png 22-actions-addfont.png - 22-actions-disablefont.png - 22-actions-enablefont.png + 22-actions-font-disable.png + 22-actions-font-enable.png 22-actions-fontstatus.png 16-actions-addfont.png DESTINATION ${KDE_INSTALL_DATADIR}/kfontinst/icons THEME hicolor) diff --git a/kcms/kfontinst/kcmfontinst/FontFilter.cpp b/kcms/kfontinst/kcmfontinst/FontFilter.cpp index 7522a4176..407940152 100644 --- a/kcms/kfontinst/kcmfontinst/FontFilter.cpp +++ b/kcms/kfontinst/kcmfontinst/FontFilter.cpp @@ -1,395 +1,373 @@ /* * KFontInst - KDE Font Installer * * Copyright 2003-2007 Craig Drummond + * 2019 Guo Yunhe * * ---- * * 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 "FontFilter.h" #include "FontFilterProxyStyle.h" #include "FontList.h" #include #include #include -#include #include #include #include #include #include #include #include #include #include #include namespace KFI { static const int constArrowPad(5); static void deselectCurrent(QActionGroup *act) { QAction *prev(act->checkedAction()); if(prev) prev->setChecked(false); } static void deselectCurrent(KSelectAction *act) { deselectCurrent(act->selectableActionGroup()); } // FIXME: Go back to using StyleSheets instead of a proxy style // once Qt has been fixed not to mess with widget font when // using StyleSheets class CFontFilterStyle : public CFontFilterProxyStyle { public: CFontFilterStyle(CFontFilter *parent, int ol) : CFontFilterProxyStyle(parent), overlap(ol) {} QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const override; int overlap; }; QRect CFontFilterStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const { if (SE_LineEditContents==element) { QRect rect(style()->subElementRect(SE_LineEditContents, option, widget)); return rect.adjusted(overlap, 0, -overlap, 0); } return CFontFilterProxyStyle::subElementRect(element, option, widget); } struct SortAction { SortAction(QAction *a) : action(a) { } bool operator<(const SortAction &o) const { return action->text().localeAwareCompare(o.action->text())<0; } QAction *action; }; static void sortActions(KSelectAction *group) { if(group->actions().count()>1) { QList actions=group->actions(); QList::ConstIterator it(actions.constBegin()), end(actions.constEnd()); QList sorted; for(; it!=end; ++it) { sorted.append(SortAction(*it)); group->removeAction(*it); } std::sort(sorted.begin(), sorted.end()); QList::ConstIterator s(sorted.constBegin()), sEnd(sorted.constEnd()); for(; s!=sEnd; ++s) group->addAction((*s).action); } } CFontFilter::CFontFilter(QWidget *parent) - : KLineEdit(parent) + : QWidget(parent) { - setClearButtonShown(true); - setTrapReturnKey(true); - - itsMenuButton = new QLabel(this); - itsMenuButton->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); - itsMenuButton->setCursor(Qt::ArrowCursor); - itsMenuButton->setToolTip(i18n("Set Criteria")); - - itsMenu=new QMenu(this); - itsPixmaps[CRIT_FAMILY]=SmallIcon("draw-text"); - itsPixmaps[CRIT_STYLE]=SmallIcon("format-text-bold"); - itsPixmaps[CRIT_FOUNDRY]=SmallIcon("user-identity"); - itsPixmaps[CRIT_FONTCONFIG]=SmallIcon("system-search"); - itsPixmaps[CRIT_FILETYPE]=SmallIcon("preferences-desktop-font-installer"); - itsPixmaps[CRIT_FILENAME]=SmallIcon("application-x-font-type1"); - itsPixmaps[CRIT_LOCATION]=SmallIcon("folder"); - itsPixmaps[CRIT_WS]=SmallIcon("character-set"); + itsIcons[CRIT_FAMILY] = QIcon::fromTheme("draw-text"); + itsTexts[CRIT_FAMILY] = i18n("Family"); + itsIcons[CRIT_STYLE] = QIcon::fromTheme("format-text-bold"); + itsTexts[CRIT_STYLE] = i18n("Style"); + itsIcons[CRIT_FOUNDRY] = QIcon::fromTheme("user-identity"); + itsTexts[CRIT_FOUNDRY] = i18n("Foundry"); + itsIcons[CRIT_FONTCONFIG] = QIcon::fromTheme("system-search"); + itsTexts[CRIT_FONTCONFIG] = i18n("FontConfig Match"); + itsIcons[CRIT_FILETYPE] = QIcon::fromTheme("preferences-desktop-font-installer"); + itsTexts[CRIT_FILETYPE] = i18n("File Type"); + itsIcons[CRIT_FILENAME] = QIcon::fromTheme("application-x-font-type1"); + itsTexts[CRIT_FILENAME] = i18n("File Name"); + itsIcons[CRIT_LOCATION] = QIcon::fromTheme("folder"); + itsTexts[CRIT_LOCATION] = i18n("File Location"); + itsIcons[CRIT_WS] = QIcon::fromTheme("character-set"); + itsTexts[CRIT_WS] = i18n("Writing System"); + + m_layout = new QHBoxLayout(this); + setLayout(m_layout); + m_layout->setContentsMargins(0, 0, 0, 0); + + m_lineEdit = new QLineEdit(this); + m_lineEdit->setClearButtonEnabled(true); + m_layout->addWidget(m_lineEdit); + + m_menuButton = new QPushButton(this); + m_menuButton->setIcon(QIcon::fromTheme("view-filter")); + m_menuButton->setText(i18n("Set Criteria")); + m_layout->addWidget(m_menuButton); + + connect(m_lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(textChanged(const QString &))); + + m_menu=new QMenu(this); + m_menuButton->setMenu(m_menu); itsActionGroup=new QActionGroup(this); - addAction(CRIT_FAMILY, i18n("Family"), true); - addAction(CRIT_STYLE, i18n("Style"), false); + addAction(CRIT_FAMILY, true); + addAction(CRIT_STYLE, false); - KSelectAction *foundryMenu=new KSelectAction(QIcon(itsPixmaps[CRIT_FOUNDRY]), i18n("Foundry"), this); + KSelectAction *foundryMenu=new KSelectAction(itsIcons[CRIT_FOUNDRY], itsTexts[CRIT_FOUNDRY], this); itsActions[CRIT_FOUNDRY]=foundryMenu; - itsMenu->addAction(itsActions[CRIT_FOUNDRY]); + m_menu->addAction(itsActions[CRIT_FOUNDRY]); foundryMenu->setData((int)CRIT_FOUNDRY); foundryMenu->setVisible(false); connect(foundryMenu, SIGNAL(triggered(QString)), SLOT(foundryChanged(QString))); - addAction(CRIT_FONTCONFIG, i18n("FontConfig Match"), false); - - KSelectAction *ftMenu=new KSelectAction(QIcon(itsPixmaps[CRIT_FILETYPE]), i18n("File Type"), this); + addAction(CRIT_FONTCONFIG, false); + + KSelectAction *ftMenu=new KSelectAction(itsIcons[CRIT_FILETYPE], itsTexts[CRIT_FILETYPE], this); itsActions[CRIT_FILETYPE]=ftMenu; - itsMenu->addAction(itsActions[CRIT_FILETYPE]); + m_menu->addAction(itsActions[CRIT_FILETYPE]); ftMenu->setData((int)CRIT_FILETYPE); - + QStringList::ConstIterator it(CFontList::fontMimeTypes.constBegin()), end(CFontList::fontMimeTypes.constEnd()); QMimeDatabase db; for(; it!=end; ++it) if((*it)!="application/vnd.kde.fontspackage") { QMimeType mime = db.mimeTypeForName(*it); - + KToggleAction *act=new KToggleAction(QIcon::fromTheme(mime.iconName()), mime.comment(), this); ftMenu->addAction(act); act->setChecked(false); QStringList mimes; foreach (QString pattern, mime.globPatterns()) mimes.append(pattern.remove(QStringLiteral("*."))); act->setData(mimes); } sortActions(ftMenu); connect(ftMenu, SIGNAL(triggered(QString)), SLOT(ftChanged(QString))); itsCurrentFileTypes.clear(); - addAction(CRIT_FILENAME, i18n("File Name"), false); - addAction(CRIT_LOCATION, i18n("File Location"), false); + addAction(CRIT_FILENAME, false); + addAction(CRIT_LOCATION, false); - KSelectAction *wsMenu=new KSelectAction(QIcon(itsPixmaps[CRIT_WS]), i18n("Writing System"), this); + KSelectAction *wsMenu=new KSelectAction(itsIcons[CRIT_WS], itsTexts[CRIT_WS], this); itsActions[CRIT_WS]=wsMenu; - itsMenu->addAction(itsActions[CRIT_WS]); + m_menu->addAction(itsActions[CRIT_WS]); wsMenu->setData((int)CRIT_WS); itsCurrentWs=QFontDatabase::Any; for(int i=QFontDatabase::Latin; iaddAction(wsAct); wsAct->setChecked(false); wsAct->setData(i); } sortActions(wsMenu); connect(wsMenu, SIGNAL(triggered(QString)), SLOT(wsChanged(QString))); setCriteria(CRIT_FAMILY); - setStyle(new CFontFilterStyle(this, itsMenuButton->width())); + setStyle(new CFontFilterStyle(this, m_menuButton->width())); } void CFontFilter::setFoundries(const QSet ¤tFoundries) { QAction *act(((KSelectAction *)itsActions[CRIT_FOUNDRY])->currentAction()); QString prev(act && act->isChecked() ? act->text() : QString()); bool changed(false); QList prevFoundries(((KSelectAction *)itsActions[CRIT_FOUNDRY])->actions()); QList::ConstIterator fIt(prevFoundries.constBegin()), fEnd(prevFoundries.constEnd()); QSet foundries(currentFoundries); // Determine which of 'foundries' are new ones, and which old ones need to be removed... for(; fIt!=fEnd; ++fIt) { if(foundries.contains((*fIt)->text())) foundries.remove((*fIt)->text()); else { ((KSelectAction *)itsActions[CRIT_FOUNDRY])->removeAction(*fIt); (*fIt)->deleteLater(); changed=true; } } if(!foundries.isEmpty()) { // Add foundries to menu - replacing '&' with '&&', as '&' is taken to be // a shortcut! QSet::ConstIterator it(foundries.begin()), end(foundries.end()); for(; it!=end; ++it) { QString foundry(*it); foundry.replace("&", "&&"); ((KSelectAction *)itsActions[CRIT_FOUNDRY])->addAction(foundry); } changed=true; } if(changed) { sortActions((KSelectAction *)itsActions[CRIT_FOUNDRY]); if(!prev.isEmpty()) { act=((KSelectAction *)itsActions[CRIT_FOUNDRY])->action(prev); if(act) ((KSelectAction *)itsActions[CRIT_FOUNDRY])->setCurrentAction(act); else ((KSelectAction *)itsActions[CRIT_FOUNDRY])->setCurrentItem(0); } - + itsActions[CRIT_FOUNDRY]->setVisible(((KSelectAction *)itsActions[CRIT_FOUNDRY])->actions().count()); } } -QSize CFontFilter::sizeHint() const -{ - return QSize(fontMetrics().width(placeholderText())+56, KLineEdit::sizeHint().height()); -} - void CFontFilter::filterChanged() { QAction *act(itsActionGroup->checkedAction()); if(act) { ECriteria crit((ECriteria)act->data().toInt()); if(itsCurrentCriteria!=crit) { deselectCurrent((KSelectAction *)itsActions[CRIT_FOUNDRY]); deselectCurrent((KSelectAction *)itsActions[CRIT_FILETYPE]); deselectCurrent((KSelectAction *)itsActions[CRIT_WS]); - setText(QString()); + m_lineEdit->setText(QString()); itsCurrentWs=QFontDatabase::Any; itsCurrentFileTypes.clear(); setCriteria(crit); - setPlaceholderText(i18n("Filter by %1...", act->text())); - setReadOnly(false); + m_lineEdit->setPlaceholderText(i18n("Filter by %1...", act->text())); + m_lineEdit->setReadOnly(false); } } } void CFontFilter::ftChanged(const QString &ft) { deselectCurrent((KSelectAction *)itsActions[CRIT_FOUNDRY]); deselectCurrent((KSelectAction *)itsActions[CRIT_WS]); deselectCurrent(itsActionGroup); QAction *act(((KSelectAction *)itsActions[CRIT_FILETYPE])->currentAction()); if(act) itsCurrentFileTypes=act->data().toStringList(); itsCurrentCriteria=CRIT_FILETYPE; - setReadOnly(true); + m_lineEdit->setReadOnly(true); setCriteria(itsCurrentCriteria); - setText(ft); - setPlaceholderText(text()); + m_lineEdit->setText(ft); + m_lineEdit->setPlaceholderText(m_lineEdit->text()); } void CFontFilter::wsChanged(const QString &writingSystemName) { deselectCurrent((KSelectAction *)itsActions[CRIT_FOUNDRY]); deselectCurrent((KSelectAction *)itsActions[CRIT_FILETYPE]); deselectCurrent(itsActionGroup); QAction *act(((KSelectAction *)itsActions[CRIT_WS])->currentAction()); if(act) itsCurrentWs=(QFontDatabase::WritingSystem)act->data().toInt(); itsCurrentCriteria=CRIT_WS; - setReadOnly(true); + m_lineEdit->setReadOnly(true); setCriteria(itsCurrentCriteria); - setText(writingSystemName); - setPlaceholderText(text()); + m_lineEdit->setText(writingSystemName); + m_lineEdit->setPlaceholderText(m_lineEdit->text()); } void CFontFilter::foundryChanged(const QString &foundry) { deselectCurrent((KSelectAction *)itsActions[CRIT_WS]); deselectCurrent((KSelectAction *)itsActions[CRIT_FILETYPE]); deselectCurrent(itsActionGroup); itsCurrentCriteria=CRIT_FOUNDRY; - setReadOnly(true); - setText(foundry); - setPlaceholderText(text()); + m_lineEdit->setReadOnly(true); + m_lineEdit->setText(foundry); + m_lineEdit->setPlaceholderText(m_lineEdit->text()); setCriteria(itsCurrentCriteria); } -void CFontFilter::addAction(ECriteria crit, const QString &text, bool on) +void CFontFilter::textChanged(const QString &text) { - itsActions[crit]=new KToggleAction(QIcon(itsPixmaps[crit]), - text, this); - itsMenu->addAction(itsActions[crit]); + emit queryChanged(text); +} + +void CFontFilter::addAction(ECriteria crit, bool on) +{ + itsActions[crit]=new KToggleAction(itsIcons[crit], itsTexts[crit], this); + m_menu->addAction(itsActions[crit]); itsActionGroup->addAction(itsActions[crit]); itsActions[crit]->setData((int)crit); itsActions[crit]->setChecked(on); if(on) - setPlaceholderText(i18n("Filter by %1...", text)); + m_lineEdit->setPlaceholderText(i18n("Filter by %1...", itsTexts[crit])); connect(itsActions[crit], SIGNAL(toggled(bool)), SLOT(filterChanged())); } -void CFontFilter::resizeEvent(QResizeEvent *ev) -{ - KLineEdit::resizeEvent(ev); - - int frameWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth)), - y((height()-itsMenuButton->height())/2); - - if (qApp->isLeftToRight()) - itsMenuButton->move(frameWidth + 2, y); - else - itsMenuButton->move(size().width() - frameWidth - itsMenuButton->width() - 2, y); -} - -void CFontFilter::mousePressEvent(QMouseEvent *ev) -{ - if(Qt::LeftButton==ev->button() && itsMenuButton->underMouse()) - itsMenu->popup(mapToGlobal(QPoint(0, height())), nullptr); - else - KLineEdit::mousePressEvent(ev); -} - void CFontFilter::setCriteria(ECriteria crit) { - QPixmap arrowmap(itsPixmaps[crit].width()+constArrowPad, itsPixmaps[crit].height()); - - QColor bgnd(palette().color(QPalette::Active, QPalette::Base)); - bgnd.setAlphaF(0.0); - arrowmap.fill(bgnd); - - QPainter p(&arrowmap); - - p.drawPixmap(0, 0, itsPixmaps[crit]); - QStyleOption opt; - opt.state = QStyle::State_Enabled; - opt.rect = QRect(arrowmap.width()-(constArrowPad+1), arrowmap.height()-(constArrowPad+1), constArrowPad, constArrowPad); - style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &opt, &p, itsMenuButton); - p.end(); - - itsMenuButton->setPixmap(arrowmap); - itsMenuButton->resize(arrowmap.width(), arrowmap.height()); itsCurrentCriteria=crit; emit criteriaChanged(crit, ((qulonglong)1) << (int)itsCurrentWs, itsCurrentFileTypes); } } diff --git a/kcms/kfontinst/kcmfontinst/FontFilter.h b/kcms/kfontinst/kcmfontinst/FontFilter.h index 96dfacbc9..764c7bb79 100644 --- a/kcms/kfontinst/kcmfontinst/FontFilter.h +++ b/kcms/kfontinst/kcmfontinst/FontFilter.h @@ -1,97 +1,99 @@ #ifndef __FONT_FILTER_H__ #define __FONT_FILTER_H__ /* * KFontInst - KDE Font Installer * * Copyright 2003-2007 Craig Drummond + * 2019 Guo Yunhe * * ---- * * 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 -#include +#include +#include #include - -class QLabel; -class QMenu; -class QActionGroup; +#include +#include +#include +#include namespace KFI { -class CFontFilter : public KLineEdit +class CFontFilter : public QWidget { Q_OBJECT public: enum ECriteria { CRIT_FAMILY, CRIT_STYLE, CRIT_FOUNDRY, CRIT_FONTCONFIG, CRIT_FILETYPE, CRIT_FILENAME, CRIT_LOCATION, CRIT_WS, NUM_CRIT }; CFontFilter(QWidget *parent); ~CFontFilter() override { } void setFoundries(const QSet ¤tFoundries); - QSize sizeHint() const override; - Q_SIGNALS: void criteriaChanged(int crit, qulonglong ws, const QStringList &ft); + void queryChanged(QString text); private Q_SLOTS: void filterChanged(); + void textChanged(const QString &text); void ftChanged(const QString &ft); void wsChanged(const QString &writingSystemName); void foundryChanged(const QString &foundry); private: - void addAction(ECriteria crit, const QString &text, bool on); - void resizeEvent(QResizeEvent *ev) override; - void mousePressEvent(QMouseEvent *ev) override; + void addAction(ECriteria crit, bool on); void setCriteria(ECriteria crit); private: - QLabel *itsMenuButton; - QMenu *itsMenu; + QPushButton *m_menuButton; + QHBoxLayout *m_layout; + QMenu *m_menu; + QLineEdit *m_lineEdit; ECriteria itsCurrentCriteria; QFontDatabase::WritingSystem itsCurrentWs; QStringList itsCurrentFileTypes; - QPixmap itsPixmaps[NUM_CRIT]; + QIcon itsIcons[NUM_CRIT]; + QString itsTexts[NUM_CRIT]; QAction *itsActions[NUM_CRIT]; QActionGroup *itsActionGroup; }; } #endif diff --git a/kcms/kfontinst/kcmfontinst/FontList.cpp b/kcms/kfontinst/kcmfontinst/FontList.cpp index 45d74aa61..3f5d14dc2 100644 --- a/kcms/kfontinst/kcmfontinst/FontList.cpp +++ b/kcms/kfontinst/kcmfontinst/FontList.cpp @@ -1,2060 +1,2060 @@ /* * 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 "FontList.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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() << "font/ttf" << "font/otf" << "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 *fonts, QSet &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 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 §) { 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(nullptr), itsStatus(ENABLED), itsRealStatus(ENABLED), itsRegularFont(nullptr), 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 nullptr; } void CFamilyItem::getFoundries(QSet &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=nullptr; if(update) updateRegularFont(nullptr); } delete font; } void CFamilyItem::refresh() { updateStatus(); itsRegularFont=nullptr; updateRegularFont(nullptr); } 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(fontDiffstyleInfo()-constRegular)); if(diff)), SLOT(fontList(int,QList))); } 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 &families) { // printf("**** fontList:%d/%d %d\n", pid, getpid(), families.count()); if(pid==getpid()) { QList::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; tlist(FontInst::SYS_MASK|FontInst::USR_MASK, getpid()); } void CFontList::setSlowUpdates(bool slow) { if(itsSlowUpdates!=slow) { if(!slow) for(int i=0; i families; QDataStream ds(&encodedData, QIODevice::WriteOnly); for(; it!=end; ++it) if((*it).isValid()) { if((static_cast((*it).internalPointer()))->isFont()) { CFontItem *font=static_cast((*it).internalPointer()); families.insert(font->family()); } else { CFamilyItem *fam=static_cast((*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"); +// return QIcon::fromTheme("fontstatus"); // break; case Qt::TextAlignmentRole: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); 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(parent.internalPointer()); if(rowfonts().count()) return createIndex(row, column, fam->fonts().at(row)); } else // Family.... if(row(index.internalPointer()); if(mi->isFamily()) return QModelIndex(); else { CFontItem *font=static_cast(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(parent.internalPointer()); if(mi->isFont()) return 0; CFamilyItem *fam=static_cast(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 &enabled, QSet &disabled, QSet &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 &foundries) const { CFamilyItemCont::ConstIterator it(itsFamilies.begin()), end(itsFamilies.end()); for(; it!=end; ++it) (*it)->getFoundries(foundries); } QString CFontList::whatsThis() const { return i18n("

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.

" "
    " "
  • Times [4]" "
    • Regular
    • " "
    • Bold
    • " "
    • Bold Italic
    • " "
    • Italic
    • " "
    " "
  • " "
"); } 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; iconstMaxSlowed) 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 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::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 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::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(nullptr), itsFilterCriteria(CFontFilter::CRIT_FAMILY), itsFilterWs(0), itsFcQuery(nullptr) { 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(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(index.internalPointer()); CFontItemCont::ConstIterator it(fam->fonts().begin()), end(fam->fonts().end()); FileCont allFiles; QString tip(""+fam->name()+""); bool markMatch(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria); tip+="

"; for(; it!=end; ++it) allFiles+=(*it)->files(); //qSort(allFiles); FileCont::ConstIterator fit(allFiles.begin()), fend(allFiles.end()); for(int i=0; fit!=fend && ifile()) tip+=""; else tip+=""; if(allFiles.count()>constMaxFiles) tip+=""; tip+="
"+Misc::contractHome((*fit).path())+"
"+Misc::contractHome((*fit).path())+"
"+i18n("...plus %1 more", allFiles.count()-constMaxFiles)+"

"; return tip; } else { CFontItem *font=static_cast(index.internalPointer()); QString tip(""+font->name()+""); const FileCont &files(font->files()); bool markMatch(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria); tip+="

"; //qSort(files); FileCont::ConstIterator fit(files.begin()), fend(files.end()); for(int i=0; fit!=fend && ifile()) tip+=""; else tip+=""; if(files.count()>constMaxFiles) tip+=""; tip+="
"+Misc::contractHome((*fit).path())+"
"+Misc::contractHome((*fit).path() )+"
"+i18n("...plus %1 more", files.count()-constMaxFiles)+"

"; 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(index.internalPointer()))->isEnabled()) || (mi->isFamily() && CFamilyItem::DISABLED==(static_cast(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(index.internalPointer()); return i18n("%1 [%2]", fam->name(), fam->fontCount()); } else return (static_cast(index.internalPointer()))->style(); } break; case Qt::DecorationRole: if(mi->isFamily()) { CFamilyItem *fam=static_cast(index.internalPointer()); switch(index.column()) { case COL_STATUS: switch(fam->status()) { case CFamilyItem::PARTIAL: - return SmallIcon("dialog-ok", 0, KIconLoader::DisabledState); + return QIcon::fromTheme("dialog-ok"); case CFamilyItem::ENABLED: - return SmallIcon("dialog-ok"); + return QIcon::fromTheme("dialog-ok"); case CFamilyItem::DISABLED: - return SmallIcon("dialog-cancel"); + return QIcon::fromTheme("dialog-cancel"); } break; default: break; } } else if(COL_STATUS==index.column()) - return SmallIcon( (static_cast(index.internalPointer()))->isEnabled() - ? "dialog-ok" : "dialog-cancel", 10); + return QIcon::fromTheme( (static_cast(index.internalPointer()))->isEnabled() + ? "dialog-ok" : "dialog-cancel"); break; case Qt::SizeHintRole: if(mi->isFamily()) { const int s = KIconLoader::global()->currentSize(KIconLoader::Small); return QSize(s, s + 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; } case CFontFilter::CRIT_WS: fontMatch=fnt->writingSystems()&itsFilterWs; 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(index.internalPointer()); if(mi->isFont()) { CFontItem *font=static_cast(index.internalPointer()); return acceptFont(font, !(CFontFilter::CRIT_FAMILY==itsFilterCriteria && matchString(font->family(), itsFilterText))); } else return acceptFamily(static_cast(index.internalPointer())); } return false; } bool CFontListSortFilterProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { if(left.isValid() && right.isValid()) { CFontModelItem *lmi=static_cast(left.internalPointer()), *rmi=static_cast(right.internalPointer()); if(lmi->isFont()isFont()) return true; if(lmi->isFont()) { CFontItem *lfi=static_cast(left.internalPointer()), *rfi=static_cast(right.internalPointer()); if(COL_STATUS==filterKeyColumn()) { if(lfi->isEnabled()isEnabled() || (lfi->isEnabled()==rfi->isEnabled() && lfi->styleInfo()styleInfo())) return true; } else if(lfi->styleInfo()styleInfo()) return true; } else { CFamilyItem *lfi=static_cast(left.internalPointer()), *rfi=static_cast(right.internalPointer()); if(COL_STATUS==filterKeyColumn()) { if(lfi->status()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, qulonglong ws, const QStringList &ft) { if(crit!=itsFilterCriteria || ws!=itsFilterWs || ft!=itsFilterTypes) { itsFilterWs=ws; 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.truncate(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(QIcon::fromTheme("edit-delete"), i18n("Delete"), this, SIGNAL(del())); itsMenu->addSeparator(); - itsEnableAct=itsMenu->addAction(QIcon::fromTheme("enablefont"), i18n("Enable"), + itsEnableAct=itsMenu->addAction(QIcon::fromTheme("font-enable"), i18n("Enable"), this, SIGNAL(enable())); - itsDisableAct=itsMenu->addAction(QIcon::fromTheme("disablefont"), i18n("Disable"), + itsDisableAct=itsMenu->addAction(QIcon::fromTheme("font-disable"), i18n("Disable"), this, SIGNAL(disable())); if(!Misc::app(KFI_VIEWER).isEmpty()) itsMenu->addSeparator(); itsPrintAct=Misc::app(KFI_VIEWER).isEmpty() ? nullptr : itsMenu->addAction(QIcon::fromTheme("document-print"), i18n("Print..."), this, SIGNAL(print())); itsViewAct=Misc::app(KFI_VIEWER).isEmpty() ? nullptr : itsMenu->addAction(QIcon::fromTheme("kfontview"), i18n("Open in Font Viewer"), this, SLOT(view())); itsMenu->addSeparator(); itsMenu->addAction(QIcon::fromTheme("view-refresh"), i18n("Reload"), model, SLOT(load())); } void CFontListView::getFonts(CJobRunner::ItemList &urls, QStringList &fontNames, QSet *fonts, bool selected, bool getEnabled, bool getDisabled) { QModelIndexList selectedItems(selected ? selectedIndexes() : allIndexes()); QSet usedFonts; QModelIndex index; foreach(index, selectedItems) if(index.isValid()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font=static_cast(realIndex.internalPointer()); addFont(font, urls, fontNames, fonts, usedFonts, getEnabled, getDisabled); } else { CFamilyItem *fam=static_cast(realIndex.internalPointer()); for(int ch=0; chfontCount(); ++ch) { QModelIndex child(itsProxy->mapToSource(index.child(ch, 0))); if(child.isValid() && (static_cast(child.internalPointer()))->isFont()) { CFontItem *font=static_cast(child.internalPointer()); addFont(font, urls, fontNames, fonts, usedFonts, getEnabled, getDisabled); } } } } } fontNames=CFontList::compact(fontNames); } QSet CFontListView::getFiles() { QModelIndexList items(allIndexes()); QModelIndex index; QSet files; foreach(index, items) if(index.isValid()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font=static_cast(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 &items, bool selected) { QModelIndexList selectedItems(selected ? selectedIndexes() : allIndexes()); QModelIndex index; foreach(index, selectedItems) { CFontItem *font=nullptr; if(index.isValid() && 0==index.column()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) font=static_cast(realIndex.internalPointer()); else { CFamilyItem *fam=static_cast(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, qulonglong ws, const QStringList &ft) { itsProxy->setFilterCriteria((CFontFilter::ECriteria)crit, ws, ft); } void CFontListView::stats(int &enabled, int &disabled, int &partial) { enabled=disabled=partial=0; for(int i=0; irowCount(); ++i) { QModelIndex idx(itsProxy->index(i, 0, QModelIndex())); if(!idx.isValid()) break; QModelIndex sourceIdx(itsProxy->mapToSource(idx)); if(!sourceIdx.isValid()) break; if((static_cast(sourceIdx.internalPointer()))->isFamily()) switch((static_cast(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()); QModelIndex index; enabled=disabled=false; foreach(index, selected) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFamily()) { switch((static_cast(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(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; iindex(i, 0, QModelIndex())); int childRowCount(itsProxy->rowCount(idx)); for(int j=0; jindex(j, 0, idx)); if(child.isValid()) rv.append(itsProxy->mapToSource(child)); } } return rv; } void CFontListView::selectFirstFont() { if(0==selectedIndexes().count()) for(int i=0; iindex(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 through current selection, and for any 'font' items that are selected, // ensure 'family' item is not... QModelIndexList selectedItems(selectedIndexes()), deselectList; QModelIndex index; QSet selectedFamilies; bool en(false), dis(false); foreach(index, selectedItems) if(index.isValid()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font=static_cast(realIndex.internalPointer()); if(font->isEnabled()) en=true; else dis=true; if(!selectedFamilies.contains(font->parent())) { selectedFamilies.insert(font->parent()); for(int i=0; imapFromSource( itsModel->createIndex(font->parent()->rowNumber(), i, font->parent()))); } } else { switch((static_cast(realIndex.internalPointer()))->status()) { case CFamilyItem::ENABLED: en=true; break; case CFamilyItem::DISABLED: dis=true; break; case CFamilyItem::PARTIAL: en=dis=true; break; } } } } if(deselectList.count()) foreach(index, deselectList) selectionModel()->select(index, QItemSelectionModel::Deselect); QModelIndexList sel; QSet pointers; selectedItems=selectedIndexes(); foreach(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(index.internalPointer()))->isFamily()) { CFamilyItem *fam=static_cast(index.internalPointer()); CFontItemCont::ConstIterator it(fam->fonts().begin()), end(fam->fonts().end()); for(; it!=end; ++it) for(int i=0; iselect(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()); QModelIndex index; QSet fonts; foreach(index, selectedItems) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font(static_cast(realIndex.internalPointer())); fonts.insert(font); } else { CFontItem *font((static_cast(realIndex.internalPointer()))->regularFont()); if(font) fonts.insert(font); } } } if(fonts.count() && (fonts.count()::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; iindex(i, 0, QModelIndex())); int childRowCount(itsProxy->rowCount(idx)); rv.append(idx); for(int j=0; jindex(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(index.internalPointer()))->isFont() ? static_cast(index.internalPointer()) : (static_cast(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("text/uri-list")) // "application/x-kde-urilist" ?? event->acceptProposedAction(); } void CFontListView::dropEvent(QDropEvent *event) { if(itsAllowDrops && event->mimeData()->hasFormat("text/uri-list")) { event->acceptProposedAction(); QList urls(event->mimeData()->urls()); QList::ConstIterator it(urls.begin()), end(urls.end()); QSet kurls; QMimeDatabase db; for (; it!=end; ++it) { QMimeType mime = db.mimeTypeForUrl(*it); foreach (const QString &fontMime, CFontList::fontMimeTypes) { if (mime.inherits(fontMime)) { kurls.insert(*it); break; } } } if(!kurls.isEmpty()) 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()); QModelIndex index; foreach(index, selectedItems) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { if((static_cast(realIndex.internalPointer())->isEnabled())) en=true; else dis=true; } else { switch((static_cast(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); } } diff --git a/kcms/kfontinst/kcmfontinst/GroupList.cpp b/kcms/kfontinst/kcmfontinst/GroupList.cpp index e1f6442aa..1e201fc83 100644 --- a/kcms/kfontinst/kcmfontinst/GroupList.cpp +++ b/kcms/kfontinst/kcmfontinst/GroupList.cpp @@ -1,1026 +1,1026 @@ /* * 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 "GroupList.h" #include "FontList.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FcEngine.h" #include "Misc.h" #include "KfiConstants.h" namespace KFI { #define GROUPS_DOC "groups" #define GROUP_TAG "group" #define NAME_ATTR "name" #define FAMILY_TAG "family" enum EGroupColumns { COL_GROUP_NAME, NUM_GROUP_COLS }; CGroupListItem::CGroupListItem(const QString &name) : itsName(name), itsType(CUSTOM), itsHighlighted(false), itsStatus(CFamilyItem::ENABLED) { itsData.validated=false; } CGroupListItem::CGroupListItem(EType type, CGroupList *p) : itsType(type), itsHighlighted(false), itsStatus(CFamilyItem::ENABLED) { switch(itsType) { case ALL: itsName=i18n("All Fonts"); break; case PERSONAL: itsName=i18n("Personal Fonts"); break; case SYSTEM: itsName=i18n("System Fonts"); break; default: itsName=i18n("Unclassified"); } itsData.parent=p; } bool CGroupListItem::hasFont(const CFontItem *fnt) const { switch(itsType) { case CUSTOM: return itsFamilies.contains(fnt->family()); case PERSONAL: return !fnt->isSystem(); case SYSTEM: return fnt->isSystem(); case ALL: return true; case UNCLASSIFIED: { QList::ConstIterator it(itsData.parent->itsGroups.begin()), end(itsData.parent->itsGroups.end()); for(; it!=end; ++it) if((*it)->isCustom() && (*it)->families().contains(fnt->family())) return false; return true; } default: return false; } return false; } void CGroupListItem::updateStatus(QSet &enabled, QSet &disabled, QSet &partial) { QSet families(itsFamilies); if(0!=families.intersect(partial).count()) itsStatus=CFamilyItem::PARTIAL; else { families=itsFamilies; bool haveEnabled(0!=families.intersect(enabled).count()); families=itsFamilies; bool haveDisabled(0!=families.intersect(disabled).count()); if(haveEnabled && haveDisabled) itsStatus=CFamilyItem::PARTIAL; else if(haveEnabled && !haveDisabled) itsStatus=CFamilyItem::ENABLED; else itsStatus=CFamilyItem::DISABLED; } } bool CGroupListItem::load(QDomElement &elem) { if(elem.hasAttribute(NAME_ATTR)) { itsName=elem.attribute(NAME_ATTR); addFamilies(elem); return true; } return false; } bool CGroupListItem::addFamilies(QDomElement &elem) { int b4(itsFamilies.count()); for(QDomNode n=elem.firstChild(); !n.isNull(); n=n.nextSibling()) { QDomElement ent=n.toElement(); if(FAMILY_TAG==ent.tagName()) itsFamilies.insert(ent.text()); } return b4!=itsFamilies.count(); } void CGroupListItem::save(QTextStream &str) { str << " <" GROUP_TAG " " NAME_ATTR "=\"" << Misc::encodeText(itsName, str) << "\">" << endl; if(!itsFamilies.isEmpty()) { QSet::ConstIterator it(itsFamilies.begin()), end(itsFamilies.end()); for(; it!=end; ++it) str << " <" FAMILY_TAG ">" << Misc::encodeText(*it, str) << "" << endl; } str << " " << endl; } CGroupList::CGroupList(QWidget *parent) : QAbstractItemModel(parent), itsTimeStamp(0), itsModified(false), itsParent(parent), itsSortOrder(Qt::AscendingOrder) { itsSpecialGroups[CGroupListItem::ALL]=new CGroupListItem(CGroupListItem::ALL, this); itsGroups.append(itsSpecialGroups[CGroupListItem::ALL]); if(Misc::root()) itsSpecialGroups[CGroupListItem::PERSONAL]= itsSpecialGroups[CGroupListItem::SYSTEM]=NULL; else { itsSpecialGroups[CGroupListItem::PERSONAL]=new CGroupListItem(CGroupListItem::PERSONAL, this); itsGroups.append(itsSpecialGroups[CGroupListItem::PERSONAL]); itsSpecialGroups[CGroupListItem::SYSTEM]=new CGroupListItem(CGroupListItem::SYSTEM, this); itsGroups.append(itsSpecialGroups[CGroupListItem::SYSTEM]); } itsSpecialGroups[CGroupListItem::UNCLASSIFIED]= new CGroupListItem(CGroupListItem::UNCLASSIFIED, this); // Locate groups.xml file - normall will be ~/.config/fontgroups.xml QString path(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + '/'); if(!Misc::dExists(path)) Misc::createDir(path); itsFileName=path+'/'+KFI_GROUPS_FILE; rescan(); } CGroupList::~CGroupList() { save(); qDeleteAll(itsGroups); itsGroups.clear(); } int CGroupList::columnCount(const QModelIndex &) const { return NUM_GROUP_COLS; } void CGroupList::update(const QModelIndex &unHighlight, const QModelIndex &highlight) { if(unHighlight.isValid()) { CGroupListItem *grp=static_cast(unHighlight.internalPointer()); if(grp) grp->setHighlighted(false); emit dataChanged(unHighlight, unHighlight); } if(highlight.isValid()) { CGroupListItem *grp=static_cast(highlight.internalPointer()); if(grp) grp->setHighlighted(true); emit dataChanged(highlight, highlight); } } void CGroupList::updateStatus(QSet &enabled, QSet &disabled, QSet &partial) { QList::Iterator it(itsGroups.begin()), end(itsGroups.end()); for(; it!=end; ++it) if((*it)->isCustom()) (*it)->updateStatus(enabled, disabled, partial); emit layoutChanged(); } inline QColor midColour(const QColor &a, const QColor &b) { return QColor((a.red()+b.red())>>1, (a.green()+b.green())>>1, (a.blue()+b.blue())>>1); } QVariant CGroupList::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); CGroupListItem *grp=static_cast(index.internalPointer()); if(grp) switch(index.column()) { case COL_GROUP_NAME: switch(role) { case Qt::FontRole: if(CGroupListItem::SYSTEM==grp->type()) { QFont font; font.setItalic(true); return font; } break; case Qt::SizeHintRole: { const int s = KIconLoader::global()->currentSize(KIconLoader::Small); return QSize(s, s + 4); } case Qt::EditRole: case Qt::DisplayRole: return grp->name(); case Qt::DecorationRole: if(grp->highlighted()) switch(grp->type()) { case CGroupListItem::ALL: // Removing from a group - return SmallIcon("list-remove"); + return QIcon::fromTheme("list-remove"); case CGroupListItem::PERSONAL: // Copying/moving case CGroupListItem::SYSTEM: // Copying/moving - return SmallIcon(Qt::LeftToRight==QApplication::layoutDirection() + return QIcon::fromTheme(Qt::LeftToRight==QApplication::layoutDirection() ? "go-next" : "go-previous"); case CGroupListItem::CUSTOM: // Adding to a group - return SmallIcon("list-add"); + return QIcon::fromTheme("list-add"); default: break; } else switch(grp->type()) { case CGroupListItem::ALL: - return SmallIcon("font"); + return QIcon::fromTheme("font"); case CGroupListItem::PERSONAL: - return SmallIcon("user-identity"); + return QIcon::fromTheme("user-identity"); case CGroupListItem::SYSTEM: - return SmallIcon("computer"); + return QIcon::fromTheme("computer"); case CGroupListItem::UNCLASSIFIED: - return SmallIcon("fontstatus"); + return QIcon::fromTheme("fontstatus"); case CGroupListItem::CUSTOM: if(0==grp->families().count()) - return SmallIcon("image-missing"); + return QIcon::fromTheme("image-missing"); switch(grp->status()) { case CFamilyItem::PARTIAL: - return SmallIcon("dialog-ok", 0, KIconLoader::DisabledState); + return QIcon::fromTheme("dialog-ok"); case CFamilyItem::ENABLED: - return SmallIcon("dialog-ok"); + return QIcon::fromTheme("dialog-ok"); case CFamilyItem::DISABLED: - return SmallIcon("dialog-cancel"); + return QIcon::fromTheme("dialog-cancel"); } break; } default: break; } break; } return QVariant(); } bool CGroupList::setData(const QModelIndex &index, const QVariant &value, int role) { if(Qt::EditRole==role && index.isValid()) { QString name(value.toString().trimmed()); if(!name.isEmpty()) { CGroupListItem *grp=static_cast(index.internalPointer()); if(grp && grp->isCustom() && grp->name()!=name && !exists(name, false)) { grp->setName(name); itsModified=true; save(); sort(0, itsSortOrder); return true; } } } return false; } Qt::ItemFlags CGroupList::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::ItemIsEnabled; CGroupListItem *grp=static_cast(index.internalPointer()); return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled | (grp && grp->type()==CGroupListItem::CUSTOM ? Qt::ItemIsEditable : Qt::NoItemFlags); } QVariant CGroupList::headerData(int section, Qt::Orientation orientation, int role) const { if (Qt::Horizontal==orientation && COL_GROUP_NAME==section) switch(role) { case Qt::DisplayRole: return i18n("Group"); case Qt::TextAlignmentRole: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); case Qt::WhatsThisRole: return whatsThis(); default: break; } return QVariant(); } QModelIndex CGroupList::index(int row, int column, const QModelIndex &parent) const { if(!parent.isValid()) { CGroupListItem *grp=itsGroups.value(row); if(grp) return createIndex(row, column, grp); } return QModelIndex(); } QModelIndex CGroupList::parent(const QModelIndex &) const { return QModelIndex(); } int CGroupList::rowCount(const QModelIndex &) const { return itsGroups.count(); } void CGroupList::rescan() { save(); load(); sort(0, itsSortOrder); } void CGroupList::load() { time_t ts=Misc::getTimeStamp(itsFileName); if(!ts || ts!=itsTimeStamp) { clear(); itsTimeStamp=ts; if(load(itsFileName)) itsModified=false; } } bool CGroupList::load(const QString &file) { QFile f(file); bool rv(false); if(f.open(QIODevice::ReadOnly)) { QDomDocument doc; if(doc.setContent(&f)) for(QDomNode n=doc.documentElement().firstChild(); !n.isNull(); n=n.nextSibling()) { QDomElement e=n.toElement(); if(GROUP_TAG==e.tagName() && e.hasAttribute(NAME_ATTR)) { QString name(e.attribute(NAME_ATTR)); CGroupListItem *item=find(name); if(!item) { item=new CGroupListItem(name); if(!itsGroups.contains(itsSpecialGroups[CGroupListItem::UNCLASSIFIED])) itsGroups.append(itsSpecialGroups[CGroupListItem::UNCLASSIFIED]); itsGroups.append(item); rv=true; } if(item->addFamilies(e)) rv=true; } } } return rv; } bool CGroupList::save() { if(itsModified && save(itsFileName, nullptr)) { itsTimeStamp=Misc::getTimeStamp(itsFileName); return true; } return false; } bool CGroupList::save(const QString &fileName, CGroupListItem *grp) { QSaveFile file(fileName); if (file.open(QIODevice::WriteOnly)) { QTextStream str(&file); str << "<" GROUPS_DOC ">" << endl; if(grp) grp->save(str); else { QList::Iterator it(itsGroups.begin()), end(itsGroups.end()); for(; it!=end; ++it) if((*it)->isCustom()) (*it)->save(str); } str << "" << endl; itsModified=false; return file.commit(); } return false; } void CGroupList::merge(const QString &file) { if(load(file)) { itsModified=true; sort(0, itsSortOrder); } } void CGroupList::clear() { beginResetModel(); itsGroups.removeFirst(); // Remove all if(itsSpecialGroups[CGroupListItem::SYSTEM]) { itsGroups.removeFirst(); // Remove personal itsGroups.removeFirst(); // Remove system } if(itsGroups.contains(itsSpecialGroups[CGroupListItem::UNCLASSIFIED])) itsGroups.removeFirst(); // Remove unclassif... qDeleteAll(itsGroups); itsGroups.clear(); itsGroups.append(itsSpecialGroups[CGroupListItem::ALL]); if(itsSpecialGroups[CGroupListItem::SYSTEM]) { itsGroups.append(itsSpecialGroups[CGroupListItem::PERSONAL]); itsGroups.append(itsSpecialGroups[CGroupListItem::SYSTEM]); } // Don't add 'Unclassif' until we have some user groups endResetModel(); } QModelIndex CGroupList::index(CGroupListItem::EType t) { return createIndex(t, 0, itsSpecialGroups[t]); } void CGroupList::createGroup(const QString &name) { if(!exists(name)) { if(!itsGroups.contains(itsSpecialGroups[CGroupListItem::UNCLASSIFIED])) itsGroups.append(itsSpecialGroups[CGroupListItem::UNCLASSIFIED]); itsGroups.append(new CGroupListItem(name)); itsModified=true; save(); sort(0, itsSortOrder); } } bool CGroupList::removeGroup(const QModelIndex &idx) { if(idx.isValid()) { CGroupListItem *grp=static_cast(idx.internalPointer()); if(grp && grp->isCustom() && KMessageBox::Continue==KMessageBox::warningContinueCancel(itsParent, i18n("

Do you really want to remove \'%1\'?

" "

This will only remove the group, and not " "the actual fonts.

", grp->name()), i18n("Remove Group"), KGuiItem(i18n("Remove"), "list-remove", i18n("Remove group")))) { itsModified=true; itsGroups.removeAll(grp); - + int stdGroups=1 +// All (itsSpecialGroups[CGroupListItem::SYSTEM] ? 2 : 0)+ // Personal, System 1; // Unclassified if(stdGroups==itsGroups.count() && itsGroups.contains(itsSpecialGroups[CGroupListItem::UNCLASSIFIED])) itsGroups.removeAll(itsSpecialGroups[CGroupListItem::UNCLASSIFIED]); delete grp; save(); sort(0, itsSortOrder); return true; } } return false; } void CGroupList::removeFromGroup(const QModelIndex &group, const QSet &families) { if(group.isValid()) { CGroupListItem *grp=static_cast(group.internalPointer()); if(grp && grp->isCustom()) { QSet::ConstIterator it(families.begin()), end(families.end()); bool update(false); for(; it!=end; ++it) if(removeFromGroup(grp, *it)) update=true; if(update) emit refresh(); } } } QString CGroupList::whatsThis() const { return i18n("

Font Groups

This list displays the font groups available on your system. " "There are 2 main types of font groups:" "

  • Standard are special groups used by the font manager.
      %1
  • " "
  • Custom are groups created by you. To add a font family to one of " "these groups simply drag it from the list of fonts, and drop " "onto the desired group. To remove a family from the group, drag " "the font onto the \"All Fonts\" group.
  • " "

", Misc::root() ? i18n("
  • All Fonts contains all the fonts installed on your system.
  • " "
  • Unclassified contains all fonts that have not yet been placed " "within a \"Custom\" group.
  • ") : i18n("
  • All Fonts contains all the fonts installed on your system - " "both \"System\" and \"Personal\".
  • " "
  • System contains all fonts that are installed system-wide (i.e. " "available to all users).
  • " "
  • Personal contains your personal fonts.
  • " "
  • Unclassified contains all fonts that have not yet been placed " "within a \"Custom\" group.
  • ")); } void CGroupList::addToGroup(const QModelIndex &group, const QSet &families) { if(group.isValid()) { CGroupListItem *grp=static_cast(group.internalPointer()); if(grp && grp->isCustom()) { QSet::ConstIterator it(families.begin()), end(families.end()); bool update(false); for(; it!=end; ++it) if(!grp->hasFamily(*it)) { grp->addFamily(*it); update=true; itsModified=true; } if(update) emit refresh(); } } } void CGroupList::removeFamily(const QString &family) { QList::ConstIterator it(itsGroups.begin()), end(itsGroups.end()); for(; it!=end; ++it) removeFromGroup(*it, family); } bool CGroupList::removeFromGroup(CGroupListItem *grp, const QString &family) { if(grp && grp->isCustom() && grp->hasFamily(family)) { grp->removeFamily(family); itsModified=true; return true; } return false; } static bool groupNameLessThan(const CGroupListItem *f1, const CGroupListItem *f2) { return f1 && f2 && (f1->type()type() || (f1->type()==f2->type() && QString::localeAwareCompare(f1->name(), f2->name())<0)); } static bool groupNameGreaterThan(const CGroupListItem *f1, const CGroupListItem *f2) { return f1 && f2 && (f1->type()type() || (f1->type()==f2->type() && QString::localeAwareCompare(f1->name(), f2->name())>0)); } void CGroupList::sort(int, Qt::SortOrder order) { itsSortOrder=order; std::sort(itsGroups.begin(), itsGroups.end(), Qt::AscendingOrder==order ? groupNameLessThan : groupNameGreaterThan); emit layoutChanged(); } Qt::DropActions CGroupList::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList CGroupList::mimeTypes() const { QStringList types; types << KFI_FONT_DRAG_MIME; return types; } CGroupListItem * CGroupList::find(const QString &name) { QList::ConstIterator it(itsGroups.begin()), end(itsGroups.end()); for(; it!=end; ++it) if((*it)->name()==name) return (*it); return nullptr; } bool CGroupList::exists(const QString &name, bool showDialog) { if(nullptr!=find(name)) { if(showDialog) KMessageBox::error(itsParent, i18n("A group named \'%1\' already " "exists.", name)); return true; } return false; } class CGroupListViewDelegate : public QStyledItemDelegate { public: CGroupListViewDelegate(QObject *p) : QStyledItemDelegate(p) { } ~CGroupListViewDelegate() override { } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &idx) const override { CGroupListItem *grp=static_cast(idx.internalPointer()); QStyleOptionViewItem opt(option); if(grp && grp->isUnclassified()) opt.rect.adjust(0, 0, 0, -1); - + QStyledItemDelegate::paint(painter, opt, idx); if(grp && grp->isUnclassified()) { opt.rect.adjust(2, 0, -2, 1); painter->setPen(QApplication::palette().color(QPalette::Text)); painter->drawLine(opt.rect.bottomLeft(), opt.rect.bottomRight()); } } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &idx) const override { QSize sz(QStyledItemDelegate::sizeHint(option, idx)); CGroupListItem *grp=static_cast(idx.internalPointer()); if(grp && grp->isUnclassified()) sz.setHeight(sz.height()+1); return sz; } static bool isCloseEvent(QKeyEvent *event) { return Qt::Key_Tab==event->key() || Qt::Key_Backtab==event->key() || Qt::Key_Enter==event->key() || Qt::Key_Return==event->key(); } - + bool eventFilter(QObject *editor, QEvent *event) override { if(editor && event && QEvent::KeyPress==event->type() && isCloseEvent(static_cast(event)) && qobject_cast(editor)) { QString text=static_cast(editor)->text().trimmed(); if(!text.isEmpty() && !static_cast(static_cast(parent())->model())->exists(text, false)) { emit commitData(static_cast(editor)); emit closeEditor(static_cast(editor)); return true; } } return false; } }; - + CGroupListView::CGroupListView(QWidget *parent, CGroupList *model) : QTreeView(parent) { setModel(model); setItemDelegate(new CGroupListViewDelegate(this)); sortByColumn(COL_GROUP_NAME, Qt::AscendingOrder); setSelectionMode(QAbstractItemView::SingleSelection); setSortingEnabled(true); setAllColumnsShowFocus(true); setAlternatingRowColors(true); setAcceptDrops(true); setDragDropMode(QAbstractItemView::DropOnly); setDropIndicatorShown(true); setDragEnabled(false); header()->setSortIndicatorShown(true); setRootIsDecorated(false); itsMenu=new QMenu(this); itsDeleteAct=itsMenu->addAction(QIcon::fromTheme("list-remove"), i18n("Remove"), this, SIGNAL(del())); itsMenu->addSeparator(); - itsEnableAct=itsMenu->addAction(QIcon::fromTheme("enablefont"), i18n("Enable"), + itsEnableAct=itsMenu->addAction(QIcon::fromTheme("font-enable"), i18n("Enable"), this, SIGNAL(enable())); - itsDisableAct=itsMenu->addAction(QIcon::fromTheme("disablefont"), i18n("Disable"), + itsDisableAct=itsMenu->addAction(QIcon::fromTheme("font-disable"), i18n("Disable"), this, SIGNAL(disable())); itsMenu->addSeparator(); itsRenameAct=itsMenu->addAction(QIcon::fromTheme("edit-rename"), i18n("Rename..."), this, SLOT(rename())); - + if(!Misc::app(KFI_PRINTER).isEmpty()) { itsMenu->addSeparator(); itsPrintAct=itsMenu->addAction(QIcon::fromTheme("document-print"), i18n("Print..."), this, SIGNAL(print())); } else itsPrintAct= nullptr; itsMenu->addSeparator(); itsExportAct=itsMenu->addAction(QIcon::fromTheme("document-export"), i18n("Export..."), this, SIGNAL(zip())); setWhatsThis(model->whatsThis()); header()->setWhatsThis(whatsThis()); connect(this, SIGNAL(addFamilies(QModelIndex,QSet)), model, SLOT(addToGroup(QModelIndex,QSet))); connect(this, SIGNAL(removeFamilies(QModelIndex,QSet)), model, SLOT(removeFromGroup(QModelIndex,QSet))); } CGroupListItem::EType CGroupListView::getType() { QModelIndexList selectedItems(selectedIndexes()); if(!selectedItems.isEmpty() && selectedItems.last().isValid()) { CGroupListItem *grp=static_cast(selectedItems.last().internalPointer()); return grp->type(); } return CGroupListItem::ALL; } void CGroupListView::controlMenu(bool del, bool en, bool dis, bool p, bool exp) { itsDeleteAct->setEnabled(del); itsRenameAct->setEnabled(del); itsEnableAct->setEnabled(en); itsDisableAct->setEnabled(dis); if(itsPrintAct) itsPrintAct->setEnabled(p); itsExportAct->setEnabled(exp); } void CGroupListView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { QModelIndexList deselectedItems(deselected.indexes()); QAbstractItemView::selectionChanged(selected, deselected); QModelIndexList selectedItems(selectedIndexes()); if(0==selectedItems.count() && 1==deselectedItems.count()) selectionModel()->select(deselectedItems.last(), QItemSelectionModel::Select); else emit itemSelected(selectedItems.count() ? selectedItems.last() : QModelIndex()); } void CGroupListView::rename() { QModelIndex index(currentIndex()); if(index.isValid()) edit(index); } void CGroupListView::emitMoveFonts() { emit moveFonts(); } void CGroupListView::contextMenuEvent(QContextMenuEvent *ev) { if(indexAt(ev->pos()).isValid()) itsMenu->popup(ev->globalPos()); } void CGroupListView::dragEnterEvent(QDragEnterEvent *event) { if(event->mimeData()->hasFormat(KFI_FONT_DRAG_MIME)) event->acceptProposedAction(); } void CGroupListView::dragMoveEvent(QDragMoveEvent *event) { if(event->mimeData()->hasFormat(KFI_FONT_DRAG_MIME)) { QModelIndex index(indexAt(event->pos())); if(index.isValid()) { if(COL_GROUP_NAME!=index.column()) index=((CGroupList *)model())->createIdx(index.row(), COL_GROUP_NAME, index.internalPointer()); CGroupListItem *dest=static_cast(index.internalPointer()); CGroupListItem::EType type=getType(); if(dest) if(!selectedIndexes().contains(index)) { bool ok(true); if(dest->isCustom()) emit info(i18n("Add to \"%1\".", dest->name())); else if(CGroupListItem::CUSTOM==type && dest->isAll()) emit info(i18n("Remove from current group.")); else if(!Misc::root() && dest->isPersonal() && CGroupListItem::SYSTEM==type) emit info(i18n("Move to personal folder.")); else if(!Misc::root() && dest->isSystem() && CGroupListItem::PERSONAL==type) emit info(i18n("Move to system folder.")); else ok=false; if(ok) { drawHighlighter(index); event->acceptProposedAction(); return; } } } event->ignore(); drawHighlighter(QModelIndex()); emit info(QString()); } } void CGroupListView::dragLeaveEvent(QDragLeaveEvent *) { drawHighlighter(QModelIndex()); emit info(QString()); } void CGroupListView::dropEvent(QDropEvent *event) { emit info(QString()); drawHighlighter(QModelIndex()); if(event->mimeData()->hasFormat(KFI_FONT_DRAG_MIME)) { event->acceptProposedAction(); QSet families; QByteArray encodedData(event->mimeData()->data(KFI_FONT_DRAG_MIME)); QDataStream ds(&encodedData, QIODevice::ReadOnly); QModelIndex from(selectedIndexes().last()), to(indexAt(event->pos())); ds >> families; // Are we moving/copying, removing a font from the current group? if(to.isValid() && from.isValid()) { if( ((static_cast(from.internalPointer()))->isSystem() && (static_cast(to.internalPointer()))->isPersonal()) || ((static_cast(from.internalPointer()))->isPersonal() && (static_cast(to.internalPointer()))->isSystem())) QTimer::singleShot(0, this, SLOT(emitMoveFonts())); else if((static_cast(from.internalPointer()))->isCustom() && !(static_cast(to.internalPointer()))->isCustom()) emit removeFamilies(from, families); else emit addFamilies(to, families); } if(isUnclassified()) emit unclassifiedChanged(); } } void CGroupListView::drawHighlighter(const QModelIndex &idx) { if(itsCurrentDropItem!=idx) { ((CGroupList *)model())->update(itsCurrentDropItem, idx); itsCurrentDropItem=idx; } } bool CGroupListView::viewportEvent(QEvent *event) { executeDelayedItemsLayout(); return QTreeView::viewportEvent(event); } } diff --git a/kcms/kfontinst/kcmfontinst/KCmFontInst.cpp b/kcms/kfontinst/kcmfontinst/KCmFontInst.cpp index e25b39724..688ca2a9c 100644 --- a/kcms/kfontinst/kcmfontinst/KCmFontInst.cpp +++ b/kcms/kfontinst/kcmfontinst/KCmFontInst.cpp @@ -1,1276 +1,1270 @@ /* * 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 "KCmFontInst.h" #include "KfiConstants.h" #include "PrintDialog.h" #include "FcEngine.h" #include "FontPreview.h" #include "FontsPackage.h" #include "Misc.h" #include "FontList.h" #include "DuplicatesDialog.h" #include "FontFilter.h" #include "PreviewSelectAction.h" #include "PreviewList.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 #include #include #include #include #include #include #include #define CFG_GROUP "Main Settings" #define CFG_PREVIEW_SPLITTER_SIZES "PreviewSplitterSizes" #define CFG_GROUP_SPLITTER_SIZES "GroupSplitterSizes" #define CFG_FONT_SIZE "FontSize" K_PLUGIN_FACTORY(FontInstallFactory, registerPlugin(); ) K_EXPORT_PLUGIN(FontInstallFactory("fontinst")) namespace KFI { static QString partialIcon(bool load=true) { QString name = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/kfi/partial.png"; if(Misc::fExists(name)) { if(!load) QFile::remove(name); } else if(load) { QString pth; QPixmap pix=KIconLoader::global()->loadIcon("dialog-ok", KIconLoader::Small, KIconLoader::SizeSmall, KIconLoader::DisabledState); pix.save(name, "PNG"); } return name; } class CPushButton : public QPushButton { public: CPushButton(const KGuiItem &item, QWidget *parent) : QPushButton(parent) { KGuiItem::assign(this, item); theirHeight=qMax(theirHeight, QPushButton::sizeHint().height()); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } QSize sizeHint() const override { QSize sh(QPushButton::sizeHint()); sh.setHeight(theirHeight); if(sh.width()addAppDir(KFI_NAME); KAboutData *about = new KAboutData(QStringLiteral("fontinst"), i18n("Font Management"), QStringLiteral("1.0"), QString(), KAboutLicense::GPL, i18n("(C) Craig Drummond, 2000 - 2009")); about->addAuthor(i18n("Craig Drummond"), i18n("Developer and maintainer"), QStringLiteral("craig@kde.org")); setAboutData(about); KConfigGroup cg(&itsConfig, CFG_GROUP); itsGroupSplitter=new QSplitter(this); - itsGroupSplitter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + itsGroupSplitter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); QWidget *groupWidget=new QWidget(itsGroupSplitter), *fontWidget=new QWidget(itsGroupSplitter); itsPreviewSplitter=new QSplitter(fontWidget); - itsPreviewSplitter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + itsPreviewSplitter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - QWidget *toolbarWidget=new QWidget(this), - *fontControlWidget=new QWidget(fontWidget); - CToolBar *toolbar=new CToolBar(toolbarWidget); + QWidget *fontControlWidget=new QWidget(fontWidget); QGridLayout *groupsLayout=new QGridLayout(groupWidget); QBoxLayout *mainLayout=new QBoxLayout(QBoxLayout::TopToBottom, this), - *toolbarLayout=new QBoxLayout(QBoxLayout::LeftToRight, toolbarWidget), *fontsLayout=new QBoxLayout(QBoxLayout::TopToBottom, fontWidget), *fontControlLayout=new QBoxLayout(QBoxLayout::LeftToRight, fontControlWidget); - toolbarLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setContentsMargins(0, 0, 0, 0); groupsLayout->setContentsMargins(0, 0, 0, 0); fontsLayout->setContentsMargins(0, 0, 0, 0); fontControlLayout->setContentsMargins(0, 0, 0, 0); - // Toolbar... - duplicateFontsAct=new QAction(QIcon::fromTheme("system-search"), i18n("Scan for Duplicate Fonts..."), this); -// validateFontsAct=new QAction(QIcon::fromTheme("checkmark"), i18n("Validate Fonts..."), this); - - toolbar->addAction(duplicateFontsAct); -// toolbar->addAction(validateFontsAct); - toolbar->setToolButtonStyle(Qt::ToolButtonFollowStyle); - itsFilter=new CFontFilter(toolbarWidget); + itsFilter=new CFontFilter(this); // Details - Groups... itsGroupList=new CGroupList(groupWidget); itsGroupListView=new CGroupListView(groupWidget, itsGroupList); QPushButton *createGroup=new CPushButton(KGuiItem(QString(), "list-add", i18n("Create New Group...")), groupWidget); itsDeleteGroupControl=new CPushButton(KGuiItem(QString(), "list-remove", i18n("Remove Group...")), groupWidget); - itsEnableGroupControl=new CPushButton(KGuiItem(QString(), "enablefont", + itsEnableGroupControl=new CPushButton(KGuiItem(QString(), "font-enable", i18n("Enable Fonts in Group...")), groupWidget); - itsDisableGroupControl=new CPushButton(KGuiItem(QString(), "disablefont", + itsDisableGroupControl=new CPushButton(KGuiItem(QString(), "font-disable", i18n("Disable Fonts in Group...")), groupWidget); groupsLayout->addWidget(itsGroupListView, 0, 0, 1, 5); groupsLayout->addWidget(createGroup, 1, 0); groupsLayout->addWidget(itsDeleteGroupControl, 1, 1); groupsLayout->addWidget(itsEnableGroupControl, 1, 2); groupsLayout->addWidget(itsDisableGroupControl, 1, 3); groupsLayout->addItem(new QSpacerItem(itsDisableGroupControl->width(), groupsLayout->spacing(), QSizePolicy::Expanding, QSizePolicy::Fixed), 1, 4); itsPreviewWidget = new QWidget(this); QBoxLayout *previewWidgetLayout = new QBoxLayout(QBoxLayout::TopToBottom, itsPreviewWidget); previewWidgetLayout->setContentsMargins(0, 0, 0, 0); previewWidgetLayout->setSpacing(0); - + // Preview QFrame *previewFrame=new QFrame(itsPreviewWidget); QBoxLayout *previewFrameLayout=new QBoxLayout(QBoxLayout::LeftToRight, previewFrame); previewFrameLayout->setContentsMargins(0, 0, 0, 0); previewFrameLayout->setSpacing(0); previewFrame->setFrameShape(QFrame::StyledPanel); previewFrame->setFrameShadow(QFrame::Sunken); previewFrame->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); itsPreview=new CFontPreview(previewFrame); itsPreview->setWhatsThis(i18n("This displays a preview of the selected font.")); itsPreview->setContextMenuPolicy(Qt::CustomContextMenu); previewFrameLayout->addWidget(itsPreview); previewWidgetLayout->addWidget(previewFrame); itsPreview->engine()->readConfig(itsConfig); // List-style preview... itsPreviewList = new CPreviewListView(itsPreview->engine(), itsPreviewWidget); previewWidgetLayout->addWidget(itsPreviewList); itsPreviewList->setVisible(false); // Font List... itsFontList=new CFontList(fontWidget); itsFontListView=new CFontListView(itsPreviewSplitter, itsFontList); itsFontListView->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + itsScanDuplicateFontsControl=new CPushButton(KGuiItem(i18n("Find Duplicates..."), "edit-duplicate", + i18n("Scan for Duplicate Fonts...")), + fontControlWidget); + itsAddFontControl=new CPushButton(KGuiItem(i18n("Install from File..."), "document-import", i18n("Install fonts from a local file")), fontControlWidget); itsGetNewFontsControl=new CPushButton(KGuiItem(i18n("Get New Fonts..."), "get-hot-new-stuff", i18n("Download new fonts")), fontControlWidget); itsDeleteFontControl=new CPushButton(KGuiItem(QString(), "edit-delete", i18n("Delete Selected Fonts...")), fontControlWidget); itsPreviewSplitter->addWidget(itsPreviewWidget); itsPreviewSplitter->setCollapsible(1, true); - itsStatusLabel = new QLabel(fontControlWidget); + QWidget *statusRow = new QWidget(this); + QBoxLayout *statusRowLayout=new QBoxLayout(QBoxLayout::LeftToRight, statusRow); + itsStatusLabel = new QLabel(statusRow); itsStatusLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight); - itsListingProgress=new CProgressBar(fontControlWidget, itsStatusLabel->height()); + itsListingProgress=new CProgressBar(statusRow, itsStatusLabel->height()); itsListingProgress->setRange(0, 100); + statusRowLayout->addWidget(itsListingProgress); + statusRowLayout->addWidget(itsStatusLabel); // Layout widgets... - toolbarLayout->addWidget(toolbar); - toolbarLayout->addWidget(itsFilter); - mainLayout->addWidget(toolbarWidget); + mainLayout->addWidget(itsFilter); mainLayout->addWidget(itsGroupSplitter); + mainLayout->addWidget(statusRow); fontControlLayout->addWidget(itsDeleteFontControl); - fontControlLayout->addWidget(itsStatusLabel); - fontControlLayout->addItem(new QSpacerItem(0, itsListingProgress->height()+4, - QSizePolicy::Fixed, QSizePolicy::Fixed)); - fontControlLayout->addWidget(itsListingProgress); + fontControlLayout->addStretch(); + fontControlLayout->addWidget(itsScanDuplicateFontsControl); fontControlLayout->addWidget(itsAddFontControl); fontControlLayout->addWidget(itsGetNewFontsControl); fontsLayout->addWidget(itsPreviewSplitter); fontsLayout->addWidget(fontControlWidget); // Set size of widgets... itsPreviewSplitter->setChildrenCollapsible(false); itsGroupSplitter->setChildrenCollapsible(false); itsGroupSplitter->setStretchFactor(0, 0); itsGroupSplitter->setStretchFactor(1, 1); itsPreviewSplitter->setStretchFactor(0, 1); itsPreviewSplitter->setStretchFactor(1, 0); // Set sizes for 3 views... QList defaultSizes; defaultSizes+=300; defaultSizes+=220; itsPreviewSplitter->setSizes(cg.readEntry(CFG_PREVIEW_SPLITTER_SIZES, defaultSizes)); itsPreviewHidden=itsPreviewSplitter->sizes().at(1)<8; defaultSizes.clear(); defaultSizes+=110; defaultSizes+=350; itsGroupSplitter->setSizes(cg.readEntry(CFG_GROUP_SPLITTER_SIZES, defaultSizes)); // Preview widget pop-up menu itsPreviewMenu = new QMenu(itsPreview); QAction *zoomIn=KStandardAction::create(KStandardAction::ZoomIn, itsPreview, SLOT(zoomIn()), this), *zoomOut=KStandardAction::create(KStandardAction::ZoomOut, itsPreview, SLOT(zoomOut()), this); itsPreviewMenu->addAction(zoomIn); itsPreviewMenu->addAction(zoomOut); itsPreviewMenu->addSeparator(); CPreviewSelectAction *prevSel=new CPreviewSelectAction(itsPreviewMenu); itsPreviewMenu->addAction(prevSel); QAction *changeTextAct=new QAction(QIcon::fromTheme("edit-rename"), i18n("Change Preview Text..."), this); itsPreviewMenu->addAction(changeTextAct), itsPreviewListMenu = new QMenu(itsPreviewList); itsPreviewListMenu->addAction(changeTextAct), // Connect signals... connect(itsPreview, SIGNAL(atMax(bool)), zoomIn, SLOT(setDisabled(bool))); connect(itsPreview, SIGNAL(atMin(bool)), zoomOut, SLOT(setDisabled(bool))); connect(prevSel, SIGNAL(range(QList)), itsPreview, SLOT(setUnicodeRange(QList))); connect(changeTextAct, SIGNAL(triggered(bool)), SLOT(changeText())); - connect(itsFilter, SIGNAL(textChanged(QString)), itsFontListView, SLOT(filterText(QString))); - connect(itsFilter, SIGNAL(criteriaChanged(int,qulonglong,QStringList)), + connect(itsFilter, SIGNAL(queryChanged(QString)), itsFontListView, SLOT(filterText(QString))); + connect(itsFilter, SIGNAL(criteriaChanged(int,qulonglong,QStringList)), itsFontListView, SLOT(filterCriteria(int,qulonglong,QStringList))); connect(itsGroupListView, SIGNAL(del()), SLOT(removeGroup())); connect(itsGroupListView, SIGNAL(print()), SLOT(printGroup())); connect(itsGroupListView, SIGNAL(enable()), SLOT(enableGroup())); connect(itsGroupListView, SIGNAL(disable()), SLOT(disableGroup())); connect(itsGroupListView, SIGNAL(moveFonts()), SLOT(moveFonts())); connect(itsGroupListView, SIGNAL(zip()), SLOT(zipGroup())); connect(itsGroupListView, SIGNAL(itemSelected(QModelIndex)), SLOT(groupSelected(QModelIndex))); connect(itsGroupListView, SIGNAL(info(QString)), SLOT(showInfo(QString))); connect(itsGroupList, SIGNAL(refresh()), SLOT(refreshFontList())); connect(itsFontList, SIGNAL(listingPercent(int)), SLOT(listingPercent(int))); connect(itsFontList, SIGNAL(layoutChanged()), SLOT(setStatusBar())); connect(itsFontListView, SIGNAL(del()), SLOT(deleteFonts())); connect(itsFontListView, SIGNAL(print()), SLOT(print())); connect(itsFontListView, SIGNAL(enable()), SLOT(enableFonts())); connect(itsFontListView, SIGNAL(disable()), SLOT(disableFonts())); connect(itsFontListView, SIGNAL(fontsDropped(QSet)), SLOT(addFonts(QSet))); connect(itsFontListView, SIGNAL(itemsSelected(QModelIndexList)), SLOT(fontsSelected(QModelIndexList))); connect(itsFontListView, SIGNAL(refresh()), SLOT(setStatusBar())); connect(itsGroupListView, SIGNAL(unclassifiedChanged()), itsFontListView, SLOT(refreshFilter())); connect(createGroup, SIGNAL(clicked()), SLOT(addGroup())); connect(itsDeleteGroupControl, SIGNAL(clicked()), SLOT(removeGroup())); connect(itsEnableGroupControl, SIGNAL(clicked()), SLOT(enableGroup())); connect(itsDisableGroupControl, SIGNAL(clicked()), SLOT(disableGroup())); connect(itsAddFontControl, SIGNAL(clicked()), SLOT(addFonts())); connect(itsGetNewFontsControl, SIGNAL(clicked()), SLOT(downloadFonts())); connect(itsDeleteFontControl, SIGNAL(clicked()), SLOT(deleteFonts())); - connect(duplicateFontsAct, SIGNAL(triggered(bool)), SLOT(duplicateFonts())); + connect(itsScanDuplicateFontsControl, SIGNAL(clicked()), SLOT(duplicateFonts())); //connect(validateFontsAct, SIGNAL(triggered(bool)), SLOT(validateFonts())); connect(itsPreview, SIGNAL(customContextMenuRequested(QPoint)), SLOT(previewMenu(QPoint))); connect(itsPreviewList, SIGNAL(showMenu(QPoint)), SLOT(previewMenu(QPoint))); connect(itsPreviewSplitter, SIGNAL(splitterMoved(int,int)), SLOT(splitterMoved())); selectMainGroup(); itsFontList->load(); } CKCmFontInst::~CKCmFontInst() { KConfigGroup cg(&itsConfig, CFG_GROUP); cg.writeEntry(CFG_PREVIEW_SPLITTER_SIZES, itsPreviewSplitter->sizes()); cg.writeEntry(CFG_GROUP_SPLITTER_SIZES, itsGroupSplitter->sizes()); delete itsTempDir; partialIcon(false); } QString CKCmFontInst::quickHelp() const { return Misc::root() ? i18n("

    Font Installer

    This module allows you to" " install TrueType, Type1, and Bitmap" " fonts.

    You may also install fonts using Konqueror:" " type fonts:/ into Konqueror's location bar" " and this will display your installed fonts. To install a" " font, simply copy one into the folder.

    ") : i18n("

    Font Installer

    This module allows you to" " install TrueType, Type1, and Bitmap" " fonts.

    You may also install fonts using Konqueror:" " type fonts:/ into Konqueror's location bar" " and this will display your installed fonts. To install a" " font, simply copy it into the appropriate folder - " " \"%1\" for fonts available to just yourself, or " " \"%2\" for system-wide fonts (available to all).

    ", i18n(KFI_KIO_FONTS_USER), i18n(KFI_KIO_FONTS_SYS)); } void CKCmFontInst::previewMenu(const QPoint &pos) { if(itsPreviewList->isHidden()) itsPreviewMenu->popup(itsPreview->mapToGlobal(pos)); else itsPreviewListMenu->popup(itsPreviewList->mapToGlobal(pos)); } void CKCmFontInst::splitterMoved() { if(itsPreviewWidget->width()>8 && itsPreviewHidden) { itsPreviewHidden=false; fontsSelected(itsFontListView->getSelectedItems()); } else if(!itsPreviewHidden && itsPreviewWidget->width()<8) itsPreviewHidden=true; } void CKCmFontInst::fontsSelected(const QModelIndexList &list) { if(!itsPreviewHidden) { if(!list.isEmpty()) { if(list.count()<2) { CFontModelItem *mi=static_cast(list.last().internalPointer()); CFontItem *font=mi->parent() ? static_cast(mi) : (static_cast(mi))->regularFont(); if(font) itsPreview->showFont(font->isEnabled() ? font->family() : font->fileName(), font->styleInfo(), font->index()); } else itsPreviewList->showFonts(list); } itsPreviewList->setVisible(list.count()>1); itsPreview->parentWidget()->setVisible(list.count()<2); } itsDeleteFontControl->setEnabled(list.count()); } void CKCmFontInst::addFonts() { QFileDialog dlg(this, i18n("Add Fonts")); dlg.setFileMode(QFileDialog::ExistingFiles); dlg.setMimeTypeFilters(CFontList::fontMimeTypes); QList list; if (dlg.exec() == QDialog::Accepted) list = dlg.selectedUrls(); if(!list.isEmpty()) { QSet urls; QList::Iterator it(list.begin()), end(list.end()); for(; it!=end; ++it) { if(KFI_KIO_FONTS_PROTOCOL!=(*it).scheme()) // Do not try to install from fonts:/ !!! { auto job = KIO::mostLocalUrl(*it); KJobWidgets::setWindow(job, this); job->exec(); QUrl url = job->mostLocalUrl(); if(url.isLocalFile()) { QString file(url.toLocalFile()); if(Misc::isPackage(file)) // If its a package we need to unzip 1st... urls+=FontsPackage::extract(url.toLocalFile(), &itsTempDir); else if(!Misc::isMetrics(url)) urls.insert(url); } else if(!Misc::isMetrics(url)) urls.insert(url); } } if(!urls.isEmpty()) addFonts(urls); delete itsTempDir; itsTempDir=nullptr; } } void CKCmFontInst::groupSelected(const QModelIndex &index) { CGroupListItem *grp=nullptr; if(index.isValid()) grp=static_cast(index.internalPointer()); else return; itsFontListView->setFilterGroup(grp); setStatusBar(); // // Check fonts listed within group are still valid! if(grp->isCustom() && !grp->validated()) { QSet remList; QSet::Iterator it(grp->families().begin()), end(grp->families().end()); for(; it!=end; ++it) if(!itsFontList->hasFamily(*it)) remList.insert(*it); it=remList.begin(); end=remList.end(); for(; it!=end; ++it) itsGroupList->removeFromGroup(grp, *it); grp->setValidated(); } itsGetNewFontsControl->setEnabled(grp->isPersonal() || grp->isAll()); } void CKCmFontInst::print(bool all) { // // In order to support printing of newly installed/enabled fonts, the actual printing // is carried out by the kfontinst helper app. This way we know Qt's font list will be // up to date. if((!itsPrintProc || QProcess::NotRunning==itsPrintProc->state()) && !Misc::app(KFI_PRINTER).isEmpty()) { QSet fonts; itsFontListView->getPrintableFonts(fonts, !all); if(!fonts.isEmpty()) { CPrintDialog dlg(this); KConfigGroup cg(&itsConfig, CFG_GROUP); if(dlg.exec(cg.readEntry(CFG_FONT_SIZE, 1))) { static const int constSizes[]={0, 12, 18, 24, 36, 48}; QSet::ConstIterator it(fonts.begin()), end(fonts.end()); QTemporaryFile tmpFile; bool useFile(fonts.count()>16), startProc(true); QStringList args; if(!itsPrintProc) itsPrintProc=new QProcess(this); else itsPrintProc->kill(); QString title = QGuiApplication::applicationDisplayName(); if (title.isEmpty()) title = QCoreApplication::applicationName(); // // If we have lots of fonts to print, pass kfontinst a temporary groups file to print // instead of passing font by font... if(useFile) { if(tmpFile.open()) { QTextStream str(&tmpFile); for(; it!=end; ++it) str << (*it).family << endl << (*it).styleInfo << endl; args << "--embed" << QString().sprintf("0x%x", (unsigned int)window()->winId()) << "--qwindowtitle" << title << "--qwindowicon" << "preferences-desktop-font-installer" << "--size" << QString().setNum(constSizes[dlg.chosenSize() < 6 ? dlg.chosenSize() : 2]) << "--listfile" << tmpFile.fileName() << "--deletefile"; } else { KMessageBox::error(this, i18n("Failed to save list of fonts to print.")); startProc=false; } } else { args << "--embed" << QString().sprintf("0x%x", (unsigned int)window()->winId()) << "--qwindowtitle" << title << "--qwindowicon" << "preferences-desktop-font-installer" << "--size" << QString().setNum(constSizes[dlg.chosenSize()<6 ? dlg.chosenSize() : 2]); for(; it!=end; ++it) args << "--pfont" << QString((*it).family.toUtf8()+','+QString().setNum((*it).styleInfo)); } if(startProc) { itsPrintProc->start(Misc::app(KFI_PRINTER), args); if(itsPrintProc->waitForStarted(1000)) { if(useFile) tmpFile.setAutoRemove(false); } else KMessageBox::error(this, i18n("Failed to start font printer.")); } cg.writeEntry(CFG_FONT_SIZE, dlg.chosenSize()); } } else KMessageBox::information(this, i18n("There are no printable fonts.\n" "You can only print non-bitmap and enabled fonts."), i18n("Cannot Print")); } } void CKCmFontInst::deleteFonts() { CJobRunner::ItemList urls; QStringList fontNames; QSet fonts; itsDeletedFonts.clear(); itsFontListView->getFonts(urls, fontNames, &fonts, true); if(urls.isEmpty()) KMessageBox::information(this, i18n("You did not select anything to delete."), i18n("Nothing to Delete")); else { QSet::ConstIterator it(fonts.begin()), end(fonts.end()); bool doIt=false; for(; it!=end; ++it) itsDeletedFonts.insert((*it).family); switch(fontNames.count()) { case 0: break; case 1: doIt = KMessageBox::Continue==KMessageBox::warningContinueCancel(this, i18n("

    Do you really want to " "delete

    \'%1\'?

    ", fontNames.first()), i18n("Delete Font"), KStandardGuiItem::del()); break; default: doIt = KMessageBox::Continue==KMessageBox::warningContinueCancelList(this, i18np("Do you really want to delete this font?", "Do you really want to delete these %1 fonts?", fontNames.count()), fontNames, i18n("Delete Fonts"), KStandardGuiItem::del()); } if(doIt) { itsStatusLabel->setText(i18n("Deleting font(s)...")); doCmd(CJobRunner::CMD_DELETE, urls); } } } void CKCmFontInst::moveFonts() { CJobRunner::ItemList urls; QStringList fontNames; itsDeletedFonts.clear(); itsFontListView->getFonts(urls, fontNames, nullptr, true); if(urls.isEmpty()) KMessageBox::information(this, i18n("You did not select anything to move."), i18n("Nothing to Move")); else { bool doIt=false; switch(fontNames.count()) { case 0: break; case 1: doIt = KMessageBox::Continue==KMessageBox::warningContinueCancel(this, i18n("

    Do you really want to " "move

    \'%1\'

    from %2 to %3?

    ", fontNames.first(), itsGroupListView->isSystem() ? i18n(KFI_KIO_FONTS_SYS) : i18n(KFI_KIO_FONTS_USER), itsGroupListView->isSystem() ? i18n(KFI_KIO_FONTS_USER) : i18n(KFI_KIO_FONTS_SYS)), i18n("Move Font"), KGuiItem(i18n("Move"))); break; default: doIt = KMessageBox::Continue==KMessageBox::warningContinueCancelList(this, i18np("

    Do you really want to move this font from %2 to %3?

    ", "

    Do you really want to move these %1 fonts from %2 to %3?

    ", fontNames.count(), itsGroupListView->isSystem() ? i18n(KFI_KIO_FONTS_SYS) : i18n(KFI_KIO_FONTS_USER), itsGroupListView->isSystem() ? i18n(KFI_KIO_FONTS_USER) : i18n(KFI_KIO_FONTS_SYS)), fontNames, i18n("Move Fonts"), KGuiItem(i18n("Move"))); } if(doIt) { itsStatusLabel->setText(i18n("Moving font(s)...")); doCmd(CJobRunner::CMD_MOVE, urls, !itsGroupListView->isSystem()); } } } void CKCmFontInst::zipGroup() { QModelIndex idx(itsGroupListView->currentIndex()); if(idx.isValid()) { CGroupListItem *grp=static_cast(idx.internalPointer()); if(grp) { QFileDialog dlg(this, i18n("Export Group")); dlg.setAcceptMode(QFileDialog::AcceptSave); dlg.setDirectoryUrl(QUrl::fromLocalFile(grp->name())); dlg.setMimeTypeFilters(QStringList() << QStringLiteral("application/zip")); QString fileName; if (dlg.exec() == QDialog::Accepted) fileName = dlg.selectedFiles().value(0); if(!fileName.isEmpty()) { KZip zip(fileName); if(zip.open(QIODevice::WriteOnly)) { QSet files; files=itsFontListView->getFiles(); if(!files.isEmpty()) { QMap map=Misc::getFontFileMap(files); QMap::ConstIterator it(map.constBegin()), end(map.constEnd()); for(; it!=end; ++it) zip.addLocalFile(it.value(), it.key()); zip.close(); } else KMessageBox::error(this, i18n("No files?")); } else KMessageBox::error(this, i18n("Failed to open %1 for writing", fileName)); } } } } void CKCmFontInst::enableFonts() { toggleFonts(true); } void CKCmFontInst::disableFonts() { toggleFonts(false); } void CKCmFontInst::addGroup() { bool ok; QString name(QInputDialog::getText(this, i18n("Create New Group"), i18n("Name of new group:"), QLineEdit::Normal, i18n("New Group"), &ok)); if(ok && !name.isEmpty()) itsGroupList->createGroup(name); } void CKCmFontInst::removeGroup() { if(itsGroupList->removeGroup(itsGroupListView->currentIndex())) selectMainGroup(); } void CKCmFontInst::enableGroup() { toggleGroup(true); } void CKCmFontInst::disableGroup() { toggleGroup(false); } void CKCmFontInst::changeText() { bool status; QString oldStr(itsPreview->engine()->getPreviewString()), newStr(QInputDialog::getText(this, i18n("Preview Text"), i18n("Please enter new text:"), QLineEdit::Normal, oldStr, &status)); if(status && oldStr!=newStr) { itsPreview->engine()->setPreviewString(newStr); itsPreview->showFont(); itsPreviewList->refreshPreviews(); } } void CKCmFontInst::duplicateFonts() { CDuplicatesDialog(this, itsFontList).exec(); } //void CKCmFontInst::validateFonts() //{ //} void CKCmFontInst::downloadFonts() { KNS3::DownloadDialog *newStuff = new KNS3::DownloadDialog("kfontinst.knsrc", this); newStuff->exec(); if(!newStuff->changedEntries().isEmpty()) // We have new fonts, so need to reconfigure fontconfig... { // Ask dbus helper for the current fonts folder name... // We then sym-link our knewstuff3 download folder into the fonts folder... QString destFolder=CJobRunner::folderName(false); if(!destFolder.isEmpty()) { destFolder+="kfontinst"; if(!QFile::exists(destFolder)) { QFile _file(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "kfontinst"); _file.link(destFolder); } } doCmd(CJobRunner::CMD_UPDATE, CJobRunner::ItemList()); } delete newStuff; } void CKCmFontInst::print() { print(false); } void CKCmFontInst::printGroup() { print(true); } void CKCmFontInst::listingPercent(int p) { if(0==p) { showInfo(i18n("Scanning font list...")); itsListingProgress->show(); } else if(100==p && p!=itsListingProgress->value()) { removeDeletedFontsFromGroups(); QSet foundries; itsFontList->getFoundries(foundries); itsFilter->setFoundries(foundries); refreshFamilies(); itsListingProgress->hide(); itsFontListView->selectFirstFont(); } itsListingProgress->setValue(p); } void CKCmFontInst::refreshFontList() { itsFontListView->refreshFilter(); refreshFamilies(); } void CKCmFontInst::refreshFamilies() { QSet enabledFamilies, disabledFamilies, partialFamilies; itsFontList->getFamilyStats(enabledFamilies, disabledFamilies, partialFamilies); itsGroupList->updateStatus(enabledFamilies, disabledFamilies, partialFamilies); setStatusBar(); } void CKCmFontInst::showInfo(const QString &info) { if(info.isEmpty()) if(itsLastStatusBarMsg.isEmpty()) setStatusBar(); else { itsStatusLabel->setText(itsLastStatusBarMsg); itsLastStatusBarMsg=QString(); } else { if(itsLastStatusBarMsg.isEmpty()) itsLastStatusBarMsg=itsStatusLabel->text(); itsStatusLabel->setText(info); } } void CKCmFontInst::setStatusBar() { if(itsFontList->slowUpdates()) return; int enabled=0, disabled=0, partial=0; bool selectedEnabled=false, selectedDisabled=false; itsStatusLabel->setToolTip(QString()); if(0==itsFontList->families().count()) itsStatusLabel->setText(i18n("No fonts")); else { itsFontListView->stats(enabled, disabled, partial); itsFontListView->selectedStatus(selectedEnabled, selectedDisabled); QString text(i18np("1 Font", "%1 Fonts", enabled+disabled+partial)); if(disabled||partial) { text+=QString(" (%2").arg(KIconLoader::global()->iconPath("dialog-ok", -KIconLoader::SizeSmall)).arg(enabled) +QString(" %2").arg(KIconLoader::global()->iconPath("dialog-cancel", -KIconLoader::SizeSmall)).arg(disabled); if(partial) text+=QString(" %2").arg(partialIcon()).arg(partial); text+=QLatin1Char(')'); itsStatusLabel->setToolTip(partial ? i18n("" "" "" "" "" "
    Enabled:%1
    Disabled:%2
    Partially enabled:%3
    Total:%4
    ", enabled, disabled, partial, enabled+disabled+partial) : i18n("" "" "" "" "
    Enabled:%1
    Disabled:%2
    Total:%3
    ", enabled, disabled, enabled+disabled)); } itsStatusLabel->setText(disabled||partial ? "

    "+text+"

    " : text); } CGroupListItem::EType type(itsGroupListView->getType()); bool isStd(CGroupListItem::CUSTOM==type); itsAddFontControl->setEnabled(CGroupListItem::ALL==type||CGroupListItem::UNCLASSIFIED==type|| CGroupListItem::PERSONAL==type||CGroupListItem::SYSTEM==type); itsDeleteGroupControl->setEnabled(isStd); itsEnableGroupControl->setEnabled(disabled||partial); itsDisableGroupControl->setEnabled(isStd && (enabled||partial)); itsGroupListView->controlMenu(itsDeleteGroupControl->isEnabled(), itsEnableGroupControl->isEnabled(), itsDisableGroupControl->isEnabled(), enabled||partial, enabled||disabled); itsDeleteFontControl->setEnabled(selectedEnabled||selectedDisabled); } void CKCmFontInst::addFonts(const QSet &src) { if(!src.isEmpty() && !itsGroupListView->isCustom()) { bool system; if(Misc::root()) system=true; else { switch(itsGroupListView->getType()) { case CGroupListItem::ALL: case CGroupListItem::UNCLASSIFIED: switch(KMessageBox::questionYesNoCancel(this, i18n("Do you wish to install the font(s) for personal use " "(only available to you), or " "system-wide (available to all users)?"), i18n("Where to Install"), KGuiItem(i18n(KFI_KIO_FONTS_USER)), KGuiItem(i18n(KFI_KIO_FONTS_SYS)))) { case KMessageBox::Yes: system=false; break; case KMessageBox::No: system=true; break; default: case KMessageBox::Cancel: return; } break; case CGroupListItem::PERSONAL: system=false; break; case CGroupListItem::SYSTEM: system=true; break; default: return; } } QSet copy; QSet::ConstIterator it, end(src.end()); // // Check if font has any associated AFM or PFM file... itsStatusLabel->setText(i18n("Looking for any associated files...")); if(!itsProgress) { itsProgress = new QProgressDialog(this); itsProgress->setWindowTitle(i18n("Scanning Files...")); itsProgress->setLabelText(i18n("Looking for additional files to install...")); itsProgress->setModal(true); itsProgress->setAutoReset(true); itsProgress->setAutoClose(true); } itsProgress->setCancelButton(nullptr); itsProgress->setMinimumDuration(500); itsProgress->setRange(0, src.size()); itsProgress->setValue(0); int steps=src.count()<200 ? 1 : src.count()/10; for(it=src.begin(); it!=end; ++it) { QList associatedUrls; itsProgress->setLabelText(i18n("Looking for files associated with %1", (*it).url())); itsProgress->setValue(itsProgress->value()+1); if(1==steps || 0==(itsProgress->value()%steps)) { bool dialogVisible(itsProgress->isVisible()); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); if(dialogVisible && !itsProgress->isVisible()) // User closed dialog! re-open!!! itsProgress->show(); } CJobRunner::getAssociatedUrls(*it, associatedUrls, false, this); copy.insert(*it); QList::Iterator aIt(associatedUrls.begin()), aEnd(associatedUrls.end()); for(; aIt!=aEnd; ++aIt) copy.insert(*aIt); } itsProgress->close(); CJobRunner::ItemList installUrls; end=copy.end(); for(it=copy.begin(); it!=end; ++it) installUrls.append(*it); itsStatusLabel->setText(i18n("Installing font(s)...")); doCmd(CJobRunner::CMD_INSTALL, installUrls, system); } } void CKCmFontInst::removeDeletedFontsFromGroups() { if(!itsDeletedFonts.isEmpty()) { QSet::Iterator it(itsDeletedFonts.begin()), end(itsDeletedFonts.end()); for(; it!=end; ++it) if(!itsFontList->hasFamily(*it)) itsGroupList->removeFamily(*it); itsDeletedFonts.clear(); } } - + void CKCmFontInst::selectGroup(CGroupListItem::EType grp) { QModelIndex current(itsGroupListView->currentIndex()); if(current.isValid()) { CGroupListItem *grpItem=static_cast(current.internalPointer()); if(grpItem && grp==grpItem->type()) return; else itsGroupListView->selectionModel()->select(current, QItemSelectionModel::Deselect); } QModelIndex idx(itsGroupList->index(grp)); itsGroupListView->selectionModel()->select(idx, QItemSelectionModel::Select); itsGroupListView->setCurrentIndex(idx); groupSelected(idx); itsFontListView->refreshFilter(); setStatusBar(); } void CKCmFontInst::toggleGroup(bool enable) { QModelIndex idx(itsGroupListView->currentIndex()); if(idx.isValid()) { CGroupListItem *grp=static_cast(idx.internalPointer()); if(grp) toggleFonts(enable, grp->name()); } } void CKCmFontInst::toggleFonts(bool enable, const QString &grp) { CJobRunner::ItemList urls; QStringList fonts; itsFontListView->getFonts(urls, fonts, nullptr, grp.isEmpty(), !enable, enable); if(urls.isEmpty()) KMessageBox::information(this, enable ? i18n("You did not select anything to enable.") : i18n("You did not select anything to disable."), enable ? i18n("Nothing to Enable") : i18n("Nothing to Disable")); else toggleFonts(urls, fonts, enable, grp); } void CKCmFontInst::toggleFonts(CJobRunner::ItemList &urls, const QStringList &fonts, bool enable, const QString &grp) { bool doIt=false; switch(fonts.count()) { case 0: break; case 1: doIt = KMessageBox::Continue==KMessageBox::warningContinueCancel(this, grp.isEmpty() ? enable ? i18n("

    Do you really want to " "enable

    \'%1\'?

    ", fonts.first()) : i18n("

    Do you really want to " "disable

    \'%1\'?

    ", fonts.first()) : enable ? i18n("

    Do you really want to " "enable

    \'%1\', " "contained within group \'%2\'?

    ", fonts.first(), grp) : i18n("

    Do you really want to " "disable

    \'%1\', " "contained within group \'%2\'?

    ", fonts.first(), grp), enable ? i18n("Enable Font") : i18n("Disable Font"), - enable ? KGuiItem(i18n("Enable"), "enablefont", i18n("Enable Font")) - : KGuiItem(i18n("Disable"), "disablefont", i18n("Disable Font"))); + enable ? KGuiItem(i18n("Enable"), "font-enable", i18n("Enable Font")) + : KGuiItem(i18n("Disable"), "font-disable", i18n("Disable Font"))); break; default: doIt = KMessageBox::Continue==KMessageBox::warningContinueCancelList(this, grp.isEmpty() ? enable ? i18np("Do you really want to enable this font?", "Do you really want to enable these %1 fonts?", urls.count()) : i18np("Do you really want to disable this font?", "Do you really want to disable these %1 fonts?", urls.count()) : enable ? i18np("

    Do you really want to enable this font " "contained within group \'%2\'?

    ", "

    Do you really want to enable these %1 fonts " "contained within group \'%2\'?

    ", urls.count(), grp) : i18np("

    Do you really want to disable this font " "contained within group \'%2\'?

    ", "

    Do you really want to disable these %1 fonts " "contained within group \'%2\'?

    ", urls.count(), grp), fonts, enable ? i18n("Enable Fonts") : i18n("Disable Fonts"), - enable ? KGuiItem(i18n("Enable"), "enablefont", i18n("Enable Fonts")) - : KGuiItem(i18n("Disable"), "disablefont", i18n("Disable Fonts"))); + enable ? KGuiItem(i18n("Enable"), "font-enable", i18n("Enable Fonts")) + : KGuiItem(i18n("Disable"), "font-disable", i18n("Disable Fonts"))); } if(doIt) { if(enable) itsStatusLabel->setText(i18n("Enabling font(s)...")); else itsStatusLabel->setText(i18n("Disabling font(s)...")); doCmd(enable ? CJobRunner::CMD_ENABLE : CJobRunner::CMD_DISABLE, urls); } } void CKCmFontInst::selectMainGroup() { selectGroup(/*Misc::root() ? */CGroupListItem::ALL/* : CGroupListItem::PERSONAL*/); } void CKCmFontInst::doCmd(CJobRunner::ECommand cmd, const CJobRunner::ItemList &urls, bool system) { itsFontList->setSlowUpdates(true); CJobRunner runner(this); connect(&runner, SIGNAL(configuring()), itsFontList, SLOT(unsetSlowUpdates())); runner.exec(cmd, urls, system); itsFontList->setSlowUpdates(false); refreshFontList(); if(CJobRunner::CMD_DELETE==cmd) itsFontListView->clearSelection(); CFcEngine::setDirty(); setStatusBar(); delete itsTempDir; itsTempDir=nullptr; itsFontListView->repaint(); removeDeletedFontsFromGroups(); } } #include "KCmFontInst.moc" diff --git a/kcms/kfontinst/kcmfontinst/KCmFontInst.h b/kcms/kfontinst/kcmfontinst/KCmFontInst.h index 70600041d..087ee1abe 100644 --- a/kcms/kfontinst/kcmfontinst/KCmFontInst.h +++ b/kcms/kfontinst/kcmfontinst/KCmFontInst.h @@ -1,142 +1,142 @@ #ifndef __KCM_FONT_INST_H__ #define __KCM_FONT_INST_H__ /* * 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 "GroupList.h" #include "JobRunner.h" #include #include #include #include #include class QPushButton; class QProgressDialog; class QTemporaryDir; class QAction; class QLabel; class QMenu; class QProcess; class QSplitter; namespace KFI { class CFontFilter; class CFontList; class CFontPreview; class CUpdateDialog; class CFontListView; class CProgressBar; class CPreviewListView; class CKCmFontInst : public KCModule { Q_OBJECT public: explicit CKCmFontInst(QWidget *parent=nullptr, const QVariantList &list=QVariantList()); ~CKCmFontInst() override; public Q_SLOTS: QString quickHelp() const override; void previewMenu(const QPoint &pos); void splitterMoved(); void fontsSelected(const QModelIndexList &list); void groupSelected(const QModelIndex &index); void addFonts(); void deleteFonts(); void moveFonts(); void zipGroup(); void enableFonts(); void disableFonts(); void addGroup(); void removeGroup(); void enableGroup(); void disableGroup(); void changeText(); void duplicateFonts(); void downloadFonts(); void print(); void printGroup(); void listingPercent(int p); void refreshFontList(); void refreshFamilies(); void showInfo(const QString &info); void setStatusBar(); void addFonts(const QSet &src); private: void removeDeletedFontsFromGroups(); void selectGroup(CGroupListItem::EType grp); void print(bool all); void toggleGroup(bool enable); void toggleFonts(bool enable, const QString &grp=QString()); void toggleFonts(CJobRunner::ItemList &urls, const QStringList &fonts, bool enable, const QString &grp); void selectMainGroup(); void doCmd(CJobRunner::ECommand cmd, const CJobRunner::ItemList &urls, bool system=false); private: QSplitter *itsGroupSplitter, *itsPreviewSplitter; CFontPreview *itsPreview; CPreviewListView *itsPreviewList; KConfig itsConfig; QLabel *itsStatusLabel; CProgressBar *itsListingProgress; CFontList *itsFontList; CFontListView *itsFontListView; CGroupList *itsGroupList; CGroupListView *itsGroupListView; QPushButton *itsDeleteGroupControl, *itsEnableGroupControl, *itsDisableGroupControl, *itsAddFontControl, *itsGetNewFontsControl, - *itsDeleteFontControl; + *itsDeleteFontControl, + *itsScanDuplicateFontsControl; CFontFilter *itsFilter; QString itsLastStatusBarMsg; KIO::Job *itsJob; QProgressDialog *itsProgress; CUpdateDialog *itsUpdateDialog; QTemporaryDir *itsTempDir; QProcess *itsPrintProc; QSet itsDeletedFonts; QList itsModifiedUrls; CJobRunner *itsRunner; QMenu *itsPreviewMenu, *itsPreviewListMenu; - QAction *duplicateFontsAct; QWidget *itsPreviewWidget; bool itsPreviewHidden; }; } #endif diff --git a/kcms/kfontinst/viewpart/FontPreview.cpp b/kcms/kfontinst/viewpart/FontPreview.cpp index 4b296e61a..8517533c1 100644 --- a/kcms/kfontinst/viewpart/FontPreview.cpp +++ b/kcms/kfontinst/viewpart/FontPreview.cpp @@ -1,178 +1,178 @@ /* * 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 "FontPreview.h" #include "FcEngine.h" #include "CharTip.h" #include #include #include #include #include namespace KFI { static const int constBorder=4; static const int constStepSize=16; CFontPreview::CFontPreview(QWidget *parent) : QWidget(parent), itsCurrentFace(1), itsLastWidth(0), itsLastHeight(0), itsStyleInfo(KFI_NO_STYLE_INFO), itsTip(nullptr) { itsEngine=new CFcEngine; } CFontPreview::~CFontPreview() { delete itsTip; delete itsEngine; } void CFontPreview::showFont(const QString &name, unsigned long styleInfo, int face) { itsFontName=name; itsStyleInfo=styleInfo; showFace(face); } void CFontPreview::showFace(int face) { itsCurrentFace=face; showFont(); } void CFontPreview::showFont() { itsLastWidth=width()+constStepSize; itsLastHeight=height()+constStepSize; itsImage=itsEngine->draw(itsFontName, itsStyleInfo, itsCurrentFace, palette().text().color(), palette().base().color(), itsLastWidth, itsLastHeight, false, itsRange, &itsChars); if(!itsImage.isNull()) { itsLastChar=CFcEngine::TChar(); setMouseTracking(itsChars.count()>0); update(); emit status(true); emit atMax(itsEngine->atMax()); emit atMin(itsEngine->atMin()); } else { itsLastChar=CFcEngine::TChar(); setMouseTracking(false); update(); emit status(false); emit atMax(true); emit atMin(true); } } void CFontPreview::zoomIn() { itsEngine->zoomIn(); showFont(); emit atMax(itsEngine->atMax()); } void CFontPreview::zoomOut() { itsEngine->zoomOut(); showFont(); emit atMin(itsEngine->atMin()); } void CFontPreview::setUnicodeRange(const QList &r) { itsRange=r; showFont(); } void CFontPreview::paintEvent(QPaintEvent *) { QPainter paint(this); paint.fillRect(rect(), palette().base()); if(!itsImage.isNull()) { if(abs(width()-itsLastWidth)>constStepSize || abs(height()-itsLastHeight)>constStepSize) showFont(); else - paint.drawImage(QPoint(constBorder, constBorder), itsImage, - QRect(0, 0, width()-(constBorder*2) * itsImage.devicePixelRatioF(), - height()-(constBorder*2) * itsImage.devicePixelRatioF())); + paint.drawImage(QPointF(constBorder, constBorder), itsImage, + QRectF(0, 0, (width()-(constBorder*2)) * itsImage.devicePixelRatioF(), + (height()-(constBorder*2)) * itsImage.devicePixelRatioF())); } } void CFontPreview::mouseMoveEvent(QMouseEvent *event) { if(!itsChars.isEmpty()) { QList::ConstIterator end(itsChars.end()); if(itsLastChar.isNull() || !itsLastChar.contains(event->pos())) for(QList::ConstIterator it(itsChars.begin()); it!=end; ++it) if((*it).contains(event->pos())) { if(!itsTip) itsTip=new CCharTip(this); itsTip->setItem(*it); itsLastChar=*it; break; } } } void CFontPreview::wheelEvent(QWheelEvent *e) { if(e->delta()>0) zoomIn(); else if(e->delta()<0) zoomOut(); e->accept(); } QSize CFontPreview::sizeHint() const { return QSize(132, 132); } QSize CFontPreview::minimumSizeHint() const { return QSize(32, 32); } }