1 /*
2     This file is part of the Okteta Kasten module, made within the KDE community.
3 
4     SPDX-FileCopyrightText: 2008, 2010, 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
5 
6     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8 
9 #include "documentinfotool.hpp"
10 
11 // lib
12 #include "bytearraymodeliodevice.hpp"
13 // Okteta Kasten core
14 #include <Kasten/Okteta/ByteArrayDocument>
15 // Kasten core
16 #include <Kasten/DocumentSyncManager>
17 #include <Kasten/AbstractModelSynchronizer>
18 
19 // Okteta core
20 #include <Okteta/AbstractByteArrayModel>
21 #include <Okteta/ArrayChangeMetricsList>
22 // KF
23 #include <KLocalizedString>
24 // Qt
25 #include <QApplication>
26 #include <QTimer>
27 #include <QUrl>
28 #include <QMimeDatabase>
29 
30 namespace Kasten {
31 
32 static constexpr int mimeTypeUpdateTimeInterval = 500; // msec
33 
DocumentInfoTool(DocumentSyncManager * syncManager)34 DocumentInfoTool::DocumentInfoTool(DocumentSyncManager* syncManager)
35     : mDocumentSyncManager(syncManager)
36     , mMimeTypeUpdateTimer(new QTimer(this))
37 {
38     setObjectName(QStringLiteral("DocumentInfo"));
39 
40     mMimeTypeUpdateTimer->setInterval(mimeTypeUpdateTimeInterval);
41     mMimeTypeUpdateTimer->setSingleShot(true);
42     connect(mMimeTypeUpdateTimer, &QTimer::timeout, this, &DocumentInfoTool::updateMimeType);
43 }
44 
45 DocumentInfoTool::~DocumentInfoTool() = default;
46 
47 // TODO: file or document or ...?
title() const48 QString DocumentInfoTool::title() const { return i18nc("@title:window", "File Info"); }
documentTitle() const49 QString DocumentInfoTool::documentTitle() const
50 {
51     return mDocument ? mDocument->title() : QString();
52 }
53 
location() const54 QString DocumentInfoTool::location() const
55 {
56     QString result;
57     if (mDocument) {
58         const QUrl url = mDocumentSyncManager->urlOf(mDocument);
59         result = url.toDisplayString(QUrl::PrettyDecoded | QUrl::PreferLocalFile);
60     }
61     return result;
62 }
63 
documentSize() const64 int DocumentInfoTool::documentSize() const
65 {
66     int documentSize = -1;
67     if (mByteArrayModel) {
68         documentSize = mByteArrayModel->size();
69     }
70 
71     return documentSize;
72 }
73 
setTargetModel(AbstractModel * model)74 void DocumentInfoTool::setTargetModel(AbstractModel* model)
75 {
76     if (mSynchronizer) {
77         mSynchronizer->disconnect(this);
78     }
79     if (mDocument) {
80         mDocument->disconnect(this);
81     }
82     if (mByteArrayModel) {
83         mByteArrayModel->disconnect(this);
84     }
85 
86     mDocument = model ? model->findBaseModel<ByteArrayDocument*>() : nullptr;
87     mByteArrayModel = mDocument ? mDocument->content() : nullptr;
88 
89     const bool hasDocument = (mDocument != nullptr);
90     AbstractModelSynchronizer* synchronizer = nullptr;
91     QString documentTitle;
92     int documentSize = -1;
93     if (hasDocument) {
94         documentTitle = mDocument->title();
95         documentSize = mByteArrayModel->size();
96         synchronizer = mDocument->synchronizer();
97 
98         connect(mDocument, &ByteArrayDocument::titleChanged,
99                 this, &DocumentInfoTool::documentTitleChanged);
100         connect(mDocument, &ByteArrayDocument::synchronizerChanged,
101                 this, &DocumentInfoTool::onSynchronizerChanged);
102         connect(mByteArrayModel, &Okteta::AbstractByteArrayModel::contentsChanged,
103                 this, &DocumentInfoTool::onContentsChanged);
104     }
105 
106     onSynchronizerChanged(synchronizer);
107 
108     emit documentTitleChanged(documentTitle);
109     emit documentSizeChanged(documentSize);
110 }
111 
112 // TODO: should this be done in a worker thread, to not block the UI?
updateMimeType()113 void DocumentInfoTool::updateMimeType()
114 {
115     QMimeType currentMimeType;
116 
117     if (mDocument) {
118         // TODO: also get file mode, if available, for findByNameAndContent()
119         const QString filename = mDocumentSyncManager->urlOf(mDocument).fileName();
120 
121         Okteta::ByteArrayModelIoDevice byteArrayModelIoDevice(mByteArrayModel);
122         QMimeDatabase db;
123         currentMimeType = filename.isEmpty() ?
124                           db.mimeTypeForData(&byteArrayModelIoDevice) :
125                           db.mimeTypeForFileNameAndData(filename, &byteArrayModelIoDevice);
126     }
127 
128     if (mMimeType != currentMimeType) {
129         mMimeType = currentMimeType;
130         emit documentMimeTypeChanged(currentMimeType);
131     }
132 }
133 
onContentsChanged()134 void DocumentInfoTool::onContentsChanged()
135 {
136     if (!mMimeTypeUpdateTimer->isActive()) {
137         mMimeTypeUpdateTimer->start();
138     }
139 
140     emit documentSizeChanged(mByteArrayModel->size());
141 }
142 
onSynchronizerChanged(AbstractModelSynchronizer * synchronizer)143 void DocumentInfoTool::onSynchronizerChanged(AbstractModelSynchronizer* synchronizer)
144 {
145     // do an instant update, no need to delay
146     if (mMimeTypeUpdateTimer->isActive()) {
147         mMimeTypeUpdateTimer->stop();
148     }
149     updateMimeType();
150 
151     if (mSynchronizer) {
152         mSynchronizer->disconnect(this);
153     }
154     mSynchronizer = synchronizer;
155 
156     if (mSynchronizer) {
157         connect(mSynchronizer, &AbstractModelSynchronizer::urlChanged,
158                 this, &DocumentInfoTool::onUrlChanged);
159     }
160 
161     emit locationChanged(location());
162 }
163 
onUrlChanged(const QUrl & url)164 void DocumentInfoTool::onUrlChanged(const QUrl& url)
165 {
166     Q_UNUSED(url);
167 
168     emit locationChanged(location());
169 }
170 
171 }
172