File indexing completed on 2024-04-14 15:52:18

0001 /*
0002     SPDX-FileCopyrightText: 2002 Shie Erlich <erlich@users.sourceforge.net>
0003     SPDX-FileCopyrightText: 2002 Rafi Yanai <yanai@users.sourceforge.net>
0004     SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "panelmanager.h"
0010 
0011 #include "Panel/PanelView/krview.h"
0012 #include "Panel/PanelView/krviewfactory.h"
0013 #include "Panel/listpanel.h"
0014 #include "Panel/panelfunc.h"
0015 #include "defaults.h"
0016 #include "icon.h"
0017 #include "kractions.h"
0018 #include "krmainwindow.h"
0019 #include "krusaderview.h"
0020 #include "tabactions.h"
0021 
0022 #include <assert.h>
0023 
0024 // QtGui
0025 #include <QImage>
0026 // QtWidgets
0027 #include <QGridLayout>
0028 #include <QMenu>
0029 #include <QStackedWidget>
0030 #include <QToolButton>
0031 
0032 #include <KConfigCore/KConfig>
0033 #include <KI18n/KLocalizedString>
0034 
0035 PanelManager::PanelManager(QWidget *parent, KrMainWindow *mainWindow, bool left)
0036     : QWidget(parent)
0037     , _otherManager(nullptr)
0038     , _actions(mainWindow->tabActions())
0039     , _layout(nullptr)
0040     , _left(left)
0041     , _currentPanel(nullptr)
0042 {
0043     _layout = new QGridLayout(this);
0044     _layout->setContentsMargins(0, 0, 0, 0);
0045     _layout->setSpacing(0);
0046     _stack = new QStackedWidget(this);
0047 
0048     // new tab button
0049     _newTab = new QToolButton(this);
0050     _newTab->setAutoRaise(true);
0051     _newTab->setText(i18n("Open a new tab"));
0052     _newTab->setToolTip(i18n("Open a new tab"));
0053     _newTab->setIcon(Icon("tab-new"));
0054     _newTab->adjustSize();
0055     connect(_newTab, &QToolButton::clicked, this, &PanelManager::slotNewTabButton);
0056 
0057     // tab-bar
0058     _tabbar = new PanelTabBar(this, _actions);
0059     connect(_tabbar, &PanelTabBar::currentChanged, this, &PanelManager::slotCurrentTabChanged);
0060     connect(_tabbar, &PanelTabBar::tabCloseRequested, this, QOverload<int>::of(&PanelManager::slotCloseTab));
0061     connect(_tabbar, &PanelTabBar::closeCurrentTab, this, QOverload<>::of(&PanelManager::slotCloseTab));
0062     connect(_tabbar, &PanelTabBar::duplicateCurrentTab, this, &PanelManager::slotDuplicateTabLMB, Qt::QueuedConnection);
0063     connect(_tabbar, &PanelTabBar::newTab, this, [=](const QUrl &url) {
0064         slotNewTab(url);
0065     });
0066     connect(_tabbar, &PanelTabBar::draggingTab, this, &PanelManager::slotDraggingTab);
0067     connect(_tabbar, &PanelTabBar::draggingTabFinished, this, &PanelManager::slotDraggingTabFinished);
0068 
0069     auto *tabbarLayout = new QHBoxLayout;
0070     tabbarLayout->setSpacing(0);
0071     tabbarLayout->setContentsMargins(0, 0, 0, 0);
0072 
0073     tabbarLayout->addWidget(_tabbar);
0074     tabbarLayout->addWidget(_newTab);
0075 
0076     _layout->addWidget(_stack, 0, 0);
0077     _layout->addLayout(tabbarLayout, 1, 0);
0078 
0079     updateTabbarPos();
0080 
0081     setLayout(_layout);
0082 
0083     addPanel(true);
0084 
0085     tabsCountChanged();
0086 }
0087 
0088 void PanelManager::tabsCountChanged()
0089 {
0090     const KConfigGroup cfg(krConfig, "Look&Feel");
0091     const bool showTabbar = _tabbar->count() > 1 || cfg.readEntry("Show Tab Bar On Single Tab", true);
0092     const bool showNewButton = showTabbar && cfg.readEntry("Show New Tab Button", true);
0093     const bool showCloseButtons = showTabbar && cfg.readEntry("Show Close Tab Buttons", true);
0094 
0095     _tabbar->setVisible(showTabbar);
0096     _newTab->setVisible(showNewButton);
0097 
0098     // disable close button if only 1 tab is left
0099     _tabbar->setTabsClosable(showCloseButtons && _tabbar->count() > 1);
0100 
0101     _actions->refreshActions();
0102 }
0103 
0104 void PanelManager::activate()
0105 {
0106     assert(sender() == (currentPanel()->gui));
0107     emit setActiveManager(this);
0108     _actions->refreshActions();
0109 }
0110 
0111 void PanelManager::slotCurrentTabChanged(int index)
0112 {
0113     ListPanel *panel = _tabbar->getPanel(index);
0114 
0115     if (!panel || panel == _currentPanel)
0116         return;
0117 
0118     ListPanel *previousPanel = _currentPanel;
0119     _currentPanel = panel;
0120 
0121     _stack->setCurrentWidget(_currentPanel);
0122 
0123     if (previousPanel) {
0124         previousPanel->slotFocusOnMe(false); // FIXME - necessary ?
0125     }
0126     _currentPanel->slotFocusOnMe(this == ACTIVE_MNG);
0127 
0128     emit pathChanged(panel);
0129 
0130     if (otherManager()) {
0131         otherManager()->currentPanel()->otherPanelChanged();
0132     }
0133 
0134     // go back to pinned url if tab is pinned and switched back to active
0135     if (panel->isPinned()) {
0136         panel->func->openUrl(panel->pinnedUrl());
0137     }
0138 }
0139 
0140 ListPanel *PanelManager::createPanel(const KConfigGroup &cfg)
0141 {
0142     ListPanel *p = new ListPanel(_stack, this, cfg);
0143     connectPanel(p);
0144     return p;
0145 }
0146 
0147 void PanelManager::connectPanel(ListPanel *p)
0148 {
0149     connect(p, &ListPanel::activate, this, &PanelManager::activate);
0150     connect(p, &ListPanel::pathChanged, this, [=]() {
0151         emit pathChanged(p);
0152     });
0153     connect(p, &ListPanel::pathChanged, this, [=]() {
0154         _tabbar->updateTab(p);
0155     });
0156 }
0157 
0158 void PanelManager::disconnectPanel(ListPanel *p)
0159 {
0160     disconnect(p, &ListPanel::activate, this, nullptr);
0161     disconnect(p, &ListPanel::pathChanged, this, nullptr);
0162 }
0163 
0164 ListPanel *PanelManager::addPanel(bool setCurrent, const KConfigGroup &cfg, int insertIndex)
0165 {
0166     // create the panel and add it into the widgetstack
0167     ListPanel *p = createPanel(cfg);
0168     _stack->addWidget(p);
0169 
0170     // now, create the corresponding tab
0171     int index = _tabbar->addPanel(p, setCurrent, insertIndex);
0172     tabsCountChanged();
0173 
0174     if (setCurrent)
0175         slotCurrentTabChanged(index);
0176 
0177     return p;
0178 }
0179 
0180 ListPanel *PanelManager::duplicatePanel(const KConfigGroup &cfg, KrPanel *nextTo, int insertIndex)
0181 {
0182     // Search for the position where the passed panel is
0183     if (insertIndex == -1) {
0184         int quantOfPanels = _tabbar->count();
0185         for (int i = 0; i < quantOfPanels; i++) {
0186             if (_tabbar->getPanel(i) == nextTo) {
0187                 insertIndex = i + 1;
0188                 break;
0189             }
0190         }
0191     }
0192 
0193     return addPanel(true, cfg, insertIndex);
0194 }
0195 
0196 void PanelManager::saveSettings(KConfigGroup config, bool saveHistory)
0197 {
0198     config.writeEntry("ActiveTab", activeTab());
0199 
0200     KConfigGroup grpTabs(&config, "Tabs");
0201     foreach (const QString &grpTab, grpTabs.groupList())
0202         grpTabs.deleteGroup(grpTab);
0203 
0204     for (int i = 0; i < _tabbar->count(); i++) {
0205         ListPanel *panel = _tabbar->getPanel(i);
0206         KConfigGroup grpTab(&grpTabs, "Tab" + QString::number(i));
0207         panel->saveSettings(grpTab, saveHistory);
0208     }
0209 }
0210 
0211 void PanelManager::loadSettings(KConfigGroup config)
0212 {
0213     KConfigGroup grpTabs(&config, "Tabs");
0214     int numTabsOld = _tabbar->count();
0215     int numTabsNew = grpTabs.groupList().count();
0216 
0217     for (int i = 0; i < numTabsNew; i++) {
0218         KConfigGroup grpTab(&grpTabs, "Tab" + QString::number(i));
0219         // TODO workaround for bug 371453. Remove this when bug is fixed
0220         if (grpTab.keyList().isEmpty())
0221             continue;
0222 
0223         ListPanel *panel = i < numTabsOld ? _tabbar->getPanel(i) : addPanel(false, grpTab, i);
0224         panel->restoreSettings(grpTab);
0225         _tabbar->updateTab(panel);
0226     }
0227 
0228     for (int i = numTabsOld - 1; i >= numTabsNew && i > 0; i--)
0229         slotCloseTab(i);
0230 
0231     setActiveTab(config.readEntry("ActiveTab", 0));
0232 
0233     // this is needed so that all tab labels get updated
0234     layoutTabs();
0235 }
0236 
0237 void PanelManager::layoutTabs()
0238 {
0239     // delayed url refreshes may be pending -
0240     // delay the layout too so it happens after them
0241     QTimer::singleShot(0, _tabbar, &PanelTabBar::layoutTabs);
0242 }
0243 
0244 KrPanel *PanelManager::currentPanel() const
0245 {
0246     return _currentPanel;
0247 }
0248 
0249 void PanelManager::moveTabToOtherSide()
0250 {
0251     if (tabCount() < 2)
0252         return;
0253 
0254     ListPanel *p;
0255     _tabbar->removeCurrentPanel(p);
0256     _stack->removeWidget(p);
0257     disconnectPanel(p);
0258 
0259     p->reparent(_otherManager->_stack, _otherManager);
0260     _otherManager->connectPanel(p);
0261     _otherManager->_stack->addWidget(p);
0262     _otherManager->_tabbar->addPanel(p, true);
0263 
0264     _otherManager->tabsCountChanged();
0265     tabsCountChanged();
0266 
0267     p->slotFocusOnMe();
0268 }
0269 
0270 void PanelManager::moveTabToLeft()
0271 {
0272     // don't move the leftmost tab - also skip a single tab, always leftmost
0273     if (_tabbar->currentIndex() == 0)
0274         return;
0275 
0276     _tabbar->moveTab(_tabbar->currentIndex(), _tabbar->currentIndex() - 1);
0277 }
0278 
0279 void PanelManager::moveTabToRight()
0280 {
0281     // don't move the rightmost tab - also skip a single tab, always rightmost
0282     if (_tabbar->currentIndex() == tabCount() - 1)
0283         return;
0284 
0285     _tabbar->moveTab(_tabbar->currentIndex(), _tabbar->currentIndex() + 1);
0286 }
0287 
0288 void PanelManager::slotNewTab(const QUrl &url, bool setCurrent, int insertIndex)
0289 {
0290     ListPanel *p = addPanel(setCurrent, KConfigGroup(), insertIndex);
0291     p->start(url);
0292 }
0293 
0294 void PanelManager::slotNewTabButton()
0295 {
0296     KConfigGroup group(krConfig, "Look&Feel");
0297     int insertIndex = group.readEntry("Insert Tabs After Current", false) ? _tabbar->currentIndex() + 1 : _tabbar->count();
0298 
0299     if (group.readEntry("New Tab Button Duplicates", false)) {
0300         slotDuplicateTab(currentPanel()->virtualPath(), currentPanel(), insertIndex);
0301         _currentPanel->slotFocusOnMe();
0302     } else {
0303         slotNewTab(insertIndex);
0304     }
0305 }
0306 
0307 void PanelManager::slotNewTab(int insertIndex)
0308 {
0309     slotNewTab(QUrl::fromLocalFile(QDir::home().absolutePath()), true, insertIndex);
0310     _currentPanel->slotFocusOnMe();
0311 }
0312 
0313 void PanelManager::slotDuplicateTab(const QUrl &url, KrPanel *nextTo, int insertIndex)
0314 {
0315     ListPanel *p = duplicatePanel(KConfigGroup(), nextTo, insertIndex);
0316     if (nextTo && nextTo->gui) {
0317         // We duplicate tab settings by writing original settings to a temporary
0318         // group and making the new tab read settings from it. Duplicating
0319         // settings directly would add too much complexity.
0320         QString grpName = "PanelManager_" + QString::number(qApp->applicationPid());
0321         krConfig->deleteGroup(grpName); // make sure the group is empty
0322         KConfigGroup cfg(krConfig, grpName);
0323 
0324         nextTo->gui->saveSettings(cfg, true);
0325         // reset undesired duplicated settings
0326         cfg.writeEntry("Properties", 0);
0327         p->restoreSettings(cfg);
0328         krConfig->deleteGroup(grpName);
0329     }
0330     p->start(url);
0331 }
0332 
0333 void PanelManager::slotDuplicateTabLMB()
0334 {
0335     slotDuplicateTab(currentPanel()->virtualPath(), currentPanel());
0336 }
0337 
0338 void PanelManager::slotCloseTab()
0339 {
0340     slotCloseTab(_tabbar->currentIndex());
0341 }
0342 
0343 void PanelManager::slotCloseTab(int index)
0344 {
0345     if (_tabbar->count() <= 1) /* if this is the last tab don't close it */
0346         return;
0347 
0348     // Back up some data that will be useful if the user wants to
0349     // undo the closing of the tab
0350     QByteArray backupData;
0351     QDataStream tabStream(&backupData, QIODevice::WriteOnly); // In order to serialize data
0352     tabStream << _left;
0353     tabStream << index;
0354     ListPanel *panel = static_cast<ListPanel *>(currentPanel());
0355     const QUrl urlTab = panel->virtualPath();
0356     tabStream << urlTab;
0357     tabStream << panel->getProperties();
0358     tabStream << panel->pinnedUrl();
0359     tabStream << panel->view->selectedUrls();
0360 
0361     QAction *actReopenTab = KrActions::actClosedTabsMenu->updateAfterClosingATab(urlTab, backupData, _actions);
0362 
0363     // Save settings of the tab. Note: The code is
0364     // based on the one of slotDuplicateTab()
0365     QString grpName = QString("closedTab_%1").arg(reinterpret_cast<qulonglong>(actReopenTab));
0366     krConfig->deleteGroup(grpName); // make sure the group is empty
0367     KConfigGroup cfg(krConfig, grpName);
0368     panel->gui->saveSettings(cfg, true);
0369     // reset undesired duplicated settings
0370     cfg.writeEntry("Properties", 0);
0371 
0372     _tabbar->removePanel(index, panel); // this automatically changes the current panel
0373 
0374     _stack->removeWidget(panel);
0375     deletePanel(panel);
0376     tabsCountChanged();
0377 }
0378 
0379 void PanelManager::slotUndoCloseTab()
0380 {
0381     const int fixedMenuEntries = KrActions::actClosedTabsMenu->quantFixedMenuEntries;
0382     Q_ASSERT(KrActions::actClosedTabsMenu->menu()->actions().size() > fixedMenuEntries);
0383     // Performs the same action as when clicking on that menu item
0384     KrActions::actClosedTabsMenu->slotTriggered(KrActions::actClosedTabsMenu->menu()->actions().at(fixedMenuEntries));
0385 }
0386 
0387 void PanelManager::undoCloseTab(const QAction *action)
0388 {
0389     QDataStream tabStream(action->data().toByteArray());
0390     // Deserialize data
0391     bool closedInTheLeftPan;
0392     tabStream >> closedInTheLeftPan;
0393     int insertIndex;
0394     tabStream >> insertIndex;
0395     QUrl urlClosedTab;
0396     tabStream >> urlClosedTab;
0397     int tabProperties;
0398     tabStream >> tabProperties;
0399     QUrl pinnedUrl;
0400     tabStream >> pinnedUrl;
0401     QList<QUrl> selectedUrls;
0402     tabStream >> selectedUrls;
0403 
0404     // This variable points to the PanelManager where the closed tab is going to be restored
0405     PanelManager *whereToUndo = closedInTheLeftPan ? LEFT_MNG : RIGHT_MNG;
0406 
0407     MAIN_VIEW->slotSetActiveManager(whereToUndo);
0408     // Open a new tab where to apply the planned changes
0409     whereToUndo->slotNewTab(urlClosedTab, true, insertIndex);
0410 
0411     // Restore settings of the tab. Note: The code is
0412     // based on the one of slotDuplicateTab()
0413     QString grpName = QString("closedTab_%1").arg(reinterpret_cast<qulonglong>(action));
0414     KConfigGroup cfg(krConfig, grpName);
0415     ListPanel *panel = static_cast<ListPanel *>(whereToUndo->currentPanel());
0416     panel->restoreSettings(cfg);
0417     krConfig->deleteGroup(grpName);
0418     panel->setProperties(tabProperties);
0419     panel->setPinnedUrl(pinnedUrl);
0420     // Note: In `void PanelManager::layoutTabs()` there was a similar `QTimer::singleShot(`
0421     // and a comment about it: "delayed url refreshes may be pending - delay the layout too
0422     // so it happens after them"
0423     QTimer::singleShot(1, this, [=] {
0424         panel->view->setSelectionUrls(selectedUrls);
0425     });
0426 }
0427 
0428 void PanelManager::delAllClosedTabs()
0429 {
0430     const int quantFixedMenuEntries = KrActions::actClosedTabsMenu->quantFixedMenuEntries;
0431     RecentlyClosedTabsMenu *closedTabsMenu = KrActions::actClosedTabsMenu;
0432     if (closedTabsMenu) {
0433         const int quantActions = closedTabsMenu->menu()->actions().size();
0434         // Remove the actions (and related information) that follow the
0435         // fixed menu entries
0436         for (int x = quantActions - 1; x >= quantFixedMenuEntries; x--) {
0437             QAction *action = closedTabsMenu->menu()->actions().at(x);
0438             delClosedTab(action);
0439         }
0440     }
0441 }
0442 
0443 void PanelManager::delClosedTab(QAction *action)
0444 {
0445     // Delete the settings of the closed tab.
0446     // Note: The code is based on the one of slotCloseTab()
0447     QString grpName = QString("closedTab_%1").arg(reinterpret_cast<qulonglong>(action));
0448     krConfig->deleteGroup(grpName);
0449 
0450     // Remove the menu entry and the rest of its information
0451     KrActions::actClosedTabsMenu->removeAction(action);
0452 }
0453 
0454 void PanelManager::updateTabbarPos()
0455 {
0456     KConfigGroup group(krConfig, "Look&Feel");
0457     if (group.readEntry("Tab Bar Position", "bottom") == "top") {
0458         _layout->addWidget(_stack, 2, 0);
0459         _tabbar->setShape(QTabBar::RoundedNorth);
0460     } else {
0461         _layout->addWidget(_stack, 0, 0);
0462         _tabbar->setShape(QTabBar::RoundedSouth);
0463     }
0464 }
0465 
0466 int PanelManager::activeTab()
0467 {
0468     return _tabbar->currentIndex();
0469 }
0470 
0471 void PanelManager::setActiveTab(int index)
0472 {
0473     _tabbar->setCurrentIndex(index);
0474 }
0475 
0476 void PanelManager::slotRecreatePanels()
0477 {
0478     updateTabbarPos();
0479 
0480     for (int i = 0; i != _tabbar->count(); i++) {
0481         QString grpName = "PanelManager_" + QString::number(qApp->applicationPid());
0482         krConfig->deleteGroup(grpName); // make sure the group is empty
0483         KConfigGroup cfg(krConfig, grpName);
0484 
0485         ListPanel *oldPanel = _tabbar->getPanel(i);
0486         oldPanel->view->setFileIconSize(oldPanel->view->defaultFileIconSize());
0487         oldPanel->saveSettings(cfg, true);
0488         disconnect(oldPanel);
0489 
0490         ListPanel *newPanel = createPanel(cfg);
0491         _stack->insertWidget(i, newPanel);
0492         _tabbar->changePanel(i, newPanel);
0493 
0494         if (_currentPanel == oldPanel) {
0495             _currentPanel = newPanel;
0496             _stack->setCurrentWidget(_currentPanel);
0497         }
0498 
0499         _stack->removeWidget(oldPanel);
0500         deletePanel(oldPanel);
0501 
0502         newPanel->restoreSettings(cfg);
0503 
0504         _tabbar->updateTab(newPanel);
0505 
0506         krConfig->deleteGroup(grpName);
0507     }
0508     tabsCountChanged();
0509     _currentPanel->slotFocusOnMe(this == ACTIVE_MNG);
0510     emit pathChanged(_currentPanel);
0511 }
0512 
0513 void PanelManager::slotNextTab()
0514 {
0515     int currTab = _tabbar->currentIndex();
0516     int nextInd = (currTab == _tabbar->count() - 1 ? 0 : currTab + 1);
0517     _tabbar->setCurrentIndex(nextInd);
0518 }
0519 
0520 void PanelManager::slotPreviousTab()
0521 {
0522     int currTab = _tabbar->currentIndex();
0523     int nextInd = (currTab == 0 ? _tabbar->count() - 1 : currTab - 1);
0524     _tabbar->setCurrentIndex(nextInd);
0525 }
0526 
0527 void PanelManager::reloadConfig()
0528 {
0529     for (int i = 0; i < _tabbar->count(); i++) {
0530         ListPanel *panel = _tabbar->getPanel(i);
0531         if (panel) {
0532             panel->func->refresh();
0533         }
0534     }
0535 }
0536 
0537 void PanelManager::deletePanel(ListPanel *p)
0538 {
0539     disconnect(p);
0540     delete p;
0541 }
0542 
0543 void PanelManager::slotCloseInactiveTabs()
0544 {
0545     int i = 0;
0546     while (i < _tabbar->count()) {
0547         if (i == activeTab())
0548             i++;
0549         else
0550             slotCloseTab(i);
0551     }
0552 }
0553 
0554 void PanelManager::slotCloseDuplicatedTabs()
0555 {
0556     int i = 0;
0557     while (i < _tabbar->count() - 1) {
0558         ListPanel *panel1 = _tabbar->getPanel(i);
0559         if (panel1 != nullptr) {
0560             for (int j = i + 1; j < _tabbar->count(); j++) {
0561                 ListPanel *panel2 = _tabbar->getPanel(j);
0562                 if (panel2 != nullptr && panel1->virtualPath().matches(panel2->virtualPath(), QUrl::StripTrailingSlash)) {
0563                     if (j == activeTab()) {
0564                         slotCloseTab(i);
0565                         i--;
0566                         break;
0567                     } else {
0568                         slotCloseTab(j);
0569                         j--;
0570                     }
0571                 }
0572             }
0573         }
0574         i++;
0575     }
0576 }
0577 
0578 int PanelManager::findTab(QUrl url)
0579 {
0580     url.setPath(QDir::cleanPath(url.path()));
0581     for (int i = 0; i < _tabbar->count(); i++) {
0582         if (_tabbar->getPanel(i)) {
0583             QUrl panelUrl = _tabbar->getPanel(i)->virtualPath();
0584             panelUrl.setPath(QDir::cleanPath(panelUrl.path()));
0585             if (panelUrl.matches(url, QUrl::StripTrailingSlash))
0586                 return i;
0587         }
0588     }
0589     return -1;
0590 }
0591 
0592 void PanelManager::slotLockTab()
0593 {
0594     ListPanel *panel = _currentPanel;
0595     panel->gui->setTabState(panel->gui->isLocked() ? ListPanel::TabState::DEFAULT : ListPanel::TabState::LOCKED);
0596     _actions->refreshActions();
0597     _tabbar->updateTab(panel);
0598 }
0599 
0600 void PanelManager::slotPinTab()
0601 {
0602     ListPanel *panel = _currentPanel;
0603     panel->gui->setTabState(panel->gui->isPinned() ? ListPanel::TabState::DEFAULT : ListPanel::TabState::PINNED);
0604     if (panel->gui->isPinned()) {
0605         QUrl virtualPath = panel->virtualPath();
0606         panel->setPinnedUrl(virtualPath);
0607     }
0608     _actions->refreshActions();
0609     _tabbar->updateTab(panel);
0610 }
0611 
0612 void PanelManager::newTabs(const QStringList &urls)
0613 {
0614     for (int i = 0; i < urls.count(); i++)
0615         slotNewTab(QUrl::fromUserInput(urls[i], QString(), QUrl::AssumeLocalFile));
0616 }