File indexing completed on 2024-04-28 05:49:08

0001 /*  This file is part of the Kate project.
0002  *
0003  *  SPDX-FileCopyrightText: 2012 Christoph Cullmann <cullmann@kde.org>
0004  *
0005  *  SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "kateprojectitem.h"
0009 #include "kateproject.h"
0010 
0011 #include <QApplication>
0012 #include <QFile>
0013 #include <QIcon>
0014 #include <QMessageBox>
0015 #include <QMimeDatabase>
0016 #include <QThread>
0017 
0018 #include <KIconUtils>
0019 #include <KLocalizedString>
0020 
0021 #include <KTextEditor/Document>
0022 
0023 KateProjectItem::KateProjectItem(Type type, const QString &text)
0024     : QStandardItem(text)
0025     , m_type(type)
0026 {
0027     if (type == File) {
0028         auto flags = this->flags();
0029         flags.setFlag(Qt::ItemIsDropEnabled, false);
0030         setFlags(flags);
0031     }
0032 }
0033 
0034 KateProjectItem::~KateProjectItem()
0035 {
0036     delete m_icon;
0037 }
0038 
0039 void KateProjectItem::slotModifiedChanged(KTextEditor::Document *doc)
0040 {
0041     if (m_icon) {
0042         delete m_icon;
0043         m_icon = nullptr;
0044     }
0045 
0046     if (doc && doc->isModified()) {
0047         if (m_emblem.isEmpty()) {
0048             m_icon = new QIcon(QIcon::fromTheme(QStringLiteral("document-save")));
0049         } else {
0050             m_icon = new QIcon(KIconUtils::addOverlay(QIcon::fromTheme(QStringLiteral("document-save")), QIcon(m_emblem), Qt::TopLeftCorner));
0051         }
0052     }
0053     emitDataChanged();
0054 }
0055 
0056 void KateProjectItem::slotModifiedOnDisk(KTextEditor::Document *document, bool isModified, KTextEditor::Document::ModifiedOnDiskReason reason)
0057 {
0058     Q_UNUSED(document)
0059     Q_UNUSED(isModified)
0060 
0061     if (m_icon) {
0062         delete m_icon;
0063         m_icon = nullptr;
0064     }
0065 
0066     m_emblem.clear();
0067 
0068     if (reason != KTextEditor::Document::OnDiskUnmodified) {
0069         m_emblem = QStringLiteral("emblem-important");
0070     }
0071     emitDataChanged();
0072 }
0073 
0074 QVariant KateProjectItem::data(int role) const
0075 {
0076     if (role == Qt::DecorationRole) {
0077         /**
0078          * this should only happen in main thread
0079          * the background thread should only construct this elements and fill data
0080          * but never query gui stuff!
0081          */
0082         Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
0083         return QVariant(*icon());
0084     }
0085 
0086     if (role == TypeRole) {
0087         return QVariant(m_type);
0088     }
0089 
0090     return QStandardItem::data(role);
0091 }
0092 
0093 bool KateProjectItem::operator<(const QStandardItem &other) const
0094 {
0095     // let directories stay first
0096     const auto thisType = data(TypeRole).toInt();
0097     const auto otherType = other.data(TypeRole).toInt();
0098     if (thisType != otherType) {
0099         return thisType < otherType;
0100     }
0101 
0102     // case-insensitive compare of the filename
0103     return data(Qt::DisplayRole).toString().compare(other.data(Qt::DisplayRole).toString(), Qt::CaseInsensitive) < 0;
0104 }
0105 
0106 QIcon *KateProjectItem::icon() const
0107 {
0108     if (m_icon) {
0109         return m_icon;
0110     }
0111 
0112     switch (m_type) {
0113     case LinkedProject:
0114     case Project:
0115         m_icon = new QIcon(QIcon::fromTheme(QStringLiteral("folder-documents")));
0116         break;
0117 
0118     case Directory:
0119         m_icon = new QIcon(QIcon::fromTheme(QStringLiteral("folder")));
0120         break;
0121 
0122     case File: {
0123         // ensure we have no empty icons, that breaks layout in tree views
0124         QIcon icon = QIcon::fromTheme(QMimeDatabase().mimeTypeForUrl(QUrl::fromLocalFile(data(Qt::UserRole).toString())).iconName());
0125         if (icon.isNull()) {
0126             icon = QIcon::fromTheme(QStringLiteral("unknown"));
0127         }
0128         if (!m_emblem.isEmpty()) {
0129             m_icon = new QIcon(KIconUtils::addOverlay(icon, QIcon(m_emblem), Qt::TopLeftCorner));
0130         } else {
0131             m_icon = new QIcon(icon);
0132         }
0133         break;
0134     }
0135     }
0136 
0137     return m_icon;
0138 }
0139 
0140 void KateProjectItem::setData(const QVariant &value, int role)
0141 {
0142     if (role == Qt::EditRole) {
0143         auto newFileName = value.toString();
0144         if (newFileName.isEmpty())
0145             return;
0146 
0147         /**
0148          *  retrieve the ref to project that we stored
0149          *  in KateProjectTreeViewContextMenu
0150          */
0151         KateProject *project = data(KateProjectItem::ProjectRole).value<KateProject *>();
0152         if (!project) {
0153             return;
0154         }
0155 
0156         auto oldFileName = data(Qt::DisplayRole).toString();
0157         auto oldName = data(Qt::UserRole).toString();
0158         QString newName = oldName;
0159         newName.replace(oldFileName, newFileName);
0160 
0161         if (oldName == newName) {
0162             return;
0163         }
0164 
0165         if (!QFile::rename(oldName, newName)) {
0166             QMessageBox::critical(QApplication::activeWindow(), i18n("Error"), i18n("File name already exists"));
0167             return;
0168         }
0169 
0170         /**
0171          * Update the file2Item
0172          */
0173         project->renameFile(newName, oldName);
0174 
0175         // change internal path
0176         setData(newName, Qt::UserRole);
0177     }
0178 
0179     QStandardItem::setData(value, role);
0180 }