File indexing completed on 2024-04-21 04:51:43
0001 /* 0002 SPDX-FileCopyrightText: 2016 Jean-Baptiste Mardelle <jb@kdenlive.org> 0003 This file is part of Kdenlive. See www.kdenlive.org. 0004 0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "librarywidget.h" 0009 #include "core.h" 0010 #include "doc/kthumb.h" 0011 #include "kdenlivesettings.h" 0012 #include "project/projectmanager.h" 0013 0014 #include <QAction> 0015 #include <QDropEvent> 0016 #include <QInputDialog> 0017 #include <QMimeData> 0018 #include <QProgressBar> 0019 #include <QStandardPaths> 0020 #include <QToolBar> 0021 #include <QTreeWidgetItem> 0022 #include <QVBoxLayout> 0023 0024 #include <KIO/FileCopyJob> 0025 #include <KIO/OpenFileManagerWindowJob> 0026 #include <KLocalizedString> 0027 #include <KMessageBox> 0028 0029 enum LibraryItem { PlayList, Clip, Folder }; 0030 0031 LibraryTree::LibraryTree(QWidget *parent) 0032 : QTreeWidget(parent) 0033 { 0034 int size = QFontInfo(font()).pixelSize(); 0035 setIconSize(QSize(size * 4, size * 2)); 0036 setDragDropMode(QAbstractItemView::DragDrop); 0037 setAcceptDrops(true); 0038 setDragEnabled(true); 0039 setDropIndicatorShown(true); 0040 viewport()->setAcceptDrops(true); 0041 } 0042 0043 // virtual 0044 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0045 QMimeData *LibraryTree::mimeData(const QList<QTreeWidgetItem *> list) const 0046 #else 0047 QMimeData *LibraryTree::mimeData(const QList<QTreeWidgetItem *> &list) const 0048 #endif 0049 { 0050 QList<QUrl> urls; 0051 urls.reserve(list.count()); 0052 for (QTreeWidgetItem *item : list) { 0053 urls << QUrl::fromLocalFile(item->data(0, Qt::UserRole).toString()); 0054 } 0055 auto *mime = new QMimeData; 0056 mime->setUrls(urls); 0057 return mime; 0058 } 0059 0060 QStringList LibraryTree::mimeTypes() const 0061 { 0062 return QStringList() << QStringLiteral("text/uri-list") << QStringLiteral("kdenlive/clip") << QStringLiteral("text/producerslist"); 0063 } 0064 0065 void LibraryTree::slotUpdateThumb(const QString &path, const QString &iconPath) 0066 { 0067 QString name = QUrl::fromLocalFile(path).fileName(); 0068 QList<QTreeWidgetItem *> list = findItems(name, Qt::MatchExactly | Qt::MatchRecursive); 0069 for (QTreeWidgetItem *item : qAsConst(list)) { 0070 if (item->data(0, Qt::UserRole).toString() == path) { 0071 // We found our item 0072 blockSignals(true); 0073 item->setData(0, Qt::DecorationRole, QIcon(iconPath)); 0074 blockSignals(false); 0075 break; 0076 } 0077 } 0078 } 0079 0080 void LibraryTree::slotUpdateThumb(const QString &path, const QPixmap &pix) 0081 { 0082 QString name = QUrl::fromLocalFile(path).fileName(); 0083 QList<QTreeWidgetItem *> list = findItems(name, Qt::MatchExactly | Qt::MatchRecursive); 0084 for (QTreeWidgetItem *item : qAsConst(list)) { 0085 if (item->data(0, Qt::UserRole).toString() == path) { 0086 // We found our item 0087 blockSignals(true); 0088 item->setData(0, Qt::DecorationRole, QIcon(pix)); 0089 blockSignals(false); 0090 break; 0091 } 0092 } 0093 } 0094 0095 void LibraryTree::mousePressEvent(QMouseEvent *event) 0096 { 0097 QTreeWidgetItem *clicked = this->itemAt(event->pos()); 0098 QList<QAction *> act = actions(); 0099 if (clicked) { 0100 for (QAction *a : qAsConst(act)) { 0101 a->setEnabled(true); 0102 } 0103 } else { 0104 // Clicked in empty area, disable clip actions 0105 clearSelection(); 0106 for (QAction *a : qAsConst(act)) { 0107 if (a->data().toInt() == 1) { 0108 a->setEnabled(false); 0109 } 0110 } 0111 } 0112 QTreeWidget::mousePressEvent(event); 0113 } 0114 0115 void LibraryTree::dropEvent(QDropEvent *event) 0116 { 0117 const QMimeData *qMimeData = event->mimeData(); 0118 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0119 QTreeWidgetItem *dropped = this->itemAt(event->pos()); 0120 #else 0121 QTreeWidgetItem *dropped = this->itemAt(event->position().toPoint()); 0122 #endif 0123 QString dest; 0124 if (dropped) { 0125 dest = dropped->data(0, Qt::UserRole).toString(); 0126 if (dropped->data(0, Qt::UserRole + 2).toInt() != LibraryItem::Folder) { 0127 dest = QUrl::fromLocalFile(dest).adjusted(QUrl::RemoveFilename).toLocalFile(); 0128 } 0129 } 0130 if (qMimeData->hasUrls()) { 0131 QList<QUrl> urls = qMimeData->urls(); 0132 Q_EMIT moveData(urls, dest); 0133 } else if (qMimeData->hasFormat(QStringLiteral("kdenlive/clip"))) { 0134 Q_EMIT importSequence(QString(qMimeData->data(QStringLiteral("kdenlive/clip"))).split(QLatin1Char(';')), dest); 0135 } else if (qMimeData->hasFormat(QStringLiteral("text/producerslist"))) { 0136 QStringList list = QString(qMimeData->data(QStringLiteral("text/producerslist"))).split(QLatin1Char(';')); 0137 for (const QString &prodslist : qAsConst(list)) { 0138 if (prodslist.startsWith(QLatin1Char('#'))) { 0139 // Bin folder, not supported yet 0140 continue; 0141 } 0142 if (prodslist.contains(QLatin1Char('/'))) { 0143 // Clip zone 0144 Q_EMIT importSequence(prodslist.split(QLatin1Char('/')), dest); 0145 } else { 0146 // Full clip 0147 Q_EMIT importSequence(QStringList() << prodslist << QStringLiteral("-1") << QStringLiteral("-1"), dest); 0148 } 0149 } 0150 } 0151 event->accept(); 0152 QTreeWidget::dropEvent(event); 0153 } 0154 0155 LibraryWidget::LibraryWidget(ProjectManager *manager, QWidget *parent) 0156 : QWidget(parent) 0157 , m_manager(manager) 0158 , m_previewJob(nullptr) 0159 , m_selectNewFile(false) 0160 { 0161 auto *lay = new QVBoxLayout(this); 0162 m_libraryTree = new LibraryTree(this); 0163 m_libraryTree->setColumnCount(1); 0164 m_libraryTree->setHeaderHidden(true); 0165 m_libraryTree->setDragEnabled(true); 0166 m_libraryTree->setItemDelegate(new LibraryItemDelegate(this)); 0167 m_libraryTree->setAlternatingRowColors(true); 0168 lay->addWidget(m_libraryTree); 0169 0170 // Library path 0171 QString path; 0172 if (KdenliveSettings::librarytodefaultfolder() || KdenliveSettings::libraryfolder().isEmpty()) { 0173 path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/library"); 0174 } else { 0175 path = KdenliveSettings::libraryfolder(); 0176 } 0177 0178 // Info message 0179 m_infoWidget = new KMessageWidget; 0180 lay->addWidget(m_infoWidget); 0181 m_infoWidget->hide(); 0182 // Download progress bar 0183 m_progressBar = new QProgressBar(this); 0184 lay->addWidget(m_progressBar); 0185 m_toolBar = new QToolBar(this); 0186 m_toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); 0187 int size = style()->pixelMetric(QStyle::PM_SmallIconSize); 0188 m_toolBar->setIconSize(QSize(size, size)); 0189 m_progressBar->setRange(0, 100); 0190 m_progressBar->setFormat(i18nc("%p is the percent value, % is the percent sign", "%p%")); 0191 m_progressBar->setOrientation(Qt::Horizontal); 0192 m_progressBar->setVisible(false); 0193 lay->addWidget(m_toolBar); 0194 setLayout(lay); 0195 0196 m_directory = QDir(path); 0197 if (!m_directory.exists()) { 0198 m_directory.mkpath(QStringLiteral(".")); 0199 } 0200 QFileInfo fi(m_directory.absolutePath()); 0201 if (!m_directory.exists() || !fi.isWritable()) { 0202 // Something went wrong 0203 showMessage(i18n("Check your settings, Library path is invalid: %1", m_directory.absolutePath()), KMessageWidget::Warning); 0204 setEnabled(false); 0205 } 0206 0207 m_libraryTree->setContextMenuPolicy(Qt::ActionsContextMenu); 0208 m_timer.setSingleShot(true); 0209 m_timer.setInterval(4000); 0210 connect(&m_timer, &QTimer::timeout, m_infoWidget, &KMessageWidget::animatedHide); 0211 connect(m_libraryTree, &LibraryTree::moveData, this, &LibraryWidget::slotMoveData); 0212 connect(m_libraryTree, &LibraryTree::importSequence, this, &LibraryWidget::slotSaveSequence); 0213 0214 m_coreLister = new KCoreDirLister(this); 0215 m_coreLister->setDelayedMimeTypes(false); 0216 connect(m_coreLister, &KCoreDirLister::itemsAdded, this, &LibraryWidget::slotItemsAdded); 0217 connect(m_coreLister, &KCoreDirLister::itemsDeleted, this, &LibraryWidget::slotItemsDeleted); 0218 connect(m_coreLister, SIGNAL(clear()), this, SLOT(slotClearAll())); 0219 m_coreLister->openUrl(QUrl::fromLocalFile(m_directory.absolutePath())); 0220 m_libraryTree->setSortingEnabled(true); 0221 m_libraryTree->sortByColumn(0, Qt::AscendingOrder); 0222 connect(m_libraryTree, &LibraryTree::itemChanged, this, &LibraryWidget::slotItemEdited, Qt::UniqueConnection); 0223 } 0224 0225 void LibraryWidget::setupActions() 0226 { 0227 QList<QAction *> menuList; 0228 m_addAction = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-add-clip")), i18n("Add Clip to Project"), this); 0229 m_addAction->setWhatsThis(xi18nc("@info:whatsthis", "Adds the selected library clip to the project bin.")); 0230 connect(m_addAction, &QAction::triggered, this, &LibraryWidget::slotAddToProject); 0231 m_addAction->setData(1); 0232 m_deleteAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete Clip from Library"), this); 0233 m_deleteAction->setWhatsThis(xi18nc("@info:whatsthis", "Deletes the currently selected library clip from the library.")); 0234 connect(m_deleteAction, &QAction::triggered, this, &LibraryWidget::slotDeleteFromLibrary); 0235 m_deleteAction->setData(1); 0236 QAction *addFolder = new QAction(QIcon::fromTheme(QStringLiteral("folder-new")), i18n("Create Library Folder"), this); 0237 addFolder->setWhatsThis(xi18nc("@info:whatsthis", "Creates a new folder in the library.")); 0238 connect(addFolder, &QAction::triggered, this, &LibraryWidget::slotAddFolder); 0239 QAction *renameFolder = new QAction(QIcon(), i18n("Rename Library Clip"), this); 0240 renameFolder->setData(1); 0241 connect(renameFolder, &QAction::triggered, this, &LibraryWidget::slotRenameItem); 0242 menuList << m_addAction << addFolder << renameFolder << m_deleteAction; 0243 m_toolBar->addAction(m_addAction); 0244 m_toolBar->addSeparator(); 0245 m_toolBar->addAction(addFolder); 0246 QAction *sentToLibrary = new QAction(QIcon::fromTheme(QStringLiteral("bookmark-new")), i18n("Add Timeline Selection to Library"), this); 0247 sentToLibrary->setWhatsThis(xi18nc("@info:whatsthis", "Adds the clip(s) currently selected in the timeline to the library. Note that the paths to images, " 0248 "video and audio files are saved as absolute paths.")); 0249 connect(sentToLibrary, &QAction::triggered, this, &LibraryWidget::slotAddToLibrary); 0250 pCore->addActionToCollection(QStringLiteral("send_library"), sentToLibrary); 0251 sentToLibrary->setEnabled(false); 0252 m_toolBar->addAction(sentToLibrary); 0253 menuList << sentToLibrary; 0254 connect(this, &LibraryWidget::enableAddSelection, sentToLibrary, &QAction::setEnabled); 0255 0256 QAction *openFolder = new QAction(QIcon::fromTheme(QStringLiteral("edit-find")), i18n("Open Containing Folder"), this); 0257 connect(openFolder, &QAction::triggered, this, &LibraryWidget::slotOpenFolder); 0258 menuList << openFolder; 0259 0260 // Create spacer 0261 QWidget *spacer = new QWidget(); 0262 spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 0263 m_toolBar->addWidget(spacer); 0264 m_toolBar->addSeparator(); 0265 m_toolBar->addAction(m_deleteAction); 0266 m_libraryTree->addActions(menuList); 0267 connect(m_libraryTree, &QTreeWidget::itemSelectionChanged, this, &LibraryWidget::updateActions); 0268 } 0269 0270 void LibraryWidget::slotAddToLibrary() 0271 { 0272 if (!isEnabled()) { 0273 return; 0274 } 0275 QTreeWidgetItem *current = m_libraryTree->currentItem(); 0276 m_selectNewFile = true; 0277 if (current) { 0278 if (current->data(0, Qt::UserRole + 2).toInt() != LibraryItem::Folder) { 0279 current = current->parent(); 0280 } 0281 if (current && current->data(0, Qt::UserRole + 2).toInt() == LibraryItem::Folder) { 0282 // We are in a folder, send correct path 0283 const QString path = current->data(0, Qt::UserRole).toString(); 0284 QDir directory(path); 0285 if (path.isEmpty() || !directory.exists()) { 0286 directory = m_directory; 0287 } 0288 Q_EMIT saveTimelineSelection(directory); 0289 return; 0290 } 0291 } 0292 Q_EMIT saveTimelineSelection(m_directory); 0293 } 0294 0295 void LibraryWidget::showMessage(const QString &text, KMessageWidget::MessageType type) 0296 { 0297 m_timer.stop(); 0298 m_infoWidget->setText(text); 0299 m_infoWidget->setWordWrap(m_infoWidget->text().length() > 35); 0300 m_infoWidget->setMessageType(type); 0301 m_infoWidget->animatedShow(); 0302 m_timer.start(); 0303 } 0304 0305 void LibraryWidget::slotAddToProject() 0306 { 0307 QTreeWidgetItem *current = m_libraryTree->currentItem(); 0308 if (!current) { 0309 return; 0310 } 0311 const QList<QUrl> list = {QUrl::fromLocalFile(current->data(0, Qt::UserRole).toString())}; 0312 Q_EMIT addProjectClips(list); 0313 } 0314 0315 void LibraryWidget::updateActions() 0316 { 0317 QTreeWidgetItem *current = m_libraryTree->currentItem(); 0318 if (!current) { 0319 m_addAction->setEnabled(false); 0320 m_deleteAction->setEnabled(false); 0321 return; 0322 } 0323 m_addAction->setEnabled(true); 0324 m_deleteAction->setEnabled(true); 0325 } 0326 0327 void LibraryWidget::slotDeleteFromLibrary() 0328 { 0329 QTreeWidgetItem *current = m_libraryTree->currentItem(); 0330 if (!current) { 0331 qCDebug(KDENLIVE_LOG) << " * * *Deleting no item "; 0332 return; 0333 } 0334 QString path = current->data(0, Qt::UserRole).toString(); 0335 if (path.isEmpty()) { 0336 return; 0337 } 0338 if (current->data(0, Qt::UserRole + 2).toInt() == LibraryItem::Folder) { 0339 // Deleting a folder 0340 QDir dir(path); 0341 // Make sure we are really trying to remove a directory located in the library folder 0342 if (!path.startsWith(m_directory.absolutePath())) { 0343 showMessage(i18n("You are trying to remove an invalid folder: %1", path)); 0344 return; 0345 } 0346 const QStringList fileList = dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); 0347 if (!fileList.isEmpty()) { 0348 if (KMessageBox::warningContinueCancel(this, i18n("This will delete the folder %1, including all playlists in it.\nThis cannot be undone", path)) != 0349 KMessageBox::Continue) { 0350 return; 0351 } 0352 } 0353 dir.removeRecursively(); 0354 } else { 0355 QString message; 0356 if (current->data(0, Qt::UserRole + 2).toInt() == LibraryItem::PlayList) { 0357 message = i18n("This will delete the MLT playlist:\n%1", path); 0358 } else { 0359 message = i18n("This will delete the file:\n%1", path); 0360 } 0361 if (KMessageBox::warningContinueCancel(this, message) != KMessageBox::Continue) { 0362 return; 0363 } 0364 // Remove playlist 0365 if (!QFile::remove(path)) { 0366 showMessage(i18n("Error removing %1", path)); 0367 } 0368 } 0369 } 0370 0371 void LibraryWidget::slotOpenFolder() 0372 { 0373 QTreeWidgetItem *current = m_libraryTree->currentItem(); 0374 if (current) { 0375 const QString filePath = current->data(0, Qt::UserRole).toString(); 0376 KIO::highlightInFileManager({QUrl::fromLocalFile(filePath)}); 0377 } 0378 } 0379 0380 void LibraryWidget::slotAddFolder() 0381 { 0382 bool ok; 0383 QString name = QInputDialog::getText(this, i18nc("@title:window", "Add Folder to Library"), i18n("Enter a folder name"), QLineEdit::Normal, QString(), &ok); 0384 if (name.isEmpty() || !ok) { 0385 return; 0386 } 0387 QTreeWidgetItem *current = m_libraryTree->currentItem(); 0388 QString parentFolder; 0389 if (current) { 0390 if (current->data(0, Qt::UserRole + 2).toInt() == LibraryItem::Folder) { 0391 // Creating a subfolder 0392 parentFolder = current->data(0, Qt::UserRole).toString(); 0393 } else { 0394 QTreeWidgetItem *parentItem = current->parent(); 0395 if (parentItem) { 0396 parentFolder = parentItem->data(0, Qt::UserRole).toString(); 0397 } 0398 } 0399 } 0400 if (parentFolder.isEmpty()) { 0401 parentFolder = m_directory.absolutePath(); 0402 } 0403 QDir dir(parentFolder); 0404 if (dir.exists(name)) { 0405 showMessage(i18n("Folder %1 already exists", name)); 0406 return; 0407 } 0408 if (!dir.mkdir(name)) { 0409 showMessage(i18n("Error creating folder %1", name)); 0410 return; 0411 } 0412 } 0413 0414 void LibraryWidget::slotRenameItem() 0415 { 0416 QTreeWidgetItem *current = m_libraryTree->currentItem(); 0417 if (!current) { 0418 // This is not a folder, abort 0419 return; 0420 } 0421 m_libraryTree->editItem(current); 0422 } 0423 0424 void LibraryWidget::slotMoveData(const QList<QUrl> &urls, QString dest) 0425 { 0426 if (urls.isEmpty()) { 0427 return; 0428 } 0429 if (dest.isEmpty()) { 0430 // moving to library's root 0431 dest = m_directory.absolutePath(); 0432 } 0433 QDir dir(dest); 0434 if (!dir.exists()) { 0435 return; 0436 } 0437 for (const QUrl &url : urls) { 0438 if (!url.toLocalFile().startsWith(m_directory.absolutePath())) { 0439 // Dropped an external file, attempt to copy it to library 0440 KIO::FileCopyJob *copyJob = KIO::file_copy(url, QUrl::fromLocalFile(dir.absoluteFilePath(url.fileName()))); 0441 connect(copyJob, &KJob::result, this, &LibraryWidget::slotDownloadFinished); 0442 connect(copyJob, SIGNAL(percent(KJob *, ulong)), this, SLOT(slotDownloadProgress(KJob *, ulong))); 0443 } else { 0444 // Internal drag/drop 0445 dir.rename(url.toLocalFile(), url.fileName()); 0446 } 0447 } 0448 } 0449 0450 void LibraryWidget::slotSaveSequence(const QStringList &info, QString dest) 0451 { 0452 if (info.isEmpty()) { 0453 return; 0454 } 0455 if (dest.isEmpty()) { 0456 // moving to library's root 0457 dest = m_directory.absolutePath(); 0458 } 0459 QDir dir(dest); 0460 if (!dir.exists()) { 0461 return; 0462 } 0463 m_selectNewFile = true; 0464 m_manager->saveZone(info, dir); 0465 } 0466 0467 void LibraryWidget::slotItemEdited(QTreeWidgetItem *item, int column) 0468 { 0469 if ((item == nullptr) || column != 0) { 0470 return; 0471 } 0472 if (item->data(0, Qt::UserRole + 2).toInt() == LibraryItem::Folder) { 0473 QDir dir(item->data(0, Qt::UserRole).toString()); 0474 dir.cdUp(); 0475 dir.rename(item->data(0, Qt::UserRole).toString(), item->text(0)); 0476 // item->setData(0, Qt::UserRole, dir.absoluteFilePath(item->text(0))); 0477 } else { 0478 QString oldPath = item->data(0, Qt::UserRole).toString(); 0479 QDir dir(QUrl::fromLocalFile(oldPath).adjusted(QUrl::RemoveFilename).toLocalFile()); 0480 dir.rename(oldPath, item->text(0)); 0481 // item->setData(0, Qt::UserRole, dir.absoluteFilePath(item->text(0))); 0482 } 0483 } 0484 0485 void LibraryWidget::slotDownloadFinished(KJob *) 0486 { 0487 m_progressBar->setValue(100); 0488 m_progressBar->setVisible(false); 0489 } 0490 0491 void LibraryWidget::slotDownloadProgress(KJob *, int progress) 0492 { 0493 m_progressBar->setVisible(true); 0494 m_progressBar->setValue(progress); 0495 } 0496 0497 void LibraryWidget::slotUpdateLibraryPath() 0498 { 0499 // Library path changed, reload library with updated path 0500 m_libraryTree->blockSignals(true); 0501 m_folders.clear(); 0502 m_libraryTree->clear(); 0503 QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/library"); 0504 if (KdenliveSettings::librarytodefaultfolder() || KdenliveSettings::libraryfolder().isEmpty()) { 0505 m_directory.setPath(defaultPath); 0506 if (!m_directory.exists()) { 0507 m_directory.mkpath(QStringLiteral(".")); 0508 } 0509 showMessage(i18n("Library path set to default: %1", defaultPath), KMessageWidget::Information); 0510 } else { 0511 m_directory.setPath(KdenliveSettings::libraryfolder()); 0512 if (!m_directory.exists()) { 0513 m_directory.mkpath(QStringLiteral(".")); 0514 } 0515 showMessage(i18n("Library path set to custom: %1", KdenliveSettings::libraryfolder()), KMessageWidget::Information); 0516 } 0517 QFileInfo fi(m_directory.absolutePath()); 0518 if (!m_directory.exists() || !fi.isWritable()) { 0519 // Cannot write to new Library, try default one 0520 if (m_directory.absolutePath() != defaultPath) { 0521 showMessage(i18n("Cannot write to Library path: %1, using default", KdenliveSettings::libraryfolder()), KMessageWidget::Warning); 0522 m_directory.setPath(defaultPath); 0523 if (!m_directory.exists()) { 0524 m_directory.mkpath(QStringLiteral(".")); 0525 } 0526 } 0527 } 0528 fi.setFile(m_directory.absolutePath()); 0529 if (!m_directory.exists() || !fi.isWritable()) { 0530 // Something is really broken, disable library 0531 showMessage(i18n("Check your settings, Library path is invalid: %1", m_directory.absolutePath()), KMessageWidget::Warning); 0532 setEnabled(false); 0533 } else { 0534 m_coreLister->openUrl(QUrl::fromLocalFile(m_directory.absolutePath())); 0535 setEnabled(true); 0536 } 0537 m_libraryTree->blockSignals(false); 0538 } 0539 0540 void LibraryWidget::slotGotPreview(const KFileItem &item, const QPixmap &pix) 0541 { 0542 const QString path = item.url().toLocalFile(); 0543 m_libraryTree->blockSignals(true); 0544 m_libraryTree->slotUpdateThumb(path, pix); 0545 m_libraryTree->blockSignals(false); 0546 } 0547 0548 void LibraryWidget::slotItemsDeleted(const KFileItemList &list) 0549 { 0550 m_libraryTree->blockSignals(true); 0551 QMutexLocker lock(&m_treeMutex); 0552 for (const KFileItem &fitem : list) { 0553 QUrl fileUrl = fitem.url(); 0554 QString path; 0555 if (fitem.isDir()) { 0556 path = fileUrl.toLocalFile(); 0557 } else { 0558 path = fileUrl.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toLocalFile(); 0559 } 0560 QTreeWidgetItem *matchingFolder = nullptr; 0561 if (path != m_directory.absolutePath()) { 0562 for (QTreeWidgetItem *folder : qAsConst(m_folders)) { 0563 if (folder->data(0, Qt::UserRole).toString() == path) { 0564 // Found parent folder 0565 matchingFolder = folder; 0566 break; 0567 } 0568 } 0569 } 0570 if (fitem.isDir()) { 0571 if (matchingFolder) { 0572 m_folders.removeAll(matchingFolder); 0573 // warning, we also need to remove all subfolders since they will be recreated 0574 QList<QTreeWidgetItem *> subList; 0575 for (QTreeWidgetItem *folder : qAsConst(m_folders)) { 0576 if (folder->data(0, Qt::UserRole).toString().startsWith(path)) { 0577 subList << folder; 0578 } 0579 } 0580 for (QTreeWidgetItem *sub : qAsConst(subList)) { 0581 m_folders.removeAll(sub); 0582 } 0583 delete matchingFolder; 0584 } 0585 } else { 0586 if (matchingFolder == nullptr) { 0587 matchingFolder = m_libraryTree->invisibleRootItem(); 0588 } 0589 for (int i = 0; i < matchingFolder->childCount(); i++) { 0590 QTreeWidgetItem *item = matchingFolder->child(i); 0591 if (item->data(0, Qt::UserRole).toString() == fileUrl.toLocalFile()) { 0592 // Found deleted item 0593 delete item; 0594 break; 0595 } 0596 } 0597 } 0598 } 0599 m_libraryTree->blockSignals(false); 0600 } 0601 0602 void LibraryWidget::slotItemsAdded(const QUrl &url, const KFileItemList &list) 0603 { 0604 m_libraryTree->blockSignals(true); 0605 QMutexLocker lock(&m_treeMutex); 0606 for (const KFileItem &fitem : list) { 0607 QUrl fileUrl = fitem.url(); 0608 QString name = fileUrl.fileName(); 0609 QTreeWidgetItem *treeItem; 0610 QTreeWidgetItem *parent = nullptr; 0611 if (url != QUrl::fromLocalFile(m_directory.absolutePath())) { 0612 // not a top level item 0613 QString directory = fileUrl.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toLocalFile(); 0614 for (QTreeWidgetItem *folder : qAsConst(m_folders)) { 0615 if (folder->data(0, Qt::UserRole).toString() == directory) { 0616 // Found parent folder 0617 parent = folder; 0618 break; 0619 } 0620 } 0621 } 0622 if (parent) { 0623 treeItem = new QTreeWidgetItem(parent, QStringList() << name); 0624 } else { 0625 treeItem = new QTreeWidgetItem(m_libraryTree, QStringList() << name); 0626 } 0627 treeItem->setData(0, Qt::UserRole, fileUrl.toLocalFile()); 0628 treeItem->setData(0, Qt::UserRole + 1, fitem.timeString()); 0629 if (fitem.isDir()) { 0630 treeItem->setData(0, Qt::UserRole + 2, int(LibraryItem::Folder)); 0631 m_folders << treeItem; 0632 m_coreLister->openUrl(fileUrl, KCoreDirLister::Keep); 0633 } else if (name.endsWith(QLatin1String(".mlt")) || name.endsWith(QLatin1String(".kdenlive"))) { 0634 treeItem->setData(0, Qt::UserRole + 2, int(LibraryItem::PlayList)); 0635 } else { 0636 treeItem->setData(0, Qt::UserRole + 2, int(LibraryItem::Clip)); 0637 } 0638 treeItem->setData(0, Qt::DecorationRole, QIcon::fromTheme(fitem.iconName())); 0639 treeItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable); 0640 if (m_selectNewFile) { 0641 m_libraryTree->setCurrentItem(treeItem); 0642 m_selectNewFile = false; 0643 } 0644 } 0645 QStringList plugins = KIO::PreviewJob::availablePlugins(); 0646 m_previewJob = KIO::filePreview(list, QSize(80, 80), &plugins); 0647 m_previewJob->setIgnoreMaximumSize(); 0648 connect(m_previewJob, &KIO::PreviewJob::gotPreview, this, &LibraryWidget::slotGotPreview); 0649 m_libraryTree->blockSignals(false); 0650 } 0651 0652 void LibraryWidget::slotClearAll() 0653 { 0654 m_libraryTree->blockSignals(true); 0655 m_folders.clear(); 0656 m_libraryTree->clear(); 0657 m_libraryTree->blockSignals(false); 0658 }