~ubuntu-branches/ubuntu/vivid/kate/vivid-proposed

« back to all changes in this revision

Viewing changes to addons/filetree/katefiletreemodel.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2014-12-04 16:49:41 UTC
  • mfrom: (1.6.6)
  • Revision ID: package-import@ubuntu.com-20141204164941-l3qbvsly83hhlw2v
Tags: 4:14.11.97-0ubuntu1
* New upstream release
* Update build-deps and use pkg-kde v3 for Qt 5 build
* kate-data now kate5-data for co-installability

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the KDE project
 
2
   Copyright (C) 2010 Thomas Fjellstrom <thomas@fjellstrom.ca>
 
3
 
 
4
   This library is free software; you can redistribute it and/or
 
5
   modify it under the terms of the GNU Library General Public
 
6
   License as published by the Free Software Foundation; either
 
7
   version 2 of the License, or (at your option) any later version.
 
8
 
 
9
   This library is distributed in the hope that it will be useful,
 
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
   Library General Public License for more details.
 
13
 
 
14
   You should have received a copy of the GNU Library General Public License
 
15
   along with this library; see the file COPYING.LIB.  If not, write to
 
16
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
17
   Boston, MA 02110-1301, USA.
 
18
*/
 
19
 
 
20
#include "katefiletreemodel.h"
 
21
 
 
22
#include <QDir>
 
23
#include <QFileInfo>
 
24
#include <QList>
 
25
#include <QMimeDatabase>
 
26
#include <QIcon>
 
27
#include <QStack>
 
28
 
 
29
#include <KColorScheme>
 
30
#include <KColorUtils>
 
31
#include <KLocalizedString>
 
32
#include <kiconutils.h>
 
33
 
 
34
#include <ktexteditor/document.h>
 
35
#include <ktexteditor/editor.h>
 
36
#include <ktexteditor/application.h>
 
37
 
 
38
#include "katefiletreedebug.h"
 
39
 
 
40
class ProxyItemDir;
 
41
class ProxyItem
 
42
{
 
43
    friend class KateFileTreeModel;
 
44
 
 
45
public:
 
46
    enum Flag { None = 0, Dir = 1, Modified = 2, ModifiedExternally = 4, DeletedExternally = 8, Empty = 16, ShowFullPath = 32, Host = 64 };
 
47
    Q_DECLARE_FLAGS(Flags, Flag)
 
48
 
 
49
    ProxyItem(const QString &n, ProxyItemDir *p = 0, Flags f = ProxyItem::None);
 
50
    ~ProxyItem();
 
51
 
 
52
    int addChild(ProxyItem *p);
 
53
    void remChild(ProxyItem *p);
 
54
 
 
55
    ProxyItemDir *parent() const;
 
56
 
 
57
    ProxyItem *child(int idx) const;
 
58
    int childCount() const;
 
59
 
 
60
    int row() const;
 
61
 
 
62
    const QString &display() const;
 
63
    const QString &documentName() const;
 
64
 
 
65
    const QString &path() const;
 
66
    void setPath(const QString &str);
 
67
 
 
68
    void setHost(const QString &host);
 
69
    const QString &host() const;
 
70
 
 
71
    void setIcon(const QIcon &i);
 
72
    const QIcon &icon() const;
 
73
 
 
74
    const QList<ProxyItem *> &children() const;
 
75
    QList<ProxyItem *> &children();
 
76
 
 
77
    void setDoc(KTextEditor::Document *doc);
 
78
    KTextEditor::Document *doc() const;
 
79
 
 
80
    /**
 
81
     * the view usess this to close all the documents under the folder
 
82
     * @returns list of all the (nested) documents under this node
 
83
     */
 
84
    QList<KTextEditor::Document *> docTree() const;
 
85
 
 
86
    void setFlags(Flags flags);
 
87
    void setFlag(Flag flag);
 
88
    void clearFlag(Flag flag);
 
89
    bool flag(Flag flag) const;
 
90
 
 
91
private:
 
92
    QString m_path;
 
93
    QString m_documentName;
 
94
    ProxyItemDir *m_parent;
 
95
    QList<ProxyItem *> m_children;
 
96
    int m_row;
 
97
    Flags m_flags;
 
98
 
 
99
    QString m_display;
 
100
    QIcon m_icon;
 
101
    KTextEditor::Document *m_doc;
 
102
    QString m_host;
 
103
 
 
104
protected:
 
105
    void updateDisplay();
 
106
    void updateDocumentName();
 
107
};
 
108
 
 
109
QDebug operator<<(QDebug dbg, ProxyItem *item)
 
110
{
 
111
    if (!item) {
 
112
        dbg.nospace() << "ProxyItem(0x0) ";
 
113
        return dbg.maybeSpace();
 
114
    }
 
115
 
 
116
    const void *parent = static_cast<void *>(item->parent());
 
117
 
 
118
    dbg.nospace() << "ProxyItem(" << (void *)item << ",";
 
119
    dbg.nospace() << parent << "," << item->row() << ",";
 
120
    dbg.nospace() << item->doc() << "," << item->path() << ") ";
 
121
    return dbg.maybeSpace();
 
122
}
 
123
 
 
124
class ProxyItemDir : public ProxyItem
 
125
{
 
126
public:
 
127
    ProxyItemDir(QString n, ProxyItemDir *p = 0) : ProxyItem(n, p) {
 
128
        setFlag(ProxyItem::Dir);
 
129
        updateDisplay();
 
130
 
 
131
        setIcon(QIcon::fromTheme(QLatin1String("folder")));
 
132
    }
 
133
};
 
134
 
 
135
QDebug operator<<(QDebug dbg, ProxyItemDir *item)
 
136
{
 
137
    if (!item) {
 
138
        dbg.nospace() << "ProxyItemDir(0x0) ";
 
139
        return dbg.maybeSpace();
 
140
    }
 
141
 
 
142
    const void *parent = static_cast<void *>(item->parent());
 
143
 
 
144
    dbg.nospace() << "ProxyItemDir(" << (void *)item << ",";
 
145
    dbg.nospace() << parent << "," << item->row() << ",";
 
146
    dbg.nospace() << item->path() << ", children:" << item->childCount() << ") ";
 
147
    return dbg.maybeSpace();
 
148
}
 
149
 
 
150
Q_DECLARE_OPERATORS_FOR_FLAGS(ProxyItem::Flags)
 
151
 
 
152
//BEGIN ProxyItem
 
153
ProxyItem::ProxyItem(const QString &d, ProxyItemDir *p, ProxyItem::Flags f)
 
154
    : m_path(d), m_parent(p), m_row(-1), m_flags(f), m_doc(0)
 
155
{
 
156
    updateDisplay();
 
157
 
 
158
    if (p) {
 
159
        p->addChild(this);
 
160
    }
 
161
}
 
162
 
 
163
ProxyItem::~ProxyItem()
 
164
{
 
165
    qDeleteAll(m_children);
 
166
}
 
167
 
 
168
void ProxyItem::updateDisplay()
 
169
{
 
170
    // triggers only if this is a top level node and the root has the show full path flag set.
 
171
    if (flag(ProxyItem::Dir) && m_parent && !m_parent->m_parent && m_parent->flag(ProxyItem::ShowFullPath)) {
 
172
        m_display = m_path;
 
173
        if (m_display.startsWith(QDir::homePath())) {
 
174
            m_display.replace(0, QDir::homePath().length(), QLatin1String("~"));
 
175
        }
 
176
    } else {
 
177
        m_display = m_path.section(QLatin1Char('/'), -1, -1);
 
178
        if (flag(ProxyItem::Host) && (!m_parent || (m_parent && !m_parent->m_parent))) {
 
179
            const QString hostPrefix = QString::fromLatin1("[%1]").arg(host());
 
180
            if (hostPrefix != m_display) {
 
181
                m_display = hostPrefix + m_display;
 
182
            }
 
183
        }
 
184
    }
 
185
}
 
186
 
 
187
int ProxyItem::addChild(ProxyItem *item)
 
188
{
 
189
    const int item_row = m_children.count();
 
190
    item->m_row = item_row;
 
191
    m_children.append(item);
 
192
    item->m_parent = static_cast<ProxyItemDir *>(this);
 
193
 
 
194
    item->updateDisplay();
 
195
 
 
196
    return item_row;
 
197
}
 
198
 
 
199
void ProxyItem::remChild(ProxyItem *item)
 
200
{
 
201
    const int idx = m_children.indexOf(item);
 
202
    Q_ASSERT(idx != -1);
 
203
 
 
204
    m_children.removeAt(idx);
 
205
 
 
206
    for (int i = idx; i < m_children.count(); i++) {
 
207
        m_children[i]->m_row = i;
 
208
    }
 
209
 
 
210
    item->m_parent = 0;
 
211
}
 
212
 
 
213
ProxyItemDir *ProxyItem::parent() const
 
214
{
 
215
    return m_parent;
 
216
}
 
217
 
 
218
ProxyItem *ProxyItem::child(int idx) const
 
219
{
 
220
    return (idx < 0 || idx >= m_children.count()) ? 0 : m_children[idx];
 
221
}
 
222
 
 
223
int ProxyItem::childCount() const
 
224
{
 
225
    return m_children.count();
 
226
}
 
227
 
 
228
int ProxyItem::row() const
 
229
{
 
230
    return m_row;
 
231
}
 
232
 
 
233
const QIcon &ProxyItem::icon() const
 
234
{
 
235
    return m_icon;
 
236
}
 
237
 
 
238
void ProxyItem::setIcon(const QIcon &i)
 
239
{
 
240
    m_icon = i;
 
241
}
 
242
 
 
243
const QString &ProxyItem::documentName() const
 
244
{
 
245
    return m_documentName;
 
246
}
 
247
 
 
248
const QString &ProxyItem::display() const
 
249
{
 
250
    return m_display;
 
251
}
 
252
 
 
253
const QString &ProxyItem::path() const
 
254
{
 
255
    return m_path;
 
256
}
 
257
 
 
258
void ProxyItem::setPath(const QString &p)
 
259
{
 
260
    m_path = p;
 
261
    updateDisplay();
 
262
}
 
263
 
 
264
const QList<ProxyItem *> &ProxyItem::children() const
 
265
{
 
266
    return m_children;
 
267
}
 
268
 
 
269
QList<ProxyItem *> &ProxyItem::children()
 
270
{
 
271
    return m_children;
 
272
}
 
273
 
 
274
void ProxyItem::setDoc(KTextEditor::Document *doc)
 
275
{
 
276
    Q_ASSERT(doc);
 
277
    m_doc = doc;
 
278
    updateDocumentName();
 
279
}
 
280
 
 
281
KTextEditor::Document *ProxyItem::doc() const
 
282
{
 
283
    return m_doc;
 
284
}
 
285
 
 
286
QList<KTextEditor::Document *> ProxyItem::docTree() const
 
287
{
 
288
    QList<KTextEditor::Document *> result;
 
289
 
 
290
    if (m_doc) {
 
291
        result.append(m_doc);
 
292
        return result;
 
293
    }
 
294
 
 
295
    foreach(const ProxyItem * item, m_children) {
 
296
        result.append(item->docTree());
 
297
    }
 
298
 
 
299
    return result;
 
300
}
 
301
 
 
302
bool ProxyItem::flag(Flag f) const
 
303
{
 
304
    return m_flags & f;
 
305
}
 
306
 
 
307
void ProxyItem::setFlag(Flag f)
 
308
{
 
309
    m_flags |= f;
 
310
}
 
311
 
 
312
void ProxyItem::setFlags(Flags f)
 
313
{
 
314
    m_flags = f;
 
315
}
 
316
 
 
317
void ProxyItem::clearFlag(Flag f)
 
318
{
 
319
    m_flags &= ~f;
 
320
}
 
321
 
 
322
void ProxyItem::setHost(const QString &host)
 
323
{
 
324
    m_host = host;
 
325
 
 
326
    if (host.isEmpty()) {
 
327
        clearFlag(Host);
 
328
    } else {
 
329
        setFlag(Host);
 
330
    }
 
331
 
 
332
    updateDocumentName();
 
333
    updateDisplay();
 
334
}
 
335
 
 
336
const QString &ProxyItem::host() const
 
337
{
 
338
    return m_host;
 
339
}
 
340
 
 
341
void ProxyItem::updateDocumentName()
 
342
{
 
343
    const QString docName = m_doc ? m_doc->documentName() : QString();
 
344
 
 
345
    if (flag(ProxyItem::Host)) {
 
346
        m_documentName = QString::fromLatin1("[%1]%2").arg(m_host).arg(docName);
 
347
    } else {
 
348
        m_documentName = docName;
 
349
    }
 
350
}
 
351
 
 
352
//END ProxyItem
 
353
 
 
354
KateFileTreeModel::KateFileTreeModel(QObject *p)
 
355
    : QAbstractItemModel(p)
 
356
    , m_root(new ProxyItemDir(QLatin1String("m_root"), 0))
 
357
{
 
358
    // setup default settings
 
359
    // session init will set these all soon
 
360
    const KColorScheme colors(QPalette::Active);
 
361
    const QColor bg = colors.background().color();
 
362
    m_editShade = KColorUtils::tint(bg, colors.foreground(KColorScheme::ActiveText).color(), 0.5);
 
363
    m_viewShade = KColorUtils::tint(bg, colors.foreground(KColorScheme::VisitedText).color(), 0.5);
 
364
    m_shadingEnabled = true;
 
365
    m_listMode = false;
 
366
 
 
367
    initModel();
 
368
}
 
369
 
 
370
KateFileTreeModel::~KateFileTreeModel()
 
371
{
 
372
    delete m_root;
 
373
}
 
374
 
 
375
bool KateFileTreeModel::shadingEnabled() const
 
376
{
 
377
    return m_shadingEnabled;
 
378
}
 
379
 
 
380
void KateFileTreeModel::setShadingEnabled(bool se)
 
381
{
 
382
    if (m_shadingEnabled != se) {
 
383
        updateBackgrounds(true);
 
384
        m_shadingEnabled = se;
 
385
    }
 
386
}
 
387
 
 
388
const QColor &KateFileTreeModel::editShade() const
 
389
{
 
390
    return m_editShade;
 
391
}
 
392
 
 
393
void KateFileTreeModel::setEditShade(const QColor &es)
 
394
{
 
395
    m_editShade = es;
 
396
}
 
397
 
 
398
const QColor &KateFileTreeModel::viewShade() const
 
399
{
 
400
    return m_viewShade;
 
401
}
 
402
 
 
403
void KateFileTreeModel::setViewShade(const QColor &vs)
 
404
{
 
405
    m_viewShade = vs;
 
406
}
 
407
 
 
408
bool KateFileTreeModel::showFullPathOnRoots(void) const
 
409
{
 
410
    return m_root->flag(ProxyItem::ShowFullPath);
 
411
}
 
412
 
 
413
void KateFileTreeModel::setShowFullPathOnRoots(bool s)
 
414
{
 
415
    if (s) {
 
416
        m_root->setFlag(ProxyItem::ShowFullPath);
 
417
    } else {
 
418
        m_root->clearFlag(ProxyItem::ShowFullPath);
 
419
    }
 
420
 
 
421
    foreach(ProxyItem * root, m_root->children()) {
 
422
        root->updateDisplay();
 
423
    }
 
424
}
 
425
 
 
426
void KateFileTreeModel::initModel()
 
427
{
 
428
    // add already existing documents
 
429
    foreach(KTextEditor::Document * doc, KTextEditor::Editor::instance()->application()->documents()) {
 
430
        documentOpened(doc);
 
431
    }
 
432
}
 
433
 
 
434
void KateFileTreeModel::clearModel()
 
435
{
 
436
    // remove all items
 
437
    // can safely ignore documentClosed here
 
438
 
 
439
    beginRemoveRows(QModelIndex(), 0, qMax(m_root->childCount() - 1, 0));
 
440
 
 
441
    delete m_root;
 
442
    m_root = new ProxyItemDir(QLatin1String("m_root"), 0);
 
443
 
 
444
    m_docmap.clear();
 
445
    m_viewHistory.clear();
 
446
    m_editHistory.clear();
 
447
    m_brushes.clear();
 
448
 
 
449
    endRemoveRows();
 
450
}
 
451
 
 
452
void KateFileTreeModel::connectDocument(const KTextEditor::Document *doc)
 
453
{
 
454
    connect(doc, SIGNAL(documentNameChanged(KTextEditor::Document *)), this, SLOT(documentNameChanged(KTextEditor::Document *)));
 
455
    connect(doc, SIGNAL(documentUrlChanged(KTextEditor::Document *)), this, SLOT(documentNameChanged(KTextEditor::Document *)));
 
456
    connect(doc, SIGNAL(modifiedChanged(KTextEditor::Document *)), this, SLOT(documentModifiedChanged(KTextEditor::Document *)));
 
457
    connect(doc, SIGNAL(modifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)),
 
458
            this,  SLOT(documentModifiedOnDisc(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)));
 
459
}
 
460
 
 
461
QModelIndex KateFileTreeModel::docIndex(const KTextEditor::Document *doc) const
 
462
{
 
463
    if (!m_docmap.contains(doc)) {
 
464
        return QModelIndex();
 
465
    }
 
466
 
 
467
    ProxyItem *item = m_docmap[doc];
 
468
 
 
469
    return createIndex(item->row(), 0, item);
 
470
}
 
471
 
 
472
Qt::ItemFlags KateFileTreeModel::flags(const QModelIndex &index) const
 
473
{
 
474
    Qt::ItemFlags flags = Qt::ItemIsEnabled;
 
475
 
 
476
    if (!index.isValid()) {
 
477
        return 0;
 
478
    }
 
479
 
 
480
    const ProxyItem *item = static_cast<ProxyItem *>(index.internalPointer());
 
481
    if (item && !item->childCount()) {
 
482
        flags |= Qt::ItemIsSelectable;
 
483
    }
 
484
 
 
485
    return flags;
 
486
}
 
487
 
 
488
Q_DECLARE_METATYPE(QList<KTextEditor::Document *>)
 
489
 
 
490
QVariant KateFileTreeModel::data(const QModelIndex &index, int role) const
 
491
{
 
492
    if (!index.isValid()) {
 
493
        return QVariant();
 
494
    }
 
495
 
 
496
    ProxyItem *item = static_cast<ProxyItem *>(index.internalPointer());
 
497
    if (!item) {
 
498
        return QVariant();
 
499
    }
 
500
 
 
501
    switch (role) {
 
502
    case KateFileTreeModel::PathRole:
 
503
        // allow to sort with hostname + path, bug 271488
 
504
        return (item->doc() && !item->doc()->url().isEmpty()) ? item->doc()->url().toString() : item->path();
 
505
 
 
506
    case KateFileTreeModel::DocumentRole:
 
507
        return QVariant::fromValue(item->doc());
 
508
 
 
509
    case KateFileTreeModel::OpeningOrderRole:
 
510
        return item->row();
 
511
 
 
512
    case KateFileTreeModel::DocumentTreeRole:
 
513
        return QVariant::fromValue(item->docTree());
 
514
 
 
515
    case Qt::DisplayRole:
 
516
        // in list mode we want to use kate's fancy names.
 
517
        if (m_listMode) {
 
518
            return item->documentName();
 
519
        } else {
 
520
            return item->display();
 
521
        }
 
522
 
 
523
    case Qt::DecorationRole:
 
524
        return item->icon();
 
525
 
 
526
    case Qt::ToolTipRole: {
 
527
        QString tooltip = item->path();
 
528
        if (item->flag(ProxyItem::DeletedExternally) || item->flag(ProxyItem::ModifiedExternally)) {
 
529
            tooltip = i18nc("%1 is the full path", "<p><b>%1</b></p><p>The document has been modified by another application.</p>").arg(item->path());
 
530
        }
 
531
 
 
532
        return tooltip;
 
533
    }
 
534
 
 
535
    case Qt::ForegroundRole: {
 
536
        const KColorScheme colors(QPalette::Active);
 
537
        if (!item->flag(ProxyItem::Dir) && (!item->doc() || item->doc()->openingError())) {
 
538
            return colors.foreground(KColorScheme::InactiveText).color();
 
539
        }
 
540
    }
 
541
    break;
 
542
 
 
543
    case Qt::BackgroundRole:
 
544
        // TODO: do that funky shading the file list does...
 
545
        if (m_shadingEnabled && m_brushes.contains(item)) {
 
546
            return m_brushes[item];
 
547
        }
 
548
        break;
 
549
    }
 
550
 
 
551
    return QVariant();
 
552
}
 
553
 
 
554
QVariant KateFileTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
 
555
{
 
556
    Q_UNUSED(orientation);
 
557
    Q_UNUSED(role);
 
558
 
 
559
    if (section == 0) {
 
560
        return QLatin1String("name");
 
561
    }
 
562
 
 
563
    return QVariant();
 
564
}
 
565
 
 
566
int KateFileTreeModel::rowCount(const QModelIndex &parent) const
 
567
{
 
568
    if (!parent.isValid()) {
 
569
        return m_root->childCount();
 
570
    }
 
571
 
 
572
    const ProxyItem *item = static_cast<ProxyItem *>(parent.internalPointer());
 
573
    if (!item) {
 
574
        return 0;
 
575
    }
 
576
 
 
577
    return item->childCount();
 
578
}
 
579
 
 
580
int KateFileTreeModel::columnCount(const QModelIndex &parent) const
 
581
{
 
582
    Q_UNUSED(parent);
 
583
    return 1;
 
584
}
 
585
 
 
586
QModelIndex KateFileTreeModel::parent(const QModelIndex &index) const
 
587
{
 
588
    if (!index.isValid()) {
 
589
        return QModelIndex();
 
590
    }
 
591
 
 
592
    const ProxyItem *item = static_cast<ProxyItem *>(index.internalPointer());
 
593
    if (!item) {
 
594
        return QModelIndex();
 
595
    }
 
596
 
 
597
    if (!item->parent()) {
 
598
        return QModelIndex();
 
599
    }
 
600
 
 
601
    if (item->parent() == m_root) {
 
602
        return QModelIndex();
 
603
    }
 
604
 
 
605
    return createIndex(item->parent()->row(), 0, item->parent());
 
606
}
 
607
 
 
608
QModelIndex KateFileTreeModel::index(int row, int column, const QModelIndex &parent) const
 
609
{
 
610
    const ProxyItem *p = 0;
 
611
    if (column != 0) {
 
612
        return QModelIndex();
 
613
    }
 
614
 
 
615
    if (!parent.isValid()) {
 
616
        p = m_root;
 
617
    } else {
 
618
        p = static_cast<ProxyItem *>(parent.internalPointer());
 
619
    }
 
620
 
 
621
    if (!p) {
 
622
        return QModelIndex();
 
623
    }
 
624
 
 
625
    if (row < 0 || row >= p->childCount()) {
 
626
        return QModelIndex();
 
627
    }
 
628
 
 
629
    return createIndex(row, 0, p->child(row));
 
630
}
 
631
 
 
632
bool KateFileTreeModel::hasChildren(const QModelIndex &parent) const
 
633
{
 
634
    if (!parent.isValid()) {
 
635
        return m_root->childCount() > 0;
 
636
    }
 
637
 
 
638
    const ProxyItem *item = static_cast<ProxyItem *>(parent.internalPointer());
 
639
    if (!item) {
 
640
        return false;
 
641
    }
 
642
 
 
643
    return item->childCount() > 0;
 
644
}
 
645
 
 
646
bool KateFileTreeModel::isDir(const QModelIndex &index) const
 
647
{
 
648
    if (!index.isValid()) {
 
649
        return true;
 
650
    }
 
651
 
 
652
    const ProxyItem *item = static_cast<ProxyItem *>(index.internalPointer());
 
653
    if (!item) {
 
654
        return false;
 
655
    }
 
656
 
 
657
    return item->flag(ProxyItem::Dir);
 
658
}
 
659
 
 
660
bool KateFileTreeModel::listMode() const
 
661
{
 
662
    return m_listMode;
 
663
}
 
664
 
 
665
void KateFileTreeModel::setListMode(bool lm)
 
666
{
 
667
    if (lm != m_listMode) {
 
668
        m_listMode = lm;
 
669
 
 
670
        clearModel();
 
671
        initModel();
 
672
    }
 
673
}
 
674
 
 
675
void KateFileTreeModel::documentOpened(KTextEditor::Document *doc)
 
676
{
 
677
    ProxyItem *item = new ProxyItem(QString());
 
678
    item->setDoc(doc);
 
679
 
 
680
    updateItemPathAndHost(item);
 
681
    setupIcon(item);
 
682
    handleInsert(item);
 
683
    m_docmap[doc] = item;
 
684
    connectDocument(doc);
 
685
}
 
686
 
 
687
void KateFileTreeModel::documentsOpened(const QList<KTextEditor::Document *> &docs)
 
688
{
 
689
    foreach(KTextEditor::Document * doc, docs) {
 
690
        if (m_docmap.contains(doc)) {
 
691
            documentNameChanged(doc);
 
692
        } else {
 
693
            documentOpened(doc);
 
694
        }
 
695
    }
 
696
}
 
697
 
 
698
void KateFileTreeModel::documentModifiedChanged(KTextEditor::Document *doc)
 
699
{
 
700
    if (!m_docmap.contains(doc)) {
 
701
        return;
 
702
    }
 
703
 
 
704
    ProxyItem *item = m_docmap[doc];
 
705
 
 
706
    if (doc->isModified()) {
 
707
        item->setFlag(ProxyItem::Modified);
 
708
    } else {
 
709
        item->clearFlag(ProxyItem::Modified);
 
710
        item->clearFlag(ProxyItem::ModifiedExternally);
 
711
        item->clearFlag(ProxyItem::DeletedExternally);
 
712
    }
 
713
 
 
714
    setupIcon(item);
 
715
 
 
716
    const QModelIndex idx = createIndex(item->row(), 0, item);
 
717
    emit dataChanged(idx, idx);
 
718
}
 
719
 
 
720
void KateFileTreeModel::documentModifiedOnDisc(KTextEditor::Document *doc, bool modified, KTextEditor::ModificationInterface::ModifiedOnDiskReason reason)
 
721
{
 
722
    Q_UNUSED(modified);
 
723
    if (!m_docmap.contains(doc)) {
 
724
        return;
 
725
    }
 
726
 
 
727
    ProxyItem *item = m_docmap[doc];
 
728
 
 
729
    // This didn't do what I thought it did, on an ignore
 
730
    // we'd get !modified causing the warning icons to disappear
 
731
    if (!modified) {
 
732
        item->clearFlag(ProxyItem::ModifiedExternally);
 
733
        item->clearFlag(ProxyItem::DeletedExternally);
 
734
    } else {
 
735
        if (reason == KTextEditor::ModificationInterface::OnDiskDeleted) {
 
736
            item->setFlag(ProxyItem::DeletedExternally);
 
737
        } else if (reason == KTextEditor::ModificationInterface::OnDiskModified) {
 
738
            item->setFlag(ProxyItem::ModifiedExternally);
 
739
        } else if (reason == KTextEditor::ModificationInterface::OnDiskCreated) {
 
740
            // with out this, on "reload" we don't get the icons removed :(
 
741
            item->clearFlag(ProxyItem::ModifiedExternally);
 
742
            item->clearFlag(ProxyItem::DeletedExternally);
 
743
        }
 
744
    }
 
745
 
 
746
    setupIcon(item);
 
747
 
 
748
    const QModelIndex idx = createIndex(item->row(), 0, item);
 
749
    emit dataChanged(idx, idx);
 
750
}
 
751
 
 
752
void KateFileTreeModel::documentActivated(const KTextEditor::Document *doc)
 
753
{
 
754
    if (!m_docmap.contains(doc)) {
 
755
        return;
 
756
    }
 
757
 
 
758
    ProxyItem *item = m_docmap[doc];
 
759
    m_viewHistory.removeAll(item);
 
760
    m_viewHistory.prepend(item);
 
761
 
 
762
    while (m_viewHistory.count() > 10) {
 
763
        m_viewHistory.removeLast();
 
764
    }
 
765
 
 
766
    updateBackgrounds();
 
767
}
 
768
 
 
769
void KateFileTreeModel::documentEdited(const KTextEditor::Document *doc)
 
770
{
 
771
    if (!m_docmap.contains(doc)) {
 
772
        return;
 
773
    }
 
774
 
 
775
    ProxyItem *item = m_docmap[doc];
 
776
    m_editHistory.removeAll(item);
 
777
    m_editHistory.prepend(item);
 
778
    while (m_editHistory.count() > 10) {
 
779
        m_editHistory.removeLast();
 
780
    }
 
781
 
 
782
    updateBackgrounds();
 
783
}
 
784
 
 
785
void KateFileTreeModel::slotAboutToDeleteDocuments(const QList<KTextEditor::Document *> &docs)
 
786
{
 
787
    foreach(const KTextEditor::Document * doc, docs) {
 
788
        disconnect(doc, SIGNAL(documentNameChanged(KTextEditor::Document *)), this, SLOT(documentNameChanged(KTextEditor::Document *)));
 
789
        disconnect(doc, SIGNAL(documentUrlChanged(KTextEditor::Document *)), this, SLOT(documentNameChanged(KTextEditor::Document *)));
 
790
        disconnect(doc, SIGNAL(modifiedChanged(KTextEditor::Document *)), this, SLOT(documentModifiedChanged(KTextEditor::Document *)));
 
791
        disconnect(doc, SIGNAL(modifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)),
 
792
                   this,  SLOT(documentModifiedOnDisc(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)));
 
793
    }
 
794
}
 
795
 
 
796
void KateFileTreeModel::slotDocumentsDeleted(const QList<KTextEditor::Document *> &docs)
 
797
{
 
798
    foreach(const KTextEditor::Document * doc, docs) {
 
799
        connectDocument(doc);
 
800
    }
 
801
}
 
802
 
 
803
class EditViewCount
 
804
{
 
805
public:
 
806
    EditViewCount(): edit(0), view(0)
 
807
    {}
 
808
    int edit;
 
809
    int view;
 
810
};
 
811
 
 
812
void KateFileTreeModel::updateBackgrounds(bool force)
 
813
{
 
814
    if (!m_shadingEnabled && !force) {
 
815
        return;
 
816
    }
 
817
 
 
818
    QMap <ProxyItem *, EditViewCount> helper;
 
819
    int i = 1;
 
820
 
 
821
    foreach(ProxyItem * item, m_viewHistory) {
 
822
        helper[item].view = i;
 
823
        i++;
 
824
    }
 
825
 
 
826
    i = 1;
 
827
    foreach(ProxyItem * item, m_editHistory) {
 
828
        helper[item].edit = i;
 
829
        i++;
 
830
    }
 
831
 
 
832
    QMap<ProxyItem *, QBrush> oldBrushes = m_brushes;
 
833
    m_brushes.clear();
 
834
 
 
835
    const int hc = m_viewHistory.count();
 
836
    const int ec = m_editHistory.count();
 
837
 
 
838
    for (QMap<ProxyItem *, EditViewCount>::iterator it = helper.begin(); it != helper.end(); ++it) {
 
839
        QColor shade(m_viewShade);
 
840
        QColor eshade(m_editShade);
 
841
 
 
842
        if (it.value().edit > 0) {
 
843
            int v = hc - it.value().view;
 
844
            int e = ec - it.value().edit + 1;
 
845
 
 
846
            e = e * e;
 
847
 
 
848
            const int n = qMax(v + e, 1);
 
849
 
 
850
            shade.setRgb(
 
851
                ((shade.red() * v) + (eshade.red() * e)) / n,
 
852
                ((shade.green() * v) + (eshade.green() * e)) / n,
 
853
                ((shade.blue() * v) + (eshade.blue() * e)) / n
 
854
            );
 
855
        }
 
856
 
 
857
        // blend in the shade color; latest is most colored.
 
858
        const double t = double(hc - it.value().view + 1) / double(hc);
 
859
 
 
860
        m_brushes[it.key()] = QBrush(KColorUtils::mix(QPalette().color(QPalette::Base), shade, t));
 
861
    }
 
862
 
 
863
    foreach(ProxyItem * item, m_brushes.keys()) {
 
864
        oldBrushes.remove(item);
 
865
        const QModelIndex idx = createIndex(item->row(), 0, item);
 
866
        dataChanged(idx, idx);
 
867
    }
 
868
 
 
869
    foreach(ProxyItem * item, oldBrushes.keys()) {
 
870
        const QModelIndex idx = createIndex(item->row(), 0, item);
 
871
        dataChanged(idx, idx);
 
872
    }
 
873
}
 
874
 
 
875
void KateFileTreeModel::handleEmptyParents(ProxyItemDir *item)
 
876
{
 
877
    Q_ASSERT(item != 0);
 
878
 
 
879
    if (!item->parent()) {
 
880
        return;
 
881
    }
 
882
 
 
883
    ProxyItemDir *parent = item->parent();
 
884
 
 
885
    while (parent) {
 
886
        if (!item->childCount()) {
 
887
            const QModelIndex parent_index = (parent == m_root) ? QModelIndex() : createIndex(parent->row(), 0, parent);
 
888
            beginRemoveRows(parent_index, item->row(), item->row());
 
889
            parent->remChild(item);
 
890
            endRemoveRows();
 
891
            delete item;
 
892
        } else {
 
893
            // breakout early, if this node isn't empty, theres no use in checking its parents
 
894
            return;
 
895
        }
 
896
 
 
897
        item = parent;
 
898
        parent = item->parent();
 
899
    }
 
900
}
 
901
 
 
902
void KateFileTreeModel::documentClosed(KTextEditor::Document *doc)
 
903
{
 
904
    if (!m_docmap.contains(doc)) {
 
905
        return;
 
906
    }
 
907
 
 
908
    if (m_shadingEnabled) {
 
909
        ProxyItem *toRemove = m_docmap[doc];
 
910
        if (m_brushes.contains(toRemove)) {
 
911
            m_brushes.remove(toRemove);
 
912
        }
 
913
 
 
914
        if (m_viewHistory.contains(toRemove)) {
 
915
            m_viewHistory.removeAll(toRemove);
 
916
        }
 
917
 
 
918
        if (m_editHistory.contains(toRemove)) {
 
919
            m_editHistory.removeAll(toRemove);
 
920
        }
 
921
    }
 
922
 
 
923
    ProxyItem *node = m_docmap[doc];
 
924
    ProxyItemDir *parent = node->parent();
 
925
 
 
926
    const QModelIndex parent_index = (parent == m_root) ? QModelIndex() : createIndex(parent->row(), 0, parent);
 
927
    beginRemoveRows(parent_index, node->row(), node->row());
 
928
    node->parent()->remChild(node);
 
929
    endRemoveRows();
 
930
 
 
931
    delete node;
 
932
    handleEmptyParents(parent);
 
933
 
 
934
    m_docmap.remove(doc);
 
935
}
 
936
 
 
937
void KateFileTreeModel::documentNameChanged(KTextEditor::Document *doc)
 
938
{
 
939
    if (!m_docmap.contains(doc)) {
 
940
        return;
 
941
    }
 
942
 
 
943
    ProxyItem *item = m_docmap[doc];
 
944
 
 
945
    if (m_shadingEnabled) {
 
946
        ProxyItem *toRemove = m_docmap[doc];
 
947
        if (m_brushes.contains(toRemove)) {
 
948
            QBrush brush = m_brushes[toRemove];
 
949
            m_brushes.remove(toRemove);
 
950
            m_brushes.insert(item, brush);
 
951
        }
 
952
 
 
953
        if (m_viewHistory.contains(toRemove)) {
 
954
            const int idx = m_viewHistory.indexOf(toRemove);
 
955
            if (idx != -1) {
 
956
                m_viewHistory.replace(idx, item);
 
957
            }
 
958
        }
 
959
 
 
960
        if (m_editHistory.contains(toRemove)) {
 
961
            const int idx = m_editHistory.indexOf(toRemove);
 
962
            if (idx != -1) {
 
963
                m_editHistory.replace(idx, item);
 
964
            }
 
965
        }
 
966
    }
 
967
 
 
968
    handleNameChange(item);
 
969
    emit triggerViewChangeAfterNameChange(); // FIXME: heh, non-standard signal?
 
970
}
 
971
 
 
972
ProxyItemDir *KateFileTreeModel::findRootNode(const QString &name, const int r) const
 
973
{
 
974
    foreach(ProxyItem * item, m_root->children()) {
 
975
        if (!item->flag(ProxyItem::Dir)) {
 
976
            continue;
 
977
        }
 
978
 
 
979
        // make sure we're actually matching against the right dir,
 
980
        // previously the check below would match /foo/xy against /foo/x
 
981
        // and return /foo/x rather than /foo/xy
 
982
        // this seems a bit hackish, but is the simplest way to solve the
 
983
        // current issue.
 
984
        QString path = item->path().section(QLatin1Char('/'), 0, -r) + QLatin1Char('/');
 
985
 
 
986
        if (name.startsWith(path)) {
 
987
            return static_cast<ProxyItemDir *>(item);
 
988
        }
 
989
    }
 
990
 
 
991
    return 0;
 
992
}
 
993
 
 
994
ProxyItemDir *KateFileTreeModel::findChildNode(const ProxyItemDir *parent, const QString &name) const
 
995
{
 
996
    Q_ASSERT(parent != 0);
 
997
    Q_ASSERT(!name.isEmpty());
 
998
 
 
999
    if (!parent->childCount()) {
 
1000
        return 0;
 
1001
    }
 
1002
 
 
1003
    foreach(ProxyItem * item, parent->children()) {
 
1004
        if (!item->flag(ProxyItem::Dir)) {
 
1005
            continue;
 
1006
        }
 
1007
 
 
1008
        if (item->display() == name) {
 
1009
            return static_cast<ProxyItemDir *>(item);
 
1010
        }
 
1011
    }
 
1012
 
 
1013
    return 0;
 
1014
}
 
1015
 
 
1016
void KateFileTreeModel::insertItemInto(ProxyItemDir *root, ProxyItem *item)
 
1017
{
 
1018
    Q_ASSERT(root != 0);
 
1019
    Q_ASSERT(item != 0);
 
1020
 
 
1021
    QString tail = item->path();
 
1022
    tail.remove(0, root->path().length());
 
1023
    QStringList parts = tail.split(QLatin1Char('/'), QString::SkipEmptyParts);
 
1024
    ProxyItemDir *ptr = root;
 
1025
    QStringList current_parts;
 
1026
    current_parts.append(root->path());
 
1027
 
 
1028
    // seems this can be empty, see bug 286191
 
1029
    if (!parts.isEmpty()) {
 
1030
        parts.pop_back();
 
1031
    }
 
1032
 
 
1033
    foreach(const QString & part, parts) {
 
1034
        current_parts.append(part);
 
1035
        ProxyItemDir *find = findChildNode(ptr, part);
 
1036
        if (!find) {
 
1037
            const QString new_name = current_parts.join(QLatin1String("/"));
 
1038
            const QModelIndex parent_index = (ptr == m_root) ? QModelIndex() : createIndex(ptr->row(), 0, ptr);
 
1039
            beginInsertRows(parent_index, ptr->childCount(), ptr->childCount());
 
1040
            ptr = new ProxyItemDir(new_name, ptr);
 
1041
            endInsertRows();
 
1042
        } else {
 
1043
            ptr = find;
 
1044
        }
 
1045
    }
 
1046
 
 
1047
    const QModelIndex parent_index = (ptr == m_root) ? QModelIndex() : createIndex(ptr->row(), 0, ptr);
 
1048
    beginInsertRows(parent_index, ptr->childCount(), ptr->childCount());
 
1049
    ptr->addChild(item);
 
1050
    endInsertRows();
 
1051
}
 
1052
 
 
1053
void KateFileTreeModel::handleInsert(ProxyItem *item)
 
1054
{
 
1055
    Q_ASSERT(item != 0);
 
1056
 
 
1057
    if (m_listMode || item->flag(ProxyItem::Empty)) {
 
1058
        beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount());
 
1059
        m_root->addChild(item);
 
1060
        endInsertRows();
 
1061
        return;
 
1062
    }
 
1063
 
 
1064
    // case (item.path > root.path)
 
1065
    ProxyItemDir *root = findRootNode(item->path());
 
1066
    if (root) {
 
1067
        insertItemInto(root, item);
 
1068
        return;
 
1069
    }
 
1070
 
 
1071
    // trim off trailing file and dir
 
1072
    QString base = item->path().section(QLatin1Char('/'), 0, -2);
 
1073
 
 
1074
    // create new root
 
1075
    ProxyItemDir *new_root = new ProxyItemDir(base);
 
1076
    new_root->setHost(item->host());
 
1077
 
 
1078
    // add new root to m_root
 
1079
    beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount());
 
1080
    m_root->addChild(new_root);
 
1081
    endInsertRows();
 
1082
 
 
1083
    // same fix as in findRootNode, try to match a full dir, instead of a partial path
 
1084
    base += QLatin1Char('/');
 
1085
 
 
1086
    // try and merge existing roots with the new root node (new_root.path < root.path)
 
1087
    foreach(ProxyItem * root, m_root->children()) {
 
1088
        if (root == new_root || !root->flag(ProxyItem::Dir)) {
 
1089
            continue;
 
1090
        }
 
1091
 
 
1092
        if (root->path().startsWith(base)) {
 
1093
            beginRemoveRows(QModelIndex(), root->row(), root->row());
 
1094
            m_root->remChild(root);
 
1095
            endRemoveRows();
 
1096
 
 
1097
            //beginInsertRows(new_root_index, new_root->childCount(), new_root->childCount());
 
1098
            // this can't use new_root->addChild directly, or it'll potentially miss a bunch of subdirs
 
1099
            insertItemInto(new_root, root);
 
1100
            //endInsertRows();
 
1101
        }
 
1102
    }
 
1103
 
 
1104
    // add item to new root
 
1105
    // have to call begin/endInsertRows here, or the new item won't show up.
 
1106
    const QModelIndex new_root_index = createIndex(new_root->row(), 0, new_root);
 
1107
    beginInsertRows(new_root_index, new_root->childCount(), new_root->childCount());
 
1108
    new_root->addChild(item);
 
1109
    endInsertRows();
 
1110
 
 
1111
    handleDuplicitRootDisplay(new_root);
 
1112
}
 
1113
 
 
1114
void KateFileTreeModel::handleDuplicitRootDisplay(ProxyItemDir *init)
 
1115
{
 
1116
    QStack<ProxyItemDir *> rootsToCheck;
 
1117
    rootsToCheck.push(init);
 
1118
 
 
1119
    // make sure the roots don't match (recursively)
 
1120
    while (!rootsToCheck.isEmpty()) {
 
1121
        ProxyItemDir *check_root = rootsToCheck.pop();
 
1122
 
 
1123
        if (check_root->parent() != m_root) {
 
1124
            continue;
 
1125
        }
 
1126
 
 
1127
        foreach(ProxyItem * root, m_root->children()) {
 
1128
            if (root == check_root || !root->flag(ProxyItem::Dir)) {
 
1129
                continue;
 
1130
            }
 
1131
 
 
1132
            if (check_root->display() == root->display()) {
 
1133
                bool changed = false;
 
1134
 
 
1135
                const QString rdir = root->path().section(QLatin1Char('/'), 0, -2);
 
1136
                if (!rdir.isEmpty()) {
 
1137
                    beginRemoveRows(QModelIndex(), root->row(), root->row());
 
1138
                    m_root->remChild(root);
 
1139
                    endRemoveRows();
 
1140
 
 
1141
                    ProxyItemDir *irdir = new ProxyItemDir(rdir);
 
1142
                    beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount());
 
1143
                    m_root->addChild(irdir);
 
1144
                    endInsertRows();
 
1145
 
 
1146
                    insertItemInto(irdir, root);
 
1147
 
 
1148
                    foreach(ProxyItem * node, m_root->children()) {
 
1149
                        if (node == irdir || !root->flag(ProxyItem::Dir)) {
 
1150
                            continue;
 
1151
                        }
 
1152
 
 
1153
                        const QString xy = rdir + QLatin1Char('/');
 
1154
                        if (node->path().startsWith(xy)) {
 
1155
                            beginRemoveRows(QModelIndex(), node->row(), node->row());
 
1156
                            m_root->remChild(node);
 
1157
                            endRemoveRows();
 
1158
                            insertItemInto(irdir, node);
 
1159
                        }
 
1160
                    }
 
1161
 
 
1162
                    rootsToCheck.push(irdir);
 
1163
                    changed = true;
 
1164
                }
 
1165
 
 
1166
                const QString nrdir = check_root->path().section(QLatin1Char('/'), 0, -2);
 
1167
                if (!nrdir.isEmpty()) {
 
1168
                    beginRemoveRows(QModelIndex(), check_root->row(), check_root->row());
 
1169
                    m_root->remChild(check_root);
 
1170
                    endRemoveRows();
 
1171
 
 
1172
                    ProxyItemDir *irdir = new ProxyItemDir(nrdir);
 
1173
                    beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount());
 
1174
                    m_root->addChild(irdir);
 
1175
                    endInsertRows();
 
1176
 
 
1177
                    insertItemInto(irdir, check_root);
 
1178
 
 
1179
                    rootsToCheck.push(irdir);
 
1180
                    changed = true;
 
1181
                }
 
1182
 
 
1183
                if (changed) {
 
1184
                    break; // restart
 
1185
                }
 
1186
            }
 
1187
        } // foreach root
 
1188
 
 
1189
    }
 
1190
 
 
1191
}
 
1192
 
 
1193
void KateFileTreeModel::handleNameChange(ProxyItem *item)
 
1194
{
 
1195
    Q_ASSERT(item != 0);
 
1196
    Q_ASSERT(item->parent());
 
1197
 
 
1198
    updateItemPathAndHost(item);
 
1199
 
 
1200
    if (m_listMode) {
 
1201
        const QModelIndex idx = createIndex(item->row(), 0, item);
 
1202
        setupIcon(item);
 
1203
        emit dataChanged(idx, idx);
 
1204
        return;
 
1205
    }
 
1206
 
 
1207
    // in either case (new/change) we want to remove the item from its parent
 
1208
    ProxyItemDir *parent = item->parent();
 
1209
 
 
1210
    const QModelIndex parent_index = (parent == m_root) ? QModelIndex() : createIndex(parent->row(), 0, parent);
 
1211
    beginRemoveRows(parent_index, item->row(), item->row());
 
1212
    parent->remChild(item);
 
1213
    endRemoveRows();
 
1214
 
 
1215
    handleEmptyParents(parent);
 
1216
 
 
1217
    // clear all but Empty flag
 
1218
    if (item->flag(ProxyItem::Empty)) {
 
1219
        item->setFlags(ProxyItem::Empty);
 
1220
    } else {
 
1221
        item->setFlags(ProxyItem::None);
 
1222
    }
 
1223
 
 
1224
    setupIcon(item);
 
1225
    handleInsert(item);
 
1226
}
 
1227
 
 
1228
void KateFileTreeModel::updateItemPathAndHost(ProxyItem *item) const
 
1229
{
 
1230
    const KTextEditor::Document *doc = item->doc();
 
1231
    Q_ASSERT(doc); // this method should not be called at directory items
 
1232
 
 
1233
    QString path = doc->url().path();
 
1234
    QString host;
 
1235
    if (doc->url().isEmpty()) {
 
1236
        path = doc->documentName();
 
1237
        item->setFlag(ProxyItem::Empty);
 
1238
    } else {
 
1239
        item->clearFlag(ProxyItem::Empty);
 
1240
        host = doc->url().host();
 
1241
        if (!host.isEmpty()) {
 
1242
            path = QString::fromLatin1("[%1]%2").arg(host).arg(path);
 
1243
        }
 
1244
    }
 
1245
 
 
1246
    // for some reason we get useless name changes [should be fixed in 5.0]
 
1247
    if (item->path() == path) {
 
1248
        return;
 
1249
    }
 
1250
 
 
1251
    item->setPath(path);
 
1252
    item->setHost(host);
 
1253
}
 
1254
 
 
1255
void KateFileTreeModel::setupIcon(ProxyItem *item) const
 
1256
{
 
1257
    Q_ASSERT(item != 0);
 
1258
 
 
1259
    QString icon_name;
 
1260
 
 
1261
    if (item->flag(ProxyItem::Modified)) {
 
1262
        icon_name = QLatin1String("document-save");
 
1263
    } else {
 
1264
        const QUrl url(item->path());
 
1265
        icon_name = QMimeDatabase().mimeTypeForFile(url.path(), QMimeDatabase::MatchExtension).iconName();
 
1266
    }
 
1267
 
 
1268
    QIcon icon = QIcon::fromTheme(icon_name);
 
1269
 
 
1270
    if (item->flag(ProxyItem::ModifiedExternally) || item->flag(ProxyItem::DeletedExternally)) {
 
1271
        icon = KIconUtils::addOverlay(icon, QIcon(QLatin1String("emblem-important")), Qt::TopLeftCorner);
 
1272
    }
 
1273
 
 
1274
    item->setIcon(icon);
 
1275
}
 
1276
 
 
1277
void KateFileTreeModel::resetHistory()
 
1278
{
 
1279
    QSet<ProxyItem *> list = QSet<ProxyItem *>::fromList(m_viewHistory);
 
1280
    list += QSet<ProxyItem *>::fromList(m_editHistory);
 
1281
 
 
1282
    m_viewHistory.clear();
 
1283
    m_editHistory.clear();
 
1284
    m_brushes.clear();
 
1285
 
 
1286
    foreach(ProxyItem * item, list) {
 
1287
        QModelIndex idx = createIndex(item->row(), 0, item);
 
1288
        dataChanged(idx, idx, QVector<int>(1, Qt::BackgroundRole));
 
1289
    }
 
1290
}
 
1291