File indexing completed on 2024-04-28 04:51:29
0001 /* 0002 SPDX-FileCopyrightText: 2023 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 "mediabrowser.h" 0009 #include "bin.h" 0010 #include "clipcreator.hpp" 0011 #include "core.h" 0012 #include "dialogs/clipcreationdialog.h" 0013 #include "kdenlivesettings.h" 0014 #include "mainwindow.h" 0015 #include "project/dialogs/slideshowclip.h" 0016 0017 #include <KActionCollection> 0018 #include <KConfigGroup> 0019 #include <KDirLister> 0020 #include <KFileFilterCombo> 0021 #include <KFilePlacesModel> 0022 #include <KIconLoader> 0023 #include <KLocalizedString> 0024 #include <KRecentDirs> 0025 #include <KSharedConfig> 0026 #include <KUrlComboBox> 0027 #include <KUrlCompletion> 0028 #include <KUrlNavigator> 0029 #include <QAction> 0030 #include <QCheckBox> 0031 #include <QDesktopServices> 0032 #include <QHBoxLayout> 0033 #include <QKeyEvent> 0034 #include <QLabel> 0035 #include <QMenu> 0036 #include <QMimeDatabase> 0037 #include <QProcessEnvironment> 0038 #include <QToolBar> 0039 #include <QVBoxLayout> 0040 #include <kio_version.h> 0041 0042 MediaBrowser::MediaBrowser(QWidget *parent) 0043 : QWidget(parent) 0044 { 0045 QVBoxLayout *lay = new QVBoxLayout(this); 0046 lay->setSpacing(0); 0047 QToolBar *tb = new QToolBar(this); 0048 int size = style()->pixelMetric(QStyle::PM_SmallIconSize); 0049 QSize iconSize(size, size); 0050 tb->setIconSize(iconSize); 0051 QString clipFolder = KRecentDirs::dir(QStringLiteral(":KdenliveClipFolder")); 0052 KFilePlacesModel *places = new KFilePlacesModel(this); 0053 QAction *zoomIn = new QAction(QIcon::fromTheme("zoom-in"), i18n("Zoom In")); 0054 QAction *zoomOut = new QAction(QIcon::fromTheme("zoom-out"), i18n("Zoom Out")); 0055 QAction *importAction = new QAction(QIcon::fromTheme("document-open"), i18n("Import Selection")); 0056 connect(importAction, &QAction::triggered, this, [this]() { importSelection(); }); 0057 QAction *importOnDoubleClick = new QAction(QIcon::fromTheme("document-open"), i18n("Import File on Double Click")); 0058 importOnDoubleClick->setCheckable(true); 0059 importOnDoubleClick->setChecked(KdenliveSettings::mediaDoubleClickImport()); 0060 connect(importOnDoubleClick, &QAction::triggered, this, [](bool enabled) { KdenliveSettings::setMediaDoubleClickImport(enabled); }); 0061 0062 // Create View 0063 m_op = new KDirOperator(QUrl(), parent); 0064 m_op->dirLister()->setAutoUpdate(false); 0065 // Ensure shortcuts are only active on this widget to avoid conflicts with app shortcuts 0066 #if KIO_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0067 QList<QAction *> actions = m_op->allActions(); 0068 QAction *trash = m_op->action(KDirOperator::Trash); 0069 QAction *up = m_op->action(KDirOperator::Up); 0070 QAction *back = m_op->action(KDirOperator::Back); 0071 QAction *forward = m_op->action(KDirOperator::Forward); 0072 QAction *inlinePreview = m_op->action(KDirOperator::ShowPreviewPanel); 0073 QAction *preview = m_op->action(KDirOperator::ShowPreviewPanel); 0074 QAction *viewMenu = m_op->action(KDirOperator::ViewModeMenu); 0075 #else 0076 QList<QAction *> actions = m_op->actionCollection()->actions(); 0077 QAction *trash = m_op->actionCollection()->action("trash"); 0078 QAction *up = m_op->actionCollection()->action("up"); 0079 QAction *back = m_op->actionCollection()->action("back"); 0080 QAction *forward = m_op->actionCollection()->action("forward"); 0081 QAction *inlinePreview = m_op->actionCollection()->action("inline preview"); 0082 QAction *preview = m_op->actionCollection()->action("preview"); 0083 QAction *viewMenu = m_op->actionCollection()->action("view menu"); 0084 #endif 0085 // Disable "Del" shortcut to move item to trash - too dangerous ?? 0086 trash->setShortcut({}); 0087 // Plug actions 0088 tb->addAction(up); 0089 tb->addAction(back); 0090 tb->addAction(forward); 0091 0092 tb->addAction(zoomOut); 0093 tb->addAction(zoomIn); 0094 tb->addAction(inlinePreview); 0095 tb->addSeparator(); 0096 tb->addAction(importAction); 0097 preview->setIcon(QIcon::fromTheme(QStringLiteral("fileview-preview"))); 0098 0099 // Menu button with extra actions 0100 QToolButton *but = new QToolButton(this); 0101 QMenu *configMenu = new QMenu(this); 0102 configMenu->addAction(importOnDoubleClick); 0103 configMenu->addAction(preview); 0104 configMenu->addAction(viewMenu); 0105 but->setIcon(QIcon::fromTheme(QStringLiteral("application-menu"))); 0106 but->setMenu(configMenu); 0107 but->setPopupMode(QToolButton::InstantPopup); 0108 0109 // Spacer 0110 QWidget *empty = new QWidget(this); 0111 empty->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); 0112 tb->addWidget(empty); 0113 tb->addWidget(but); 0114 0115 connect(zoomIn, &QAction::triggered, this, [this]() { 0116 int iconZoom = m_op->iconSize(); 0117 int newZoom = iconZoom * 1.5; 0118 m_op->setIconSize(qMin(512, newZoom)); 0119 }); 0120 connect(zoomOut, &QAction::triggered, this, [this]() { 0121 int iconZoom = m_op->iconSize() / 1.5; 0122 iconZoom = qMax(int(KIconLoader::SizeSmall), iconZoom); 0123 m_op->setIconSize(iconZoom); 0124 }); 0125 KConfigGroup grp(KSharedConfig::openConfig(), "Media Browser"); 0126 m_op->readConfig(grp); 0127 #if KIO_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0128 m_op->setViewMode(KFile::Default); 0129 #else 0130 m_op->setView(KFile::Default); 0131 #endif 0132 m_op->setMode(KFile::ExistingOnly | KFile::Files | KFile::Directory); 0133 m_op->setIconSize(KdenliveSettings::mediaIconSize()); 0134 m_filterCombo = new KFileFilterCombo(this); 0135 m_filenameEdit = new KUrlComboBox(KUrlComboBox::Files, true, this); 0136 m_locationEdit = new KUrlNavigator(places, QUrl(), this); 0137 connect(m_locationEdit, &KUrlNavigator::urlChanged, this, [this](const QUrl url) { m_op->setUrl(url, true); }); 0138 0139 connect(m_op, &KDirOperator::urlEntered, this, &MediaBrowser::slotUrlEntered); 0140 connect(m_op, &KDirOperator::viewChanged, this, &MediaBrowser::connectView); 0141 connect(m_op, &KDirOperator::currentIconSizeChanged, this, [](int size) { KdenliveSettings::setMediaIconSize(size); }); 0142 connect(m_op, &KDirOperator::fileHighlighted, this, [this](const KFileItem &item) { 0143 KFileItemList files = m_op->selectedItems(); 0144 if (item.isDir() || files.size() == 0) { 0145 m_filenameEdit->clear(); 0146 } else { 0147 const QString fileName = files.first().url().fileName(); 0148 if (!fileName.isEmpty()) { 0149 m_filenameEdit->setUrl(QUrl(fileName)); 0150 } 0151 } 0152 }); 0153 connect(m_op, &KDirOperator::contextMenuAboutToShow, this, [importAction](const KFileItem &, QMenu *menu) { 0154 QList<QAction *> act = menu->actions(); 0155 if (act.isEmpty()) { 0156 menu->addAction(importAction); 0157 } else if (!act.contains(importAction)) { 0158 menu->insertAction(act.first(), importAction); 0159 } 0160 }); 0161 0162 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0163 QString allExtensions = ClipCreationDialog::getExtensions().join(QLatin1Char(' ')); 0164 QString dialogFilter = allExtensions + QLatin1Char('|') + i18n("All Supported Files") + QStringLiteral("\n*|") + i18n("All Files"); 0165 m_filterCombo->setFilter(dialogFilter); 0166 m_op->setNameFilter(m_filterCombo->currentFilter()); 0167 #else 0168 QStringList allExtensions = ClipCreationDialog::getExtensions(); 0169 0170 const QList<KFileFilter> filters{ 0171 KFileFilter(i18n("All Supported Files"), allExtensions, {}), 0172 KFileFilter(i18n("All Files"), {QStringLiteral("*")}, {}), 0173 }; 0174 0175 m_filterCombo->setFilters(filters, filters.first()); 0176 m_op->setNameFilter(filters.first().toFilterString()); 0177 #endif 0178 0179 // Setup mime filter combo 0180 m_filterCombo->setEditable(true); 0181 m_filterCombo->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); 0182 connect(m_filterCombo, &KFileFilterCombo::filterChanged, this, [this]() { slotFilterChanged(); }); 0183 m_filterDelayTimer.setSingleShot(true); 0184 m_filterDelayTimer.setInterval(300); 0185 connect(m_filterCombo, &QComboBox::editTextChanged, &m_filterDelayTimer, qOverload<>(&QTimer::start)); 0186 connect(&m_filterDelayTimer, &QTimer::timeout, this, [this]() { slotFilterChanged(); }); 0187 0188 // Load initial folder 0189 m_op->setUrl(QUrl::fromLocalFile(clipFolder), true); 0190 0191 // Setup file name field 0192 m_filenameEdit->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); 0193 connect(m_filenameEdit, &KUrlComboBox::editTextChanged, this, [this](const QString &text) { slotLocationChanged(text); }); 0194 connect(m_filenameEdit, qOverload<const QString &>(&KUrlComboBox::returnPressed), this, [this](const QString &) { 0195 KFileItemList files = m_op->selectedItems(); 0196 if (files.size() == 1 && files.first().isDir()) { 0197 m_op->setUrl(m_op->url().resolved(files.first().url()), true); 0198 } else { 0199 importSelection(); 0200 } 0201 }); 0202 KUrlCompletion *fileCompletionObj = new KUrlCompletion(KUrlCompletion::FileCompletion); 0203 fileCompletionObj->setDir(m_op->url()); 0204 m_filenameEdit->setCompletionObject(fileCompletionObj); 0205 m_filenameEdit->setAutoDeleteCompletionObject(true); 0206 0207 // Layout stuff 0208 // File name 0209 QHBoxLayout *hlay1 = new QHBoxLayout; 0210 hlay1->addWidget(new QLabel(i18n("Name:"), this)); 0211 hlay1->addWidget(m_filenameEdit); 0212 // Mime filter 0213 QHBoxLayout *hlay2 = new QHBoxLayout; 0214 hlay2->addWidget(new QLabel(i18n("Filter:"), this)); 0215 hlay2->addWidget(m_filterCombo); 0216 // Checkbox options 0217 QHBoxLayout *hlay3 = new QHBoxLayout; 0218 QCheckBox *b = new QCheckBox(i18n("Ignore subfolder structure")); 0219 b->setChecked(KdenliveSettings::ignoresubdirstructure()); 0220 b->setToolTip(i18n("Do not create subfolders in Project Bin")); 0221 b->setWhatsThis( 0222 xi18nc("@info:whatsthis", 0223 "When enabled, Kdenlive will import all clips contained in the folder and its subfolders without creating the subfolders in Project Bin.")); 0224 connect(b, &QCheckBox::toggled, this, [](bool enabled) { KdenliveSettings::setIgnoresubdirstructure(enabled); }); 0225 0226 QCheckBox *b2 = new QCheckBox(i18n("Import image sequence")); 0227 b2->setChecked(KdenliveSettings::autoimagesequence()); 0228 connect(b2, &QCheckBox::toggled, this, [](bool enabled) { KdenliveSettings::setAutoimagesequence(enabled); }); 0229 b2->setToolTip(i18n("Try to import an image sequence")); 0230 b2->setWhatsThis( 0231 xi18nc("@info:whatsthis", "When enabled, Kdenlive will look for other images with the same name pattern and import them as an image sequence.")); 0232 hlay3->addWidget(b2); 0233 hlay3->addWidget(b); 0234 lay->addWidget(tb); 0235 lay->addWidget(m_locationEdit); 0236 lay->addWidget(m_op); 0237 lay->addLayout(hlay1); 0238 lay->addLayout(hlay2); 0239 lay->addLayout(hlay3); 0240 for (QObject *child : children()) { 0241 if (child->isWidgetType()) { 0242 child->installEventFilter(this); 0243 } 0244 } 0245 connectView(); 0246 } 0247 0248 MediaBrowser::~MediaBrowser() 0249 { 0250 KConfigGroup grp(KSharedConfig::openConfig(), "Media Browser"); 0251 m_op->writeConfig(grp); 0252 } 0253 0254 void MediaBrowser::connectView() 0255 { 0256 connect(m_op->view(), &QAbstractItemView::doubleClicked, this, &MediaBrowser::slotViewDoubleClicked); 0257 m_op->view()->installEventFilter(this); 0258 setFocusProxy(m_op->view()); 0259 setFocusPolicy(Qt::ClickFocus); 0260 } 0261 0262 void MediaBrowser::slotViewDoubleClicked() 0263 { 0264 if (KdenliveSettings::mediaDoubleClickImport()) { 0265 importSelection(); 0266 return; 0267 } 0268 KFileItemList files = m_op->selectedItems(); 0269 if (files.isEmpty()) { 0270 return; 0271 } 0272 if (files.first().isDir()) { 0273 return; 0274 } 0275 openExternalFile(files.first().url()); 0276 } 0277 0278 void MediaBrowser::detectShortcutConflicts() 0279 { 0280 #if KIO_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0281 QList<QAction *> actions = m_op->allActions(); 0282 #else 0283 QList<QAction *> actions = m_op->actionCollection()->actions(); 0284 #endif 0285 QList<QKeySequence> shortcutsList; 0286 m_browserActions.clear(); 0287 m_conflictingAppActions.clear(); 0288 for (auto &a : actions) { 0289 QKeySequence sh = a->shortcut(); 0290 if (!sh.isEmpty()) { 0291 shortcutsList << sh; 0292 m_browserActions << a; 0293 a->setEnabled(false); 0294 } 0295 } 0296 // qDebug()<<"::: FOUND BROWSER SHORTCUTS: "<<shortcutsList<<"\n__________________________"; 0297 QList<QAction *> appActions = pCore->window()->actionCollection()->actions(); 0298 for (auto &a : appActions) { 0299 QKeySequence sh = a->shortcut(); 0300 if (!sh.isEmpty() && shortcutsList.contains(sh)) { 0301 m_conflictingAppActions << a; 0302 } 0303 } 0304 } 0305 0306 void MediaBrowser::importSelection() 0307 { 0308 KFileItemList files = m_op->selectedItems(); 0309 if (KdenliveSettings::autoimagesequence() && files.size() == 1) { 0310 QMimeDatabase db; 0311 QUrl url = files.first().url(); 0312 QMimeType type = db.mimeTypeForUrl(url); 0313 0314 QDomElement prod; 0315 qDebug() << "=== GOT DROPPED MIME: " << type.name(); 0316 if (type.name().startsWith(QLatin1String("image/")) && !type.name().contains(QLatin1String("image/gif"))) { 0317 QStringList patternlist; 0318 QString pattern = SlideshowClip::selectedPath(url, false, QString(), &patternlist); 0319 Timecode tc = pCore->timecode(); 0320 QScopedPointer<SlideshowClip> dia(new SlideshowClip(tc, url.toLocalFile(), nullptr, this)); 0321 if (dia->exec() == QDialog::Accepted) { 0322 QString parentFolder = "-1"; 0323 std::unordered_map<QString, QString> properties; 0324 properties[QStringLiteral("ttl")] = QString::number(tc.getFrameCount(dia->clipDuration())); 0325 properties[QStringLiteral("loop")] = QString::number(static_cast<int>(dia->loop())); 0326 properties[QStringLiteral("crop")] = QString::number(static_cast<int>(dia->crop())); 0327 properties[QStringLiteral("fade")] = QString::number(static_cast<int>(dia->fade())); 0328 properties[QStringLiteral("luma_duration")] = QString::number(tc.getFrameCount(dia->lumaDuration())); 0329 properties[QStringLiteral("luma_file")] = dia->lumaFile(); 0330 properties[QStringLiteral("softness")] = QString::number(dia->softness()); 0331 properties[QStringLiteral("animation")] = dia->animation(); 0332 properties[QStringLiteral("low-pass")] = QString::number(dia->lowPass()); 0333 int duration = tc.getFrameCount(dia->clipDuration()) * dia->imageCount(); 0334 ClipCreator::createSlideshowClip(dia->selectedPath(), duration, dia->clipName(), parentFolder, properties, pCore->projectItemModel()); 0335 } 0336 return; 0337 } 0338 } 0339 QList<QUrl> urls; 0340 for (auto &f : files) { 0341 urls << f.url(); 0342 } 0343 pCore->bin()->droppedUrls(urls); 0344 } 0345 0346 const QUrl MediaBrowser::url() const 0347 { 0348 return m_op->url(); 0349 } 0350 0351 bool MediaBrowser::eventFilter(QObject *watched, QEvent *event) 0352 { 0353 // To avoid shortcut conflicts between the media browser and main app, we dis/enable actions when we gain/lose focus 0354 if (event->type() == QEvent::FocusIn) { 0355 qDebug() << ":::::: \n\nFOCUS IN\n\n:::::::::::::::::"; 0356 disableAppShortcuts(); 0357 } else if (event->type() == QEvent::FocusOut) { 0358 qDebug() << ":::::: \n\nFOCUS OUT\n\n:::::::::::::::::"; 0359 enableAppShortcuts(); 0360 } else if (event->type() == QEvent::Hide) { 0361 if (m_op->dirLister()->autoUpdate()) { 0362 m_op->dirLister()->setAutoUpdate(false); 0363 } 0364 } else if (event->type() == QEvent::Show) { 0365 if (!m_op->dirLister()->autoUpdate()) { 0366 m_op->dirLister()->setAutoUpdate(true); 0367 } 0368 } 0369 const bool res = QWidget::eventFilter(watched, event); 0370 QKeyEvent *keyEvent = dynamic_cast<QKeyEvent *>(event); 0371 if (!keyEvent) { 0372 return res; 0373 } 0374 0375 const auto type = event->type(); 0376 const auto key = keyEvent->key(); 0377 0378 if (watched == m_op && type == QEvent::KeyPress && (key == Qt::Key_Return || key == Qt::Key_Enter)) { 0379 // ignore return events from the KDirOperator 0380 importSelection(); 0381 event->accept(); 0382 return true; 0383 } 0384 return res; 0385 } 0386 0387 void MediaBrowser::disableAppShortcuts() 0388 { 0389 for (auto &a : m_conflictingAppActions) { 0390 if (a) { 0391 a->setEnabled(false); 0392 } 0393 } 0394 for (auto &a : m_browserActions) { 0395 if (a) { 0396 a->setEnabled(true); 0397 } 0398 } 0399 } 0400 0401 void MediaBrowser::enableAppShortcuts() 0402 { 0403 for (auto &a : m_browserActions) { 0404 if (a) { 0405 a->setEnabled(false); 0406 } 0407 } 0408 for (auto &a : m_conflictingAppActions) { 0409 if (a) { 0410 a->setEnabled(true); 0411 } 0412 } 0413 } 0414 0415 void MediaBrowser::slotUrlEntered(const QUrl &url) 0416 { 0417 QSignalBlocker bk(m_locationEdit); 0418 m_locationEdit->setLocationUrl(url); 0419 QSignalBlocker bk2(m_filenameEdit); 0420 KUrlCompletion *completion = dynamic_cast<KUrlCompletion *>(m_filenameEdit->completionObject()); 0421 if (completion) { 0422 completion->setDir(url); 0423 } 0424 } 0425 0426 void MediaBrowser::setUrl(const QUrl url) 0427 { 0428 m_op->setUrl(url, true); 0429 m_op->setIconSize(KdenliveSettings::mediaIconSize()); 0430 } 0431 0432 void MediaBrowser::slotFilterChanged() 0433 { 0434 m_filterDelayTimer.stop(); 0435 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0436 QString filter = m_filterCombo->currentFilter(); 0437 m_op->clearFilter(); 0438 if (filter.contains(QLatin1Char('/'))) { 0439 QStringList types = filter.split(QLatin1Char(' '), Qt::SkipEmptyParts); 0440 types.prepend(QStringLiteral("inode/directory")); 0441 m_op->setMimeFilter(types); 0442 } else if (filter.contains(QLatin1Char('*')) || filter.contains(QLatin1Char('?')) || filter.contains(QLatin1Char('['))) { 0443 m_op->setNameFilter(filter); 0444 } else { 0445 m_op->setNameFilter(QLatin1Char('*') + filter.replace(QLatin1Char(' '), QLatin1Char('*')) + QLatin1Char('*')); 0446 } 0447 #else 0448 KFileFilter filter = m_filterCombo->currentFilter(); 0449 m_op->clearFilter(); 0450 if (!filter.mimePatterns().isEmpty()) { 0451 QStringList types = filter.mimePatterns(); 0452 types.prepend(QStringLiteral("inode/directory")); 0453 m_op->setMimeFilter(types); 0454 } else { 0455 m_op->setNameFilter(filter.toFilterString()); 0456 } 0457 #endif 0458 m_op->updateDir(); 0459 } 0460 0461 void MediaBrowser::slotLocationChanged(const QString &text) 0462 { 0463 m_filenameEdit->lineEdit()->setModified(true); 0464 if (text.isEmpty() && m_op->view()) { 0465 m_op->view()->clearSelection(); 0466 } 0467 0468 if (!m_filenameEdit->lineEdit()->text().isEmpty()) { 0469 QUrl u = m_op->url().adjusted(QUrl::RemoveFilename); 0470 QUrl partial_url; 0471 partial_url.setPath(text); 0472 const QUrl finalUrl = u.resolved(partial_url); 0473 qDebug() << ":::: GOT FINAL URL: " << finalUrl << "\n_____________________"; 0474 ; 0475 // const QList<QUrl> urlList(tokenize(text)); 0476 m_op->setCurrentItem(finalUrl); 0477 } 0478 } 0479 0480 void MediaBrowser::openExternalFile(const QUrl &url) 0481 { 0482 if (pCore->packageType() == QStringLiteral("appimage")) { 0483 qDebug() << "::::: LAUNCHING APPIMAGE BROWSER........."; 0484 QProcess process; 0485 QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); 0486 qDebug() << "::: GOT ENV: " << env.value("LD_LIBRARY_PATH") << ", PATH: " << env.value("PATH") << "\n\nXDG:\n" << env.value("XDG_DATA_DIRS"); 0487 QStringList libPath = env.value(QStringLiteral("LD_LIBRARY_PATH")).split(QLatin1Char(':'), Qt::SkipEmptyParts); 0488 QStringList updatedLDPath; 0489 for (auto &s : libPath) { 0490 if (!s.startsWith(QStringLiteral("/tmp/.mount_"))) { 0491 updatedLDPath << s; 0492 } 0493 } 0494 if (updatedLDPath.isEmpty()) { 0495 env.remove(QStringLiteral("LD_LIBRARY_PATH")); 0496 } else { 0497 env.insert(QStringLiteral("LD_LIBRARY_PATH"), updatedLDPath.join(QLatin1Char(':'))); 0498 } 0499 // Path 0500 libPath = env.value(QStringLiteral("PATH")).split(QLatin1Char(':'), Qt::SkipEmptyParts); 0501 updatedLDPath.clear(); 0502 for (auto &s : libPath) { 0503 if (!s.startsWith(QStringLiteral("/tmp/.mount_"))) { 0504 updatedLDPath << s; 0505 } 0506 } 0507 if (updatedLDPath.isEmpty()) { 0508 env.remove(QStringLiteral("PATH")); 0509 } else { 0510 env.insert(QStringLiteral("PATH"), updatedLDPath.join(QLatin1Char(':'))); 0511 } 0512 // XDG 0513 libPath = env.value(QStringLiteral("XDG_DATA_DIRS")).split(QLatin1Char(':'), Qt::SkipEmptyParts); 0514 updatedLDPath.clear(); 0515 for (auto &s : libPath) { 0516 if (!s.startsWith(QStringLiteral("/tmp/.mount_"))) { 0517 updatedLDPath << s; 0518 } 0519 } 0520 if (updatedLDPath.isEmpty()) { 0521 env.remove(QStringLiteral("XDG_DATA_DIRS")); 0522 } else { 0523 env.insert(QStringLiteral("XDG_DATA_DIRS"), updatedLDPath.join(QLatin1Char(':'))); 0524 } 0525 env.remove(QStringLiteral("QT_QPA_PLATFORM")); 0526 process.setProcessEnvironment(env); 0527 QString openPath = QStandardPaths::findExecutable(QStringLiteral("xdg-open")); 0528 process.setProgram(openPath.isEmpty() ? QStringLiteral("xdg-open") : openPath); 0529 process.setArguments({url.toLocalFile()}); 0530 process.startDetached(); 0531 } else { 0532 QDesktopServices::openUrl(url); 0533 } 0534 } 0535 0536 void MediaBrowser::back() 0537 { 0538 m_op->back(); 0539 } 0540 0541 void MediaBrowser::forward() 0542 { 0543 m_op->forward(); 0544 }