You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

973 lines
30 KiB

/*
SPDX-FileCopyrightText: 2003-2007 Craig Drummond <craig@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "GroupList.h"
#include "FcEngine.h"
#include "KfiConstants.h"
#include "Misc.h"
#include <KIconLoader>
#include <KMessageBox>
#include <QApplication>
#include <QDomElement>
#include <QDropEvent>
#include <QEvent>
#include <QFont>
#include <QHeaderView>
#include <QMenu>
#include <QMimeData>
#include <QPainter>
#include <QSaveFile>
#include <QStandardPaths>
#include <QStyledItemDelegate>
#include <QTextStream>
#include <QTimer>
#include <stdlib.h>
#include <unistd.h>
#include <utime.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<CGroupListItem *>::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<QString> &enabled, QSet<QString> &disabled, QSet<QString> &partial)
{
QSet<QString> 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) << "\">" << Qt::endl;
if (!itsFamilies.isEmpty()) {
QSet<QString>::ConstIterator it(itsFamilies.begin()), end(itsFamilies.end());
for (; it != end; ++it) {
str << " <" FAMILY_TAG ">" << Misc::encodeText(*it, str) << "</" FAMILY_TAG ">" << Qt::endl;
}
}
str << " </" GROUP_TAG ">" << Qt::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<CGroupListItem *>(unHighlight.internalPointer());
if (grp) {
grp->setHighlighted(false);
}
emit dataChanged(unHighlight, unHighlight);
}
if (highlight.isValid()) {
CGroupListItem *grp = static_cast<CGroupListItem *>(highlight.internalPointer());
if (grp) {
grp->setHighlighted(true);
}
emit dataChanged(highlight, highlight);
}
}
void CGroupList::updateStatus(QSet<QString> &enabled, QSet<QString> &disabled, QSet<QString> &partial)
{
QList<CGroupListItem *>::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<CGroupListItem *>(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 QIcon::fromTheme("list-remove");
case CGroupListItem::PERSONAL: // Copying/moving
case CGroupListItem::SYSTEM: // Copying/moving
return QIcon::fromTheme(Qt::LeftToRight == QApplication::layoutDirection() ? "go-next" : "go-previous");
case CGroupListItem::CUSTOM: // Adding to a group
return QIcon::fromTheme("list-add");
default:
break;
}
} else {
switch (grp->type()) {
case CGroupListItem::ALL:
return QIcon::fromTheme("font");
case CGroupListItem::PERSONAL:
return QIcon::fromTheme("user-identity");
case CGroupListItem::SYSTEM:
return QIcon::fromTheme("computer");
case CGroupListItem::UNCLASSIFIED:
return QIcon::fromTheme("fontstatus");
case CGroupListItem::CUSTOM:
if (0 == grp->families().count()) {
return QIcon::fromTheme("image-missing");
}
switch (grp->status()) {
case CFamilyItem::PARTIAL:
return QIcon::fromTheme("dialog-ok");
case CFamilyItem::ENABLED:
return QIcon::fromTheme("dialog-ok");
case CFamilyItem::DISABLED:
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<CGroupListItem *>(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<CGroupListItem *>(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 ">" << Qt::endl;
if (grp) {
grp->save(str);
} else {
QList<CGroupListItem *>::Iterator it(itsGroups.begin()), end(itsGroups.end());
for (; it != end; ++it) {
if ((*it)->isCustom()) {
(*it)->save(str);
}
}
}
str << "</" GROUPS_DOC ">" << Qt::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<CGroupListItem *>(idx.internalPointer());
if (grp && grp->isCustom()
&& KMessageBox::Continue
== KMessageBox::warningContinueCancel(itsParent,
i18n("<p>Do you really want to remove \'<b>%1</b>\'?</p>"
"<p><i>This will only remove the group, and not "
"the actual fonts.</i></p>",
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<QString> &families)
{
if (group.isValid()) {
CGroupListItem *grp = static_cast<CGroupListItem *>(group.internalPointer());
if (grp && grp->isCustom()) {
QSet<QString>::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(
"<h3>Font Groups</h3><p>This list displays the font groups available on your system. "
"There are 2 main types of font groups:"
"<ul><li><b>Standard</b> are special groups used by the font manager.<ul>%1</ul></li>"
"<li><b>Custom</b> 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.</li>"
"</ul></p>",
Misc::root() ? i18n("<li><i>All Fonts</i> contains all the fonts installed on your system.</li>"
"<li><i>Unclassified</i> contains all fonts that have not yet been placed "
"within a \"Custom\" group.</li>")
: i18n("<li><i>All Fonts</i> contains all the fonts installed on your system - "
"both \"System\" and \"Personal\".</li>"
"<li><i>System</i> contains all fonts that are installed system-wide (i.e. "
"available to all users).</li>"
"<li><i>Personal</i> contains your personal fonts.</li>"
"<li><i>Unclassified</i> contains all fonts that have not yet been placed "
"within a \"Custom\" group.</li>"));
}
void CGroupList::addToGroup(const QModelIndex &group, const QSet<QString> &families)
{
if (group.isValid()) {
CGroupListItem *grp = static_cast<CGroupListItem *>(group.internalPointer());
if (grp && grp->isCustom()) {
QSet<QString>::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<CGroupListItem *>::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() < f2->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() < f2->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<CGroupListItem *>::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("<qt>A group named <b>\'%1\'</b> already "
"exists.</qt>",
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<CGroupListItem *>(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<CGroupListItem *>(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<QKeyEvent *>(event)) && qobject_cast<QLineEdit *>(editor)) {
QString text = static_cast<QLineEdit *>(editor)->text().trimmed();
if (!text.isEmpty() && !static_cast<CGroupList *>(static_cast<CGroupListView *>(parent())->model())->exists(text, false)) {
emit commitData(static_cast<QWidget *>(editor));
emit closeEditor(static_cast<QWidget *>(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, &CGroupListView::del);
itsMenu->addSeparator();
itsEnableAct = itsMenu->addAction(QIcon::fromTheme("font-enable"), i18n("Enable"), this, &CGroupListView::enable);
itsDisableAct = itsMenu->addAction(QIcon::fromTheme("font-disable"), i18n("Disable"), this, &CGroupListView::disable);
itsMenu->addSeparator();
itsRenameAct = itsMenu->addAction(QIcon::fromTheme("edit-rename"), i18n("Rename…"), this, &CGroupListView::rename);
if (!Misc::app(KFI_PRINTER).isEmpty()) {
itsMenu->addSeparator();
itsPrintAct = itsMenu->addAction(QIcon::fromTheme("document-print"), i18n("Print…"), this, &CGroupListView::print);
} else {
itsPrintAct = nullptr;
}
itsMenu->addSeparator();
itsExportAct = itsMenu->addAction(QIcon::fromTheme("document-export"), i18n("Export…"), this, &CGroupListView::zip);
setWhatsThis(model->whatsThis());
header()->setWhatsThis(whatsThis());
connect(this, &CGroupListView::addFamilies, model, &CGroupList::addToGroup);
connect(this, SIGNAL(removeFamilies(QModelIndex, QSet<QString>)), model, SLOT(removeFromGroup(QModelIndex, QSet<QString>)));
}
CGroupListItem::EType CGroupListView::getType()
{
QModelIndexList selectedItems(selectedIndexes());
if (!selectedItems.isEmpty() && selectedItems.last().isValid()) {
CGroupListItem *grp = static_cast<CGroupListItem *>(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<CGroupListItem *>(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<QString> 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<CGroupListItem *>(from.internalPointer()))->isSystem() && (static_cast<CGroupListItem *>(to.internalPointer()))->isPersonal())
|| ((static_cast<CGroupListItem *>(from.internalPointer()))->isPersonal()
&& (static_cast<CGroupListItem *>(to.internalPointer()))->isSystem())) {
QTimer::singleShot(0, this, &CGroupListView::emitMoveFonts);
} else if ((static_cast<CGroupListItem *>(from.internalPointer()))->isCustom()
&& !(static_cast<CGroupListItem *>(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);
}
}