1 /***************************************************************************
2 * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
9 * This program 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 *
12 * GNU General Public License for more details. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
21 #include "documentchecker.h"
23 #include "definitions.h"
26 #include <KGlobalSettings>
28 #include <KIO/NetAccess>
29 #include <KFileDialog>
30 #include <KApplication>
31 #include <KUrlRequesterDialog>
33 #include <QTreeWidgetItem>
35 #include <QHeaderView>
39 #include <QCryptographicHash>
41 const int hashRole = Qt::UserRole;
42 const int sizeRole = Qt::UserRole + 1;
43 const int idRole = Qt::UserRole + 2;
44 const int statusRole = Qt::UserRole + 3;
46 DocumentChecker::DocumentChecker(QDomDocument doc, QWidget * parent) :
47 QDialog(parent), m_doc(doc)
49 setFont(KGlobalSettings::toolBarFont());
52 QDomNodeList producers = m_doc.elementsByTagName("producer");
53 QDomNodeList infoproducers = m_doc.elementsByTagName("kdenlive_producer");
59 QList <QDomElement> missingClips;
60 for (int i = 0; i < infoproducers.count(); i++) {
61 e = infoproducers.item(i).toElement();
62 clipType = e.attribute("type").toInt();
63 if (clipType == TEXT) continue;
64 id = e.attribute("id");
65 resource = e.attribute("resource");
66 if (clipType == SLIDESHOW) resource = KUrl(resource).directory();
67 if (!KIO::NetAccess::exists(KUrl(resource), KIO::NetAccess::SourceSide, 0)) {
69 missingClips.append(e);
73 if (missingClips.isEmpty()) QTimer::singleShot(0, this, SLOT(reject()));
75 for (int i = 0; i < missingClips.count(); i++) {
76 e = missingClips.at(i).toElement();
78 switch (e.attribute("type").toInt()) {
80 clipType = i18n("Video clip");
83 clipType = i18n("Mute video clip");
86 clipType = i18n("Audio clip");
89 clipType = i18n("Playlist clip");
92 clipType = i18n("Image clip");
95 clipType = i18n("Slideshow clip");
98 clipType = i18n("Video clip");
100 QTreeWidgetItem *item = new QTreeWidgetItem(m_view.treeWidget, QStringList() << clipType << e.attribute("resource"));
101 item->setIcon(0, KIcon("dialog-close"));
102 item->setData(0, hashRole, e.attribute("file_hash"));
103 item->setData(0, sizeRole, e.attribute("file_size"));
104 item->setData(0, idRole, e.attribute("id"));
105 item->setData(0, statusRole, '1');
107 connect(m_view.recursiveSearch, SIGNAL(pressed()), this, SLOT(slotSearchClips()));
108 connect(m_view.treeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(slotEditItem(QTreeWidgetItem *, int)));
112 DocumentChecker::~DocumentChecker() {}
114 void DocumentChecker::slotSearchClips()
116 QString newpath = KFileDialog::getExistingDirectory(KUrl("kfiledialog:///clipfolder"), kapp->activeWindow(), i18n("Clips folder"));
117 if (newpath.isEmpty()) return;
119 QTreeWidgetItem *child = m_view.treeWidget->topLevelItem(ix);
120 while (child && !child->data(0, statusRole).toString().isEmpty()) {
121 QString clipPath = searchFileRecursively(QDir(newpath), child->data(0, sizeRole).toString(), child->data(0, hashRole).toString());
122 if (!clipPath.isEmpty()) {
123 child->setText(1, clipPath);
124 child->setIcon(0, KIcon("dialog-ok"));
125 child->setData(0, statusRole, QString());
128 child = m_view.treeWidget->topLevelItem(ix);
132 QString DocumentChecker::searchFileRecursively(const QDir &dir, const QString &matchSize, const QString &matchHash) const
134 QString foundFileName;
137 QStringList filesAndDirs = dir.entryList(QDir::Files | QDir::Readable);
138 for (int i = 0; i < filesAndDirs.size() && foundFileName.isEmpty(); i++) {
139 QFile file(dir.absoluteFilePath(filesAndDirs.at(i)));
140 if (file.open(QIODevice::ReadOnly)) {
141 if (QString::number(file.size()) == matchSize) {
143 * 1 MB = 1 second per 450 files (or faster)
144 * 10 MB = 9 seconds per 450 files (or faster)
146 if (file.size() > 1000000*2) {
147 fileData = file.read(1000000);
148 if (file.seek(file.size() - 1000000))
149 fileData.append(file.readAll());
151 fileData = file.readAll();
153 fileHash = QCryptographicHash::hash(fileData, QCryptographicHash::Md5);
154 if (QString(fileHash.toHex()) == matchHash)
155 return file.fileName();
158 kDebug() << filesAndDirs.at(i) << file.size() << fileHash.toHex();
160 filesAndDirs = dir.entryList(QDir::Dirs | QDir::Readable | QDir::Executable | QDir::NoDotAndDotDot);
161 for (int i = 0; i < filesAndDirs.size() && foundFileName.isEmpty(); i++) {
162 foundFileName = searchFileRecursively(dir.absoluteFilePath(filesAndDirs.at(i)), matchSize, matchHash);
163 if (!foundFileName.isEmpty())
166 return foundFileName;
169 void DocumentChecker::slotEditItem(QTreeWidgetItem *item, int)
171 KUrl url = KUrlRequesterDialog::getUrl(item->text(1), this, i18n("Enter new location for file"));
172 if (url.isEmpty()) return;
173 item->setText(1, url.path());
174 if (KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, 0)) {
175 item->setIcon(0, KIcon("dialog-ok"));
176 item->setData(0, statusRole, QString());
181 void DocumentChecker::accept()
184 QDomNodeList producers = m_doc.elementsByTagName("producer");
185 QDomNodeList infoproducers = m_doc.elementsByTagName("kdenlive_producer");
187 QTreeWidgetItem *child = m_view.treeWidget->topLevelItem(ix);
188 while (child && child->data(0, statusRole).toString().isEmpty()) {
189 QString id = child->data(0, idRole).toString();
190 for (int i = 0; i < infoproducers.count(); i++) {
191 e = infoproducers.item(i).toElement();
192 if (e.attribute("id") == id) {
194 e.setAttribute("resource", child->text(1));
198 for (int i = 0; i < producers.count(); i++) {
199 e = producers.item(i).toElement();
200 if (e.attribute("id") == id) {
202 e.setAttribute("resource", child->text(1));
208 child = m_view.treeWidget->topLevelItem(ix);
213 #include "documentchecker.moc"