~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kcontrol/kfontinst/kcmfontinst/GroupList.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * KFontInst - KDE Font Installer
 
3
 *
 
4
 * Copyright 2003-2007 Craig Drummond <craig@kde.org>
 
5
 *
 
6
 * ----
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation; either version 2 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; see the file COPYING.  If not, write to
 
20
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
21
 * Boston, MA 02110-1301, USA.
 
22
 */
 
23
 
 
24
#include "GroupList.h"
 
25
#include "FontList.h"
 
26
#include <KDE/KGlobal>
 
27
#include <KDE/KStandardDirs>
 
28
#include <KDE/KLocale>
 
29
#include <KDE/KMimeType>
 
30
#include <KDE/KIconLoader>
 
31
#include <kde_file.h>
 
32
#include <KDE/KMessageBox>
 
33
#include <KDE/KSaveFile>
 
34
#include <QtGui/QFont>
 
35
#include <QtGui/QFontDatabase>
 
36
#include <QtGui/QDropEvent>
 
37
#include <QtGui/QHeaderView>
 
38
#include <QtGui/QMenu>
 
39
#include <QtGui/QApplication>
 
40
#include <QtGui/QStyledItemDelegate>
 
41
#include <QtGui/QPainter>
 
42
#include <QtGui/QLinearGradient>
 
43
#include <QtXml/QDomElement>
 
44
#include <QtCore/QTextStream>
 
45
#include <QtCore/QDir>
 
46
#include <QtCore/QEvent>
 
47
#include <stdlib.h>
 
48
#include <unistd.h>
 
49
#include <utime.h>
 
50
#include "FcEngine.h"
 
51
#include "Misc.h"
 
52
#include "KfiConstants.h"
 
53
#include <config-workspace.h>
 
54
 
 
55
namespace KFI
 
56
{
 
57
 
 
58
#define GROUPS_DOC "groups"
 
59
#define GROUP_TAG  "group"
 
60
#define NAME_ATTR  "name"
 
61
#define FAMILY_TAG "family"
 
62
 
 
63
enum EGroupColumns
 
64
{
 
65
    COL_GROUP_NAME,
 
66
 
 
67
    NUM_GROUP_COLS
 
68
};
 
69
 
 
70
CGroupListItem::CGroupListItem(const QString &name)
 
71
              : itsName(name),
 
72
                itsType(CUSTOM),
 
73
                itsHighlighted(false),
 
74
                itsStatus(CFamilyItem::ENABLED)
 
75
{
 
76
    itsData.validated=false;
 
77
}
 
78
 
 
79
CGroupListItem::CGroupListItem(EType type, CGroupList *p)
 
80
              : itsType(type),
 
81
                itsHighlighted(false),
 
82
                itsStatus(CFamilyItem::ENABLED)
 
83
{
 
84
    switch(itsType)
 
85
    {
 
86
        case ALL:
 
87
            itsName=i18n("All Fonts");
 
88
            break;
 
89
        case PERSONAL:
 
90
            itsName=i18n("Personal Fonts");
 
91
            break;
 
92
        case SYSTEM:
 
93
            itsName=i18n("System Fonts");
 
94
            break;
 
95
        default:
 
96
            itsName=i18n("Unclassified");
 
97
    }
 
98
    itsData.parent=p;
 
99
}
 
100
 
 
101
bool CGroupListItem::hasFont(const CFontItem *fnt) const
 
102
{
 
103
    switch(itsType)
 
104
    {
 
105
        case CUSTOM:
 
106
            return itsFamilies.contains(fnt->family());
 
107
        case PERSONAL:
 
108
            return !fnt->isSystem();
 
109
        case SYSTEM:
 
110
            return fnt->isSystem();
 
111
        case ALL:
 
112
            return true;
 
113
        case UNCLASSIFIED:
 
114
        {
 
115
            QList<CGroupListItem *>::ConstIterator it(itsData.parent->itsGroups.begin()),
 
116
                                                   end(itsData.parent->itsGroups.end());
 
117
 
 
118
            for(; it!=end; ++it)
 
119
                if((*it)->isCustom() && (*it)->families().contains(fnt->family()))
 
120
                    return false;
 
121
            return true;
 
122
        }
 
123
        default:
 
124
            return false;
 
125
    }
 
126
    return false;
 
127
}
 
128
 
 
129
void CGroupListItem::updateStatus(QSet<QString> &enabled, QSet<QString> &disabled, QSet<QString> &partial)
 
130
{
 
131
    QSet<QString> families(itsFamilies);
 
132
 
 
133
    if(0!=families.intersect(partial).count())
 
134
        itsStatus=CFamilyItem::PARTIAL;
 
135
    else
 
136
    {
 
137
        families=itsFamilies;
 
138
 
 
139
        bool haveEnabled(0!=families.intersect(enabled).count());
 
140
 
 
141
        families=itsFamilies;
 
142
 
 
143
        bool haveDisabled(0!=families.intersect(disabled).count());
 
144
 
 
145
        if(haveEnabled && haveDisabled)
 
146
            itsStatus=CFamilyItem::PARTIAL;
 
147
        else if(haveEnabled && !haveDisabled)
 
148
            itsStatus=CFamilyItem::ENABLED;
 
149
        else
 
150
            itsStatus=CFamilyItem::DISABLED;
 
151
    }
 
152
}
 
153
 
 
154
bool CGroupListItem::load(QDomElement &elem)
 
155
{
 
156
    if(elem.hasAttribute(NAME_ATTR))
 
157
    {
 
158
        itsName=elem.attribute(NAME_ATTR);
 
159
        addFamilies(elem);
 
160
        return true;
 
161
    }
 
162
    return false;
 
163
}
 
164
 
 
165
bool CGroupListItem::addFamilies(QDomElement &elem)
 
166
{
 
167
    int b4(itsFamilies.count());
 
168
 
 
169
    for(QDomNode n=elem.firstChild(); !n.isNull(); n=n.nextSibling())
 
170
    {
 
171
        QDomElement ent=n.toElement();
 
172
 
 
173
        if(FAMILY_TAG==ent.tagName())
 
174
            itsFamilies.insert(ent.text());
 
175
    }
 
176
    return b4!=itsFamilies.count();
 
177
}
 
178
 
 
179
void CGroupListItem::save(QTextStream &str)
 
180
{
 
181
    str << " <"GROUP_TAG" "NAME_ATTR"=\"" << Misc::encodeText(itsName, str) << "\">" << endl;
 
182
    if(itsFamilies.count())
 
183
    {
 
184
        QSet<QString>::ConstIterator it(itsFamilies.begin()),
 
185
                                     end(itsFamilies.end());
 
186
 
 
187
        for(; it!=end; ++it)
 
188
            str << "  <"FAMILY_TAG">" << Misc::encodeText(*it, str) << "</"FAMILY_TAG">" << endl;
 
189
    }
 
190
    str << " </"GROUP_TAG">" << endl;
 
191
}
 
192
 
 
193
CGroupList::CGroupList(QWidget *parent)
 
194
          : QAbstractItemModel(parent),
 
195
            itsTimeStamp(0),
 
196
            itsModified(false),
 
197
            itsParent(parent),
 
198
            itsSortOrder(Qt::AscendingOrder)
 
199
{
 
200
    itsSpecialGroups[CGroupListItem::ALL]=new CGroupListItem(CGroupListItem::ALL, this);
 
201
    itsGroups.append(itsSpecialGroups[CGroupListItem::ALL]);
 
202
    if(Misc::root())
 
203
        itsSpecialGroups[CGroupListItem::PERSONAL]=
 
204
        itsSpecialGroups[CGroupListItem::SYSTEM]=NULL;
 
205
    else
 
206
    {
 
207
        itsSpecialGroups[CGroupListItem::PERSONAL]=new CGroupListItem(CGroupListItem::PERSONAL, this);
 
208
        itsGroups.append(itsSpecialGroups[CGroupListItem::PERSONAL]);
 
209
        itsSpecialGroups[CGroupListItem::SYSTEM]=new CGroupListItem(CGroupListItem::SYSTEM, this);
 
210
        itsGroups.append(itsSpecialGroups[CGroupListItem::SYSTEM]);
 
211
    }
 
212
    itsSpecialGroups[CGroupListItem::UNCLASSIFIED]=
 
213
                new CGroupListItem(CGroupListItem::UNCLASSIFIED, this);
 
214
    itsGroups.append(itsSpecialGroups[CGroupListItem::UNCLASSIFIED]);
 
215
    // Locate groups.xml file - normall will be ~/.config/fontgroups.xml
 
216
    QString path(KGlobal::dirs()->localxdgconfdir());
 
217
 
 
218
    if(!Misc::dExists(path))
 
219
        Misc::createDir(path);
 
220
 
 
221
    itsFileName=path+'/'+KFI_GROUPS_FILE;
 
222
 
 
223
    rescan();
 
224
}
 
225
 
 
226
CGroupList::~CGroupList()
 
227
{
 
228
    save();
 
229
    qDeleteAll(itsGroups);
 
230
    itsGroups.clear();
 
231
}
 
232
 
 
233
int CGroupList::columnCount(const QModelIndex &) const
 
234
{
 
235
    return NUM_GROUP_COLS;
 
236
}
 
237
 
 
238
void CGroupList::update(const QModelIndex &unHighlight, const QModelIndex &highlight)
 
239
{
 
240
    if(unHighlight.isValid())
 
241
    {
 
242
        CGroupListItem *grp=static_cast<CGroupListItem *>(unHighlight.internalPointer());
 
243
        if(grp)
 
244
            grp->setHighlighted(false);
 
245
        emit dataChanged(unHighlight, unHighlight);
 
246
    }
 
247
    if(highlight.isValid())
 
248
    {
 
249
        CGroupListItem *grp=static_cast<CGroupListItem *>(highlight.internalPointer());
 
250
        if(grp)
 
251
            grp->setHighlighted(true);
 
252
        emit dataChanged(highlight, highlight);
 
253
    }
 
254
}
 
255
 
 
256
void CGroupList::updateStatus(QSet<QString> &enabled, QSet<QString> &disabled,
 
257
                              QSet<QString> &partial)
 
258
{
 
259
    QList<CGroupListItem *>::Iterator it(itsGroups.begin()),
 
260
                                      end(itsGroups.end());
 
261
 
 
262
    for(; it!=end; ++it)
 
263
        if((*it)->isCustom())
 
264
            (*it)->updateStatus(enabled, disabled, partial);
 
265
 
 
266
    emit layoutChanged();
 
267
}
 
268
 
 
269
inline QColor midColour(const QColor &a, const QColor &b)
 
270
{
 
271
    return QColor((a.red()+b.red())>>1, (a.green()+b.green())>>1, (a.blue()+b.blue())>>1);
 
272
}
 
273
 
 
274
QVariant CGroupList::data(const QModelIndex &index, int role) const
 
275
{
 
276
    if (!index.isValid())
 
277
        return QVariant();
 
278
 
 
279
    CGroupListItem *grp=static_cast<CGroupListItem *>(index.internalPointer());
 
280
 
 
281
    if(grp)
 
282
        switch(index.column())
 
283
        {
 
284
            case COL_GROUP_NAME:
 
285
                switch(role)
 
286
                {
 
287
                    case Qt::FontRole:
 
288
                        if(CGroupListItem::SYSTEM==grp->type())
 
289
                        {
 
290
                            QFont font;
 
291
                            font.setItalic(true);
 
292
                            return font;
 
293
                        }
 
294
                        break;
 
295
                    case Qt::SizeHintRole:
 
296
                        return SmallIcon("dialog-ok").size()+QSize(0, 4);
 
297
                    case Qt::EditRole:
 
298
                    case Qt::DisplayRole:
 
299
                        return grp->name();
 
300
                    case Qt::DecorationRole:
 
301
                        if(grp->highlighted())
 
302
                            switch(grp->type())
 
303
                            {
 
304
                                case CGroupListItem::ALL:      // Removing from a group
 
305
                                    return SmallIcon("list-remove");
 
306
                                case CGroupListItem::PERSONAL: // Copying/moving
 
307
                                case CGroupListItem::SYSTEM:   // Copying/moving
 
308
                                    return SmallIcon(Qt::LeftToRight==QApplication::layoutDirection()
 
309
                                                        ? "go-next" : "go-previous");
 
310
                                case CGroupListItem::CUSTOM:   // Adding to a group
 
311
                                    return SmallIcon("list-add");
 
312
                                default:
 
313
                                    break;
 
314
                            }
 
315
                        else
 
316
                            switch(grp->type())
 
317
                            {
 
318
                                case CGroupListItem::ALL:
 
319
                                    return SmallIcon("preferences-desktop-font");
 
320
                                case CGroupListItem::PERSONAL:
 
321
                                    return SmallIcon("user-identity");
 
322
                                case CGroupListItem::SYSTEM:
 
323
                                    return SmallIcon("computer");
 
324
                                case CGroupListItem::UNCLASSIFIED:
 
325
                                    return SmallIcon("fontstatus");
 
326
                                case CGroupListItem::CUSTOM:
 
327
                                    if(0==grp->families().count())
 
328
                                        return SmallIcon("image-missing");
 
329
                                    switch(grp->status())
 
330
                                    {
 
331
                                        case CFamilyItem::PARTIAL:
 
332
                                            return SmallIcon("dialog-ok", 0, KIconLoader::DisabledState);
 
333
                                        case CFamilyItem::ENABLED:
 
334
                                            return SmallIcon("dialog-ok");
 
335
                                        case CFamilyItem::DISABLED:
 
336
                                            return SmallIcon("dialog-cancel");
 
337
                                    }
 
338
                                    break;
 
339
                            }
 
340
                    default:
 
341
                        break;
 
342
                }
 
343
                break;
 
344
        }
 
345
    return QVariant();
 
346
}
 
347
 
 
348
bool CGroupList::setData(const QModelIndex &index, const QVariant &value, int role)
 
349
{
 
350
    if(Qt::EditRole==role && index.isValid())
 
351
    {
 
352
        QString name(value.toString().trimmed());
 
353
 
 
354
        if(!name.isEmpty())
 
355
        {
 
356
            CGroupListItem *grp=static_cast<CGroupListItem *>(index.internalPointer());
 
357
 
 
358
            if(grp && grp->isCustom() && grp->name()!=name && !exists(name, false))
 
359
            {
 
360
                grp->setName(name);
 
361
                itsModified=true;
 
362
                save();
 
363
                sort(0, itsSortOrder);
 
364
                return true;
 
365
            }
 
366
        }
 
367
    }
 
368
    return false;
 
369
}
 
370
 
 
371
Qt::ItemFlags CGroupList::flags(const QModelIndex &index) const
 
372
{
 
373
    if (!index.isValid())
 
374
        return Qt::ItemIsEnabled;
 
375
 
 
376
    CGroupListItem *grp=static_cast<CGroupListItem *>(index.internalPointer());
 
377
 
 
378
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled |
 
379
           (grp && grp->type()==CGroupListItem::CUSTOM ? Qt::ItemIsEditable : Qt::NoItemFlags);
 
380
}
 
381
 
 
382
QVariant CGroupList::headerData(int section, Qt::Orientation orientation, int role) const
 
383
{
 
384
    if (Qt::Horizontal==orientation && COL_GROUP_NAME==section)
 
385
        switch(role)
 
386
        {
 
387
            case Qt::DisplayRole:
 
388
                return i18n("Group");
 
389
            case Qt::TextAlignmentRole:
 
390
                return Qt::AlignLeft;
 
391
            case Qt::WhatsThisRole:
 
392
                return whatsThis();
 
393
            default:
 
394
                break;
 
395
        }
 
396
 
 
397
    return QVariant();
 
398
}
 
399
 
 
400
QModelIndex CGroupList::index(int row, int column, const QModelIndex &parent) const
 
401
{
 
402
    if(!parent.isValid())
 
403
    {
 
404
        CGroupListItem *grp=itsGroups.value(row);
 
405
 
 
406
        if(grp)
 
407
            return createIndex(row, column, grp);
 
408
    }
 
409
 
 
410
    return QModelIndex();
 
411
}
 
412
 
 
413
QModelIndex CGroupList::parent(const QModelIndex &) const
 
414
{
 
415
    return QModelIndex();
 
416
}
 
417
 
 
418
int CGroupList::rowCount(const QModelIndex &) const
 
419
{
 
420
    return itsGroups.count();
 
421
}
 
422
 
 
423
void CGroupList::rescan()
 
424
{
 
425
    save();
 
426
    load();
 
427
    sort(0, itsSortOrder);
 
428
}
 
429
 
 
430
void CGroupList::load()
 
431
{
 
432
    time_t ts=Misc::getTimeStamp(itsFileName);
 
433
 
 
434
    if(!ts || ts!=itsTimeStamp)
 
435
    {
 
436
        clear();
 
437
        itsTimeStamp=ts;
 
438
        if(load(itsFileName))
 
439
            itsModified=false;
 
440
    }
 
441
}
 
442
 
 
443
bool CGroupList::load(const QString &file)
 
444
{
 
445
    QFile f(file);
 
446
    bool  rv(false);
 
447
 
 
448
    if(f.open(QIODevice::ReadOnly))
 
449
    {
 
450
        QDomDocument doc;
 
451
 
 
452
        if(doc.setContent(&f))
 
453
            for(QDomNode n=doc.documentElement().firstChild(); !n.isNull(); n=n.nextSibling())
 
454
            {
 
455
                QDomElement e=n.toElement();
 
456
 
 
457
                if(GROUP_TAG==e.tagName() && e.hasAttribute(NAME_ATTR))
 
458
                {
 
459
                    QString name(e.attribute(NAME_ATTR));
 
460
 
 
461
                    CGroupListItem *item=find(name);
 
462
 
 
463
                    if(!item)
 
464
                    {
 
465
                        item=new CGroupListItem(name);
 
466
                        itsGroups.append(item);
 
467
                        rv=true;
 
468
                    }
 
469
 
 
470
                    if(item->addFamilies(e))
 
471
                        rv=true;
 
472
                }
 
473
            }
 
474
    }
 
475
    return rv;
 
476
}
 
477
 
 
478
bool CGroupList::save()
 
479
{
 
480
    if(itsModified && save(itsFileName, NULL))
 
481
    {
 
482
        itsTimeStamp=Misc::getTimeStamp(itsFileName);
 
483
        return true;
 
484
    }
 
485
    return false;
 
486
}
 
487
 
 
488
bool CGroupList::save(const QString &fileName, CGroupListItem *grp)
 
489
{
 
490
    KSaveFile file(fileName);
 
491
 
 
492
    if(file.open())
 
493
    {
 
494
        QTextStream str(&file);
 
495
 
 
496
        str << "<"GROUPS_DOC">" << endl;
 
497
 
 
498
        if(grp)
 
499
            grp->save(str);
 
500
        else
 
501
        {
 
502
            QList<CGroupListItem *>::Iterator it(itsGroups.begin()),
 
503
                                              end(itsGroups.end());
 
504
 
 
505
            for(; it!=end; ++it)
 
506
                if((*it)->isCustom())
 
507
                    (*it)->save(str);
 
508
        }
 
509
        str << "</"GROUPS_DOC">" << endl;
 
510
        itsModified=false;
 
511
        return file.finalize();
 
512
    }
 
513
 
 
514
    return false;
 
515
}
 
516
 
 
517
void CGroupList::merge(const QString &file)
 
518
{
 
519
    if(load(file))
 
520
    {
 
521
        itsModified=true;
 
522
        sort(0, itsSortOrder);
 
523
    }
 
524
}
 
525
 
 
526
void CGroupList::clear()
 
527
{
 
528
    beginRemoveRows(QModelIndex(), 0, itsGroups.count());
 
529
    endRemoveRows();
 
530
    itsGroups.removeFirst(); // Remove all
 
531
    if(itsSpecialGroups[CGroupListItem::SYSTEM])
 
532
    {
 
533
        itsGroups.removeFirst(); // Remove personal
 
534
        itsGroups.removeFirst(); // Remove system
 
535
    }
 
536
    itsGroups.removeFirst(); // Remove unclassif...
 
537
    qDeleteAll(itsGroups);
 
538
    itsGroups.clear();
 
539
    itsGroups.append(itsSpecialGroups[CGroupListItem::ALL]);
 
540
    if(itsSpecialGroups[CGroupListItem::SYSTEM])
 
541
    {
 
542
        itsGroups.append(itsSpecialGroups[CGroupListItem::PERSONAL]);
 
543
        itsGroups.append(itsSpecialGroups[CGroupListItem::SYSTEM]);
 
544
    }
 
545
    itsGroups.append(itsSpecialGroups[CGroupListItem::UNCLASSIFIED]);
 
546
}
 
547
 
 
548
QModelIndex CGroupList::index(CGroupListItem::EType t)
 
549
{
 
550
    return createIndex(t, 0, itsSpecialGroups[t]);
 
551
}
 
552
 
 
553
void CGroupList::createGroup(const QString &name)
 
554
{
 
555
    if(!exists(name))
 
556
    {
 
557
        itsGroups.append(new CGroupListItem(name));
 
558
        itsModified=true;
 
559
        save();
 
560
        sort(0, itsSortOrder);
 
561
    }
 
562
}
 
563
 
 
564
bool CGroupList::removeGroup(const QModelIndex &idx)
 
565
{
 
566
    if(idx.isValid())
 
567
    {
 
568
        CGroupListItem *grp=static_cast<CGroupListItem *>(idx.internalPointer());
 
569
 
 
570
        if(grp && grp->isCustom() &&
 
571
           KMessageBox::Yes==KMessageBox::warningYesNo(itsParent,
 
572
                                          i18n("<p>Do you really want to remove \'<b>%1</b>\'?</p>"
 
573
                                               "<p><i>This will only remove the group, and not "
 
574
                                               "the actual fonts.</i></p>", grp->name()),
 
575
                                          i18n("Remove Group"), KGuiItem(i18n("Remove"), "list-remove",
 
576
                                          i18n("Remove group"))))
 
577
        {
 
578
            itsModified=true;
 
579
            itsGroups.removeAll(grp);
 
580
            delete grp;
 
581
            save();
 
582
            sort(0, itsSortOrder);
 
583
            return true;
 
584
        }
 
585
    }
 
586
 
 
587
    return false;
 
588
}
 
589
 
 
590
void CGroupList::removeFromGroup(const QModelIndex &group, const QSet<QString> &families)
 
591
{
 
592
    if(group.isValid())
 
593
    {
 
594
        CGroupListItem *grp=static_cast<CGroupListItem *>(group.internalPointer());
 
595
 
 
596
        if(grp && grp->isCustom())
 
597
        {
 
598
            QSet<QString>::ConstIterator it(families.begin()),
 
599
                                         end(families.end());
 
600
            bool                         update(false);
 
601
 
 
602
            for(; it!=end; ++it)
 
603
                if(removeFromGroup(grp, *it))
 
604
                    update=true;
 
605
 
 
606
            if(update)
 
607
                emit refresh();
 
608
        }
 
609
    }
 
610
}
 
611
 
 
612
QString CGroupList::whatsThis() const
 
613
{
 
614
    return i18n("<h3>Font Groups</h3><p>This list displays the font groups available on your system. "
 
615
                                       "There are 2 main types of font groups:"
 
616
               "<ul><li><b>Standard</b> are special groups used by the font manager.<ul>%1</ul></li>"
 
617
                   "<li><b>Custom</b> are groups created by you. To add a font family to one of "
 
618
                                     "these groups simply drag it from the list of fonts, and drop "
 
619
                                     "onto the desired group. To remove a family from the group, drag "
 
620
                                     "the font onto the \"All Fonts\" group.</li>"
 
621
                   "</ul></p>",
 
622
                Misc::root()
 
623
                    ? i18n("<li><i>All Fonts</i> contains all the fonts installed on your system.</li>"
 
624
                            "<li><i>Unclassified</i> contains all fonts that have not yet been placed "
 
625
                                                    "within a \"Custom\" group.</li>")
 
626
                    : i18n("<li><i>All Fonts</i> contains all the fonts installed on your system - "
 
627
                                                "both  \"System\" and \"Personal\".</li>"
 
628
                            "<li><i>System</i> contains all fonts that are installed system-wide (i.e. "
 
629
                                            "available to all users).</li>"
 
630
                            "<li><i>Personal</i> contains your personal fonts.</li>"
 
631
                            "<li><i>Unclassified</i> contains all fonts that have not yet been placed "
 
632
                                                    "within a \"Custom\" group.</li>"));
 
633
}
 
634
 
 
635
void CGroupList::addToGroup(const QModelIndex &group, const QSet<QString> &families)
 
636
{
 
637
    if(group.isValid())
 
638
    {
 
639
        CGroupListItem *grp=static_cast<CGroupListItem *>(group.internalPointer());
 
640
 
 
641
        if(grp && grp->isCustom())
 
642
        {
 
643
            QSet<QString>::ConstIterator it(families.begin()),
 
644
                                         end(families.end());
 
645
            bool                         update(false);
 
646
 
 
647
            for(; it!=end; ++it)
 
648
                if(!grp->hasFamily(*it))
 
649
                {
 
650
                    grp->addFamily(*it);
 
651
                    update=true;
 
652
                    itsModified=true;
 
653
                }
 
654
 
 
655
            if(update)
 
656
                emit refresh();
 
657
        }
 
658
    }
 
659
}
 
660
 
 
661
void CGroupList::removeFamily(const QString &family)
 
662
{
 
663
    QList<CGroupListItem *>::ConstIterator it(itsGroups.begin()),
 
664
                                           end(itsGroups.end());
 
665
 
 
666
    for(; it!=end; ++it)
 
667
        removeFromGroup(*it, family);
 
668
}
 
669
 
 
670
bool CGroupList::removeFromGroup(CGroupListItem *grp, const QString &family)
 
671
{
 
672
    if(grp && grp->isCustom() && grp->hasFamily(family))
 
673
    {
 
674
        grp->removeFamily(family);
 
675
        itsModified=true;
 
676
        return true;
 
677
    }
 
678
 
 
679
    return false;
 
680
}
 
681
 
 
682
static bool groupNameLessThan(const CGroupListItem *f1, const CGroupListItem *f2)
 
683
{
 
684
    return f1 && f2 && (f1->type()<f2->type() ||
 
685
                       (f1->type()==f2->type() && QString::localeAwareCompare(f1->name(), f2->name())<0));
 
686
}
 
687
 
 
688
static bool groupNameGreaterThan(const CGroupListItem *f1, const CGroupListItem *f2)
 
689
{
 
690
    return f1 && f2 && (f1->type()<f2->type() ||
 
691
                       (f1->type()==f2->type() && QString::localeAwareCompare(f1->name(), f2->name())>0));
 
692
}
 
693
 
 
694
void CGroupList::sort(int, Qt::SortOrder order)
 
695
{
 
696
    itsSortOrder=order;
 
697
 
 
698
    qSort(itsGroups.begin(), itsGroups.end(),
 
699
          Qt::AscendingOrder==order ? groupNameLessThan : groupNameGreaterThan);
 
700
 
 
701
    emit layoutChanged();
 
702
}
 
703
 
 
704
Qt::DropActions CGroupList::supportedDropActions() const
 
705
{
 
706
    return Qt::CopyAction | Qt::MoveAction;
 
707
}
 
708
 
 
709
QStringList CGroupList::mimeTypes() const
 
710
{
 
711
    QStringList types;
 
712
    types << KFI_FONT_DRAG_MIME;
 
713
    return types;
 
714
}
 
715
 
 
716
CGroupListItem * CGroupList::find(const QString &name)
 
717
{
 
718
    QList<CGroupListItem *>::ConstIterator it(itsGroups.begin()),
 
719
                                           end(itsGroups.end());
 
720
 
 
721
    for(; it!=end; ++it)
 
722
        if((*it)->name()==name)
 
723
            return (*it);
 
724
 
 
725
    return NULL;
 
726
}
 
727
 
 
728
bool CGroupList::exists(const QString &name, bool showDialog)
 
729
{
 
730
    if(NULL!=find(name))
 
731
    {
 
732
        if(showDialog)
 
733
            KMessageBox::error(itsParent, i18n("<qt>A group named <b>\'%1\'</b> already "
 
734
                                               "exists.</qt>", name));
 
735
        return true;
 
736
    }
 
737
 
 
738
    return false;
 
739
}
 
740
 
 
741
class CGroupListViewDelegate : public QStyledItemDelegate
 
742
{
 
743
    public:
 
744
 
 
745
    CGroupListViewDelegate(QObject *p) : QStyledItemDelegate(p) { }
 
746
    virtual ~CGroupListViewDelegate() { }
 
747
 
 
748
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &idx) const
 
749
    {
 
750
        CGroupListItem       *grp=static_cast<CGroupListItem *>(idx.internalPointer());
 
751
        QStyleOptionViewItem opt(option);
 
752
 
 
753
        if(grp && grp->isUnclassified())
 
754
            opt.rect.adjust(0, 0, 0, -1);
 
755
            
 
756
        QStyledItemDelegate::paint(painter, opt, idx);
 
757
 
 
758
        if(grp && grp->isUnclassified())
 
759
        {
 
760
            opt.rect.adjust(2, 0, -2, 1);
 
761
            painter->setPen(QApplication::palette().color(QPalette::Text));
 
762
            painter->drawLine(opt.rect.bottomLeft(), opt.rect.bottomRight());
 
763
        }
 
764
    }
 
765
 
 
766
    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &idx) const
 
767
    {
 
768
        QSize sz(QStyledItemDelegate::sizeHint(option, idx));
 
769
 
 
770
        CGroupListItem *grp=static_cast<CGroupListItem *>(idx.internalPointer());
 
771
 
 
772
        if(grp && grp->isUnclassified())
 
773
            sz.setHeight(sz.height()+1);
 
774
        return sz;
 
775
    }
 
776
 
 
777
    static bool isCloseEvent(QKeyEvent *event)
 
778
    {
 
779
        return Qt::Key_Tab==event->key() || Qt::Key_Backtab==event->key() ||
 
780
               Qt::Key_Enter==event->key() || Qt::Key_Return==event->key();
 
781
    }
 
782
    
 
783
    bool eventFilter(QObject *editor, QEvent *event)
 
784
    {
 
785
        if(editor && event && QEvent::KeyPress==event->type() && isCloseEvent(static_cast<QKeyEvent *>(event)) &&
 
786
           qobject_cast<QLineEdit *>(editor))
 
787
        {
 
788
            QString text=static_cast<QLineEdit *>(editor)->text().trimmed();
 
789
            if(!text.isEmpty() &&
 
790
               !static_cast<CGroupList *>(static_cast<CGroupListView *>(parent())->model())->exists(text, false))
 
791
            {
 
792
                emit commitData(static_cast<QWidget *>(editor));
 
793
                emit closeEditor(static_cast<QWidget *>(editor));
 
794
                return true;
 
795
            }
 
796
        }
 
797
        return false;
 
798
    }
 
799
};
 
800
                                     
 
801
CGroupListView::CGroupListView(QWidget *parent, CGroupList *model)
 
802
              : QTreeView(parent)
 
803
{
 
804
    setModel(model);
 
805
    setItemDelegate(new CGroupListViewDelegate(this));
 
806
    sortByColumn(COL_GROUP_NAME, Qt::AscendingOrder);
 
807
    setSelectionMode(QAbstractItemView::SingleSelection);
 
808
    setSortingEnabled(true);
 
809
    setAllColumnsShowFocus(true);
 
810
    setAlternatingRowColors(true);
 
811
    setAcceptDrops(true);
 
812
    setDragDropMode(QAbstractItemView::DropOnly);
 
813
    setDropIndicatorShown(true);
 
814
    setDragEnabled(false);
 
815
    header()->setSortIndicatorShown(true);
 
816
    setRootIsDecorated(false);
 
817
    itsMenu=new QMenu(this);
 
818
 
 
819
    itsDeleteAct=itsMenu->addAction(KIcon("list-remove"), i18n("Remove"),
 
820
                                    this, SIGNAL(del()));
 
821
    itsEnableAct=itsMenu->addAction(KIcon("enablefont"), i18n("Enable"),
 
822
                                    this, SIGNAL(enable()));
 
823
    itsDisableAct=itsMenu->addAction(KIcon("disablefont"), i18n("Disable"),
 
824
                                     this, SIGNAL(disable()));
 
825
    itsMenu->addSeparator();
 
826
    itsRenameAct=itsMenu->addAction(i18n("Rename..."), this, SLOT(rename()));
 
827
    itsMenu->addSeparator();
 
828
    itsPrintAct=itsMenu->addAction(KIcon("document-print"), i18n("Print..."),
 
829
                                   this, SIGNAL(print()));
 
830
    itsMenu->addSeparator();
 
831
    itsExportAct=itsMenu->addAction(KIcon("document-export"), i18n("Export..."),
 
832
                                    this, SIGNAL(zip()));
 
833
 
 
834
    itsActionMenu=new QMenu(this);
 
835
    itsActionMenu->addAction(KIcon("go-jump"), i18n("Move Here"), this, SIGNAL(moveFonts()));
 
836
    itsActionMenu->addSeparator();
 
837
    itsActionMenu->addAction(KIcon("process-stop"), i18n("Cancel"));
 
838
 
 
839
    setWhatsThis(model->whatsThis());
 
840
    header()->setWhatsThis(whatsThis());
 
841
    connect(this, SIGNAL(addFamilies(const QModelIndex &,  const QSet<QString> &)),
 
842
            model, SLOT(addToGroup(const QModelIndex &,  const QSet<QString> &)));
 
843
    connect(this, SIGNAL(removeFamilies(const QModelIndex &,  const QSet<QString> &)),
 
844
            model, SLOT(removeFromGroup(const QModelIndex &,  const QSet<QString> &)));
 
845
}
 
846
 
 
847
CGroupListItem::EType CGroupListView::getType()
 
848
{
 
849
    QModelIndexList selectedItems(selectedIndexes());
 
850
 
 
851
    if(selectedItems.count() && selectedItems.last().isValid())
 
852
    {
 
853
        CGroupListItem *grp=static_cast<CGroupListItem *>(selectedItems.last().internalPointer());
 
854
 
 
855
        return grp->type();
 
856
    }
 
857
 
 
858
    return CGroupListItem::ALL;
 
859
}
 
860
 
 
861
void CGroupListView::controlMenu(bool del, bool en, bool dis, bool p, bool exp)
 
862
{
 
863
    itsDeleteAct->setEnabled(del);
 
864
    itsRenameAct->setEnabled(del);
 
865
    itsEnableAct->setEnabled(en);
 
866
    itsDisableAct->setEnabled(dis);
 
867
    itsPrintAct->setEnabled(p);
 
868
    itsExportAct->setEnabled(exp);
 
869
}
 
870
 
 
871
void CGroupListView::selectionChanged(const QItemSelection &selected,
 
872
                                      const QItemSelection &deselected)
 
873
{
 
874
    QModelIndexList deselectedItems(deselected.indexes());
 
875
 
 
876
    QAbstractItemView::selectionChanged(selected, deselected);
 
877
 
 
878
    QModelIndexList selectedItems(selectedIndexes());
 
879
 
 
880
    if(0==selectedItems.count() && 1==deselectedItems.count())
 
881
        selectionModel()->select(deselectedItems.last(), QItemSelectionModel::Select);
 
882
    else
 
883
        emit itemSelected(selectedItems.count()
 
884
                            ? selectedItems.last()
 
885
                            : QModelIndex());
 
886
}
 
887
 
 
888
void CGroupListView::rename()
 
889
{
 
890
    QModelIndex index(currentIndex());
 
891
 
 
892
    if(index.isValid())
 
893
        edit(index);
 
894
}
 
895
 
 
896
void CGroupListView::contextMenuEvent(QContextMenuEvent *ev)
 
897
{
 
898
    if(indexAt(ev->pos()).isValid())
 
899
        itsMenu->popup(ev->globalPos());
 
900
}
 
901
 
 
902
void CGroupListView::dragEnterEvent(QDragEnterEvent *event)
 
903
{
 
904
    if(event->provides(KFI_FONT_DRAG_MIME))
 
905
        event->acceptProposedAction();
 
906
}
 
907
 
 
908
void CGroupListView::dragMoveEvent(QDragMoveEvent *event)
 
909
{
 
910
    if(event->provides(KFI_FONT_DRAG_MIME))
 
911
    {
 
912
        QModelIndex index(indexAt(event->pos()));
 
913
 
 
914
        if(index.isValid())
 
915
        {
 
916
            if(COL_GROUP_NAME!=index.column())
 
917
                index=((CGroupList *)model())->createIdx(index.row(), COL_GROUP_NAME, index.internalPointer());
 
918
 
 
919
            CGroupListItem        *dest=static_cast<CGroupListItem *>(index.internalPointer());
 
920
            CGroupListItem::EType type=getType();
 
921
 
 
922
            if(dest)
 
923
                if(!selectedIndexes().contains(index))
 
924
                {
 
925
                    bool ok(true);
 
926
 
 
927
                    if(dest->isCustom())
 
928
                        emit info(i18n("Add to \"%1\".", dest->name()));
 
929
                    else if(CGroupListItem::CUSTOM==type && dest->isAll())
 
930
                        emit info(i18n("Remove from current group."));
 
931
                    else if(!Misc::root() && dest->isPersonal() && CGroupListItem::SYSTEM==type)
 
932
                        emit info(i18n("Move to personal folder."));
 
933
                    else if(!Misc::root() && dest->isSystem() && CGroupListItem::PERSONAL==type)
 
934
                        emit info(i18n("Move to system folder."));
 
935
                    else
 
936
                        ok=false;
 
937
 
 
938
                    if(ok)
 
939
                    {
 
940
                        drawHighlighter(index);
 
941
                        event->acceptProposedAction();
 
942
                        return;
 
943
                    }
 
944
                }
 
945
        }
 
946
        event->ignore();
 
947
        drawHighlighter(QModelIndex());
 
948
        emit info(QString());
 
949
    }
 
950
}
 
951
 
 
952
void CGroupListView::dragLeaveEvent(QDragLeaveEvent *)
 
953
{
 
954
    drawHighlighter(QModelIndex());
 
955
    emit info(QString());
 
956
}
 
957
 
 
958
void CGroupListView::dropEvent(QDropEvent *event)
 
959
{
 
960
    emit info(QString());
 
961
    drawHighlighter(QModelIndex());
 
962
    if(event->provides(KFI_FONT_DRAG_MIME))
 
963
    {
 
964
        event->acceptProposedAction();
 
965
 
 
966
        QSet<QString> families;
 
967
        QByteArray    encodedData(event->mimeData()->data(KFI_FONT_DRAG_MIME));
 
968
        QDataStream   ds(&encodedData, QIODevice::ReadOnly);
 
969
        QModelIndex   from(selectedIndexes().last()),
 
970
                      to(indexAt(event->pos()));
 
971
 
 
972
        ds >> families;
 
973
        // Are we mvoeing/copying, removing a font from the current group?
 
974
        if(to.isValid() && from.isValid())
 
975
        {
 
976
            if( ((static_cast<CGroupListItem *>(from.internalPointer()))->isSystem() &&
 
977
                 (static_cast<CGroupListItem *>(to.internalPointer()))->isPersonal()) ||
 
978
                ((static_cast<CGroupListItem *>(from.internalPointer()))->isPersonal() &&
 
979
                 (static_cast<CGroupListItem *>(to.internalPointer()))->isSystem()))
 
980
                itsActionMenu->popup(QCursor::pos());
 
981
            else if((static_cast<CGroupListItem *>(from.internalPointer()))->isCustom() &&
 
982
                    !(static_cast<CGroupListItem *>(to.internalPointer()))->isCustom())
 
983
                emit removeFamilies(from, families);
 
984
            else
 
985
                emit addFamilies(to, families);
 
986
        }
 
987
 
 
988
        if(isUnclassified())
 
989
            emit unclassifiedChanged();
 
990
    }
 
991
}
 
992
 
 
993
void CGroupListView::drawHighlighter(const QModelIndex &idx)
 
994
{
 
995
    if(itsCurrentDropItem!=idx)
 
996
    {
 
997
        ((CGroupList *)model())->update(itsCurrentDropItem, idx);
 
998
        itsCurrentDropItem=idx;
 
999
    }
 
1000
}
 
1001
 
 
1002
bool CGroupListView::viewportEvent(QEvent *event)
 
1003
{
 
1004
    executeDelayedItemsLayout();
 
1005
    return QTreeView::viewportEvent(event);
 
1006
}
 
1007
 
 
1008
}
 
1009
 
 
1010
#include "GroupList.moc"