Warning, file /office/calligra/gemini/DocumentListModel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002  * SPDX-FileCopyrightText: 2014 Dan Leinir Turthra Jensen <admin@leinir.dk>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #include "DocumentListModel.h"
0008 
0009 #include <QDebug>
0010 #include <QDirIterator>
0011 #include <QRunnable>
0012 #include <QThreadPool>
0013 #include <QTimer>
0014 #include <QLocale>
0015 
0016 #include <KSharedConfig>
0017 #include <KConfigGroup>
0018 
0019 /*#include <QSparqlConnection>
0020 #include <QSparqlResult>
0021 #include <QSparqlError>*/
0022 #include <kfileitem.h>
0023 
0024 
0025 QDebug operator<<(QDebug dbg, const DocumentListModel::DocumentInfo& d) { 
0026     dbg.nospace() << d.filePath << "," << d.fileName << "," << d.docType << "," << d.fileSize << "," << d.authorName << "," << d.accessedTime << "," << d.modifiedTime << "," << d.uuid;
0027     return dbg.space();
0028 };
0029 
0030 const QString SearchThread::textDocumentType = QString("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#PaginatedTextDocument");
0031 const QString SearchThread::presentationType = QString("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#PresentationDocument");
0032 const QString SearchThread::spreadsheetType = QString("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#SpreadsheetDocument");
0033 
0034 SearchThread::SearchThread(const QHash<QString, DocumentListModel::DocumentType> &docTypes, QObject *parent) 
0035     : QObject(parent), m_abort(false), m_docTypes(docTypes)
0036 {
0037 }
0038 
0039 SearchThread::~SearchThread()
0040 {
0041 }
0042 
0043 void SearchThread::run()
0044 {
0045 // Keeping this code around, in case Tracker later blows up horribly and we
0046 // have to rapidly reenable the filesystem only support
0047     // Get documents from the device storage's document directory...
0048     QString documentsDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
0049     QStringList nameFilters;
0050     for (QHash<QString, DocumentListModel::DocumentType>::const_iterator it = m_docTypes.constBegin(); it != m_docTypes.constEnd(); ++it)
0051         nameFilters.append("*." + it.key());
0052 
0053     QDirIterator it(documentsDir, nameFilters, QDir::Files, QDirIterator::Subdirectories);
0054     while (it.hasNext() && !m_abort) {
0055         it.next();
0056         DocumentListModel::DocumentInfo info;
0057         info.fileName = it.fileName();
0058         info.authorName = "-";
0059         info.filePath = it.filePath();
0060         info.modifiedTime = it.fileInfo().lastModified();
0061         info.accessedTime = it.fileInfo().lastRead();
0062         info.fileSize = QString("%1").arg(it.fileInfo().size());
0063         info.docType = m_docTypes.value(info.filePath.split('.').last());
0064         info.uuid = "not known...";
0065         emit documentFound(info);
0066     }
0067 
0068     emit finished();
0069 }
0070 
0071 DocumentListModel::DocumentListModel(QObject *parent)
0072     : QAbstractListModel(parent)
0073     , m_searchThread(0)
0074     , m_groupBy(GroupByName)
0075     , m_filter(UnknownType)
0076 {
0077     qRegisterMetaType<DocumentInfo>();
0078 
0079     m_docTypes["odt"] = TextDocumentType;
0080     m_docTypes["doc"] = TextDocumentType;
0081     m_docTypes["docx"] = TextDocumentType;
0082     m_docTypes["odp"] = PresentationType;
0083     m_docTypes["ppt"] = PresentationType;
0084     m_docTypes["pptx"] = PresentationType;
0085     m_docTypes["ods"] = SpreadsheetType;
0086     m_docTypes["xls"] = SpreadsheetType;
0087     m_docTypes["xlsx"] = SpreadsheetType;
0088 }
0089 
0090 DocumentListModel::~DocumentListModel()
0091 {
0092     stopSearch();
0093 }
0094 
0095 QHash<int, QByteArray> DocumentListModel::roleNames() const
0096 {
0097     QHash<int, QByteArray> roleNames = QAbstractListModel::roleNames();
0098     roleNames[FileNameRole] = "fileName";
0099     roleNames[FilePathRole] = "filePath";
0100     roleNames[DocTypeRole] = "docType";
0101     roleNames[SectionCategoryRole] = "sectionCategory";
0102     roleNames[FileSizeRole] = "fileSize";
0103     roleNames[AuthorNameRole] = "authorName";
0104     roleNames[AccessedTimeRole] = "accessedTime";
0105     roleNames[ModifiedTimeRole] = "modifiedTime";
0106     roleNames[UUIDRole] = "uuid";
0107     return roleNames;
0108 }
0109 
0110 void DocumentListModel::startSearch()
0111 {
0112     if (m_searchThread) {
0113         qDebug() << "Already searching or finished search";
0114         return;
0115     }
0116     m_searchThread = new SearchThread(m_docTypes);
0117     connect(m_searchThread, &SearchThread::documentFound, this, &DocumentListModel::addDocument);
0118     connect(m_searchThread, &SearchThread::finished, this, &DocumentListModel::searchFinished);
0119     m_searchThread->setAutoDelete(false);
0120     QThreadPool::globalInstance()->start(m_searchThread);
0121 }
0122 
0123 void DocumentListModel::stopSearch()
0124 {
0125     if (m_searchThread)
0126         m_searchThread->abort();
0127 }
0128 
0129 void DocumentListModel::searchFinished()
0130 {
0131     Q_ASSERT(m_searchThread);
0132     delete m_searchThread;
0133     m_searchThread = 0;
0134 }
0135 
0136 void DocumentListModel::addDocument(const DocumentInfo &info)
0137 {
0138     if(m_allDocumentInfos.contains(info))
0139     {
0140         qDebug() << "Attempted to add duplicate entry" << info;
0141         return;
0142     }
0143 
0144     m_allDocumentInfos.append(info);
0145 
0146     if(m_filter == UnknownType || info.docType == m_filter) {
0147         beginInsertRows(QModelIndex(), m_currentDocumentInfos.count(), m_currentDocumentInfos.count());
0148         m_currentDocumentInfos.append(info);
0149         endInsertRows();
0150     }
0151 }
0152 
0153 int DocumentListModel::rowCount(const QModelIndex &parent) const
0154 {
0155     if(parent.isValid())
0156         return 0;
0157     return m_currentDocumentInfos.count();
0158 }
0159 
0160 int DocumentListModel::columnCount(const QModelIndex &parent) const
0161 {
0162     if (parent.isValid())
0163         return 0;
0164     return 1;
0165 }
0166 
0167 QVariant DocumentListModel::data(const QModelIndex &index, int role) const
0168 {
0169     if (!index.isValid())
0170         return QVariant();
0171     const int row = index.row();
0172     const DocumentInfo &info = m_currentDocumentInfos[row];
0173 
0174     switch (role) {
0175     case FileNameRole: // intentional fall through
0176     case Qt::DisplayRole: return info.fileName;
0177     case FilePathRole: return info.filePath;
0178     case DocTypeRole: return info.docType;
0179     case FileSizeRole: return info.fileSize;
0180     case AuthorNameRole: return info.authorName;
0181     case AccessedTimeRole: return prettyTime(info.accessedTime);
0182     case ModifiedTimeRole: return prettyTime(info.modifiedTime);
0183     case UUIDRole: return info.uuid;
0184     case SectionCategoryRole: 
0185         return m_groupBy == GroupByName ? info.fileName[0].toUpper() : info.docType;
0186     default: return QVariant();
0187     }
0188 }
0189 
0190 QString DocumentListModel::prettyTime(QDateTime theTime)
0191 {
0192     // QT5TODO: used to be KLocale::FancyShortDate, but no such thing with QLocale (also static anyway)
0193     return QLocale().toString(theTime, QLocale::ShortFormat);
0194 }
0195 
0196 QVariant DocumentListModel::headerData(int section, Qt::Orientation orientation, int role) const
0197 {
0198     if (orientation == Qt::Vertical || role != Qt::DisplayRole)
0199         return QVariant();
0200     switch (section) {
0201     case 0: return tr("Filename");
0202     case 1: return tr("Path");
0203     case 2: return tr("Type");
0204     case 3: return tr("Size");
0205     case 4: return tr("Author");
0206     case 5: return tr("Last Accessed");
0207     case 6: return tr("Last Modified");
0208     default: return QVariant();
0209     }
0210 }
0211 
0212 void DocumentListModel::groupBy(GroupBy role)
0213 {
0214     if (m_groupBy == role)
0215         return;
0216     m_groupBy = role;
0217     relayout();
0218 }
0219 
0220 void DocumentListModel::relayout()
0221 {
0222     beginResetModel();
0223     emit layoutAboutToBeChanged();
0224 
0225     QList<DocumentInfo> newList;
0226     foreach(const DocumentInfo &docInfo, m_allDocumentInfos) {
0227         if(m_filter == UnknownType || docInfo.docType == m_filter) {
0228             qDebug() << docInfo.filePath;
0229             newList.append(docInfo);
0230         }
0231     }
0232     
0233     m_currentDocumentInfos = newList;
0234     emit layoutChanged();
0235     endResetModel();
0236 }
0237 
0238 void DocumentListModel::classBegin()
0239 {
0240 }
0241 
0242 DocumentListModel::DocumentType DocumentListModel::filter()
0243 {
0244     return m_filter;
0245 }
0246 
0247 QString DocumentListModel::documentsFolder() const
0248 {
0249     return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
0250 }
0251 
0252 void DocumentListModel::setFilter(DocumentListModel::DocumentType newFilter)
0253 {
0254     m_filter = newFilter;
0255     relayout();
0256     emit filterChanged();
0257 }
0258 
0259 void DocumentListModel::componentComplete()
0260 {
0261     beginResetModel();
0262     endResetModel();
0263     startSearch();
0264 }
0265