1 //**************************************************************************
2 // Copyright 2006 - 2018 Martin Koller, kollix@aon.at
3 //
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, version 2 of the License
7 //
8 //**************************************************************************
9
10 #include <Selector.hxx>
11
12 #include <kio_version.h>
13 #include <kio/global.h>
14 #include <KIconLoader>
15 #include <KIconEffect>
16 #include <KIconUtils>
17 #include <KLocalizedString>
18 #include <KPropertiesDialog>
19 #include <KFileItem>
20 #include <KApplicationTrader>
21 #include <KActionCollection>
22 #include <KMessageBox>
23
24 #include <KIO/ApplicationLauncherJob>
25 #include <KIO/OpenUrlJob>
26 #include <KIO/JobUiDelegate>
27
28 #include <QDir>
29 #include <QPixmap>
30 #include <QDateTime>
31 #include <QCollator>
32 #include <QHeaderView>
33 #include <QMenu>
34 #include <QPointer>
35
36 #include <iostream>
37 using namespace std;
38
39 //--------------------------------------------------------------------------------
40 //--------------------------------------------------------------------------------
41
42 class Model : public QStandardItemModel
43 {
44 public:
Model(Selector * parent)45 explicit Model(Selector *parent) : QStandardItemModel(parent), tree(parent)
46 {
47 const char *lc_collate = ::getenv("LC_COLLATE");
48 if ( lc_collate )
49 collator.setLocale(QLocale(QLatin1String(lc_collate)));
50
51 collator.setNumericMode(true);
52 }
53
hasChildren(const QModelIndex & index=QModelIndex ()) const54 bool hasChildren(const QModelIndex &index = QModelIndex()) const override
55 {
56 QStandardItem *item = itemFromIndex(index);
57
58 if ( !item )
59 return true; // invisible root
60
61 return !(item->flags() & Qt::ItemNeverHasChildren);
62 }
63
64 Selector *tree;
65 QCollator collator;
66 };
67
68 //--------------------------------------------------------------------------------
69 //--------------------------------------------------------------------------------
70
71 class ListItem : public QStandardItem
72 {
73 public:
ListItem(QStandardItem * parent,const QString & text,bool dir)74 ListItem(QStandardItem *parent, const QString &text, bool dir)
75 : isDir_(dir), partly(false)
76 {
77 parent->appendRow(this);
78 parent->setChild(row(), 1, new QStandardItem);
79 parent->setChild(row(), 2, new QStandardItem);
80
81 setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable);
82
83 if ( !isDir_ )
84 setFlags(flags() | Qt::ItemNeverHasChildren);
85
86 setCheckState(Qt::Unchecked);
87 setText(0, text, key(text));
88 }
89
type() const90 int type() const override { return QStandardItem::UserType; }
91
isOn() const92 bool isOn() const { return checkState() == Qt::Checked; }
setOn(bool on)93 void setOn(bool on) { setCheckState(on ? Qt::Checked : Qt::Unchecked); }
94
setText(int column,const QString & txt,const QVariant & sortKey)95 void setText(int column, const QString &txt, const QVariant &sortKey)
96 {
97 QStandardItem *item;
98
99 if ( parent() )
100 item = parent()->child(row(), column);
101 else
102 item = model()->item(row(), column);
103
104 item->setText(txt);
105 item->setData(sortKey, Qt::UserRole);
106 }
107
setData(const QVariant & value,int role=Qt::UserRole+1)108 void setData(const QVariant &value, int role = Qt::UserRole + 1) override
109 {
110 if ( role == Qt::CheckStateRole )
111 {
112 if ( value.toInt() != checkState() )
113 {
114 QStandardItem::setData(value, role);
115 stateChanged();
116 return;
117 }
118 }
119
120 QStandardItem::setData(value, role);
121 }
122
123 // check if all siblings have the same state as the parent or are partly marked
124 // If not, then the parent must have the partly flag set, otherwise the parents
125 // partly flag can be cleared
recursSiblingsUp()126 void recursSiblingsUp()
127 {
128 if ( !parent() ) return;
129
130 bool allSame = true, state = static_cast<ListItem*>(parent())->isOn();
131
132 for (int i = 0; i < parent()->rowCount(); i++)
133 {
134 QStandardItem *item = parent()->child(i);
135
136 if ( (static_cast<ListItem*>(item)->isOn() != state) || static_cast<ListItem*>(item)->partly )
137 {
138 allSame = false;
139 break;
140 }
141 }
142
143 // only continue upwards if the parents partly status changes
144 if ( static_cast<ListItem*>(parent())->partly != !allSame )
145 {
146 static_cast<ListItem*>(parent())->partly = !allSame;
147
148 if ( !allSame )
149 static_cast<ListItem*>(parent())->setForeground(Qt::blue);
150 else
151 {
152 QWidget *w = static_cast<Model *>(model())->tree;
153 static_cast<ListItem*>(parent())->setForeground(w->palette().color(w->foregroundRole()));
154 }
155
156 static_cast<ListItem*>(parent())->recursSiblingsUp();
157 }
158 }
159
stateChanged()160 void stateChanged()
161 {
162 recursActivate(isOn());
163 recursSiblingsUp();
164 }
165
166 // set all children recursively below this to on
recursActivate(bool on)167 void recursActivate(bool on)
168 {
169 partly = false; // all children will get the same state
170
171 QWidget *w = static_cast<Model *>(model())->tree;
172 setForeground(w->palette().color(w->foregroundRole()));
173
174 setOn(on);
175
176 for (int i = 0; i < rowCount(); i++)
177 static_cast<ListItem*>(child(i))->recursActivate(on);
178 }
179
isDir() const180 bool isDir() const { return isDir_; }
181
key(const QString & text) const182 int key(const QString &text) const
183 {
184 bool hidden = text[0] == QLatin1Char('.');
185
186 // sort directories _always_ first, and hidden before shown
187 if ( isDir_ )
188 return hidden ? 0 : 1;
189 else // file
190 return hidden ? 2 : 3;
191 }
192
operator <(const QStandardItem & other_) const193 bool operator<(const QStandardItem &other_) const override
194 {
195 QTreeView *w = static_cast<Model *>(model())->tree;
196 Qt::SortOrder order = w->header()->sortIndicatorOrder();
197
198 const ListItem &other = static_cast<const ListItem &>(other_);
199
200 int myKey = data(Qt::UserRole).toInt();
201 int otherKey = other.data(Qt::UserRole).toInt();
202
203 if ( myKey != otherKey )
204 return (order == Qt::AscendingOrder) ? (myKey < otherKey) : (myKey > otherKey);
205 else
206 {
207 // don't use localeAwareCompare. QLocale does not use LC_COLLATE QTBUG-29397
208 return static_cast<Model *>(model())->collator.compare(text(), other.text()) < 0;
209 }
210 }
211
setSize(KIO::filesize_t size)212 void setSize(KIO::filesize_t size)
213 {
214 setText(1, KIO::convertSize(size), size);
215 }
216
setLastModified(const QDateTime & time)217 void setLastModified(const QDateTime &time)
218 {
219 setText(2, QLocale().toString(time, QLocale::ShortFormat), time);
220 }
221
setShowHiddenFiles(bool show)222 void setShowHiddenFiles(bool show)
223 {
224 QTreeView *w = static_cast<Model *>(model())->tree;
225
226 QStandardItem *parentItem = parent() ? parent() : model()->invisibleRootItem();
227
228 w->setRowHidden(row(), parentItem->index(), show ? false : text()[0] == QLatin1Char('.'));
229
230 for (int i = 0; i < rowCount(); i++)
231 static_cast<ListItem*>(child(i))->setShowHiddenFiles(show);
232 }
233
234 private:
235 bool isDir_;
236 bool partly; // is this an item which is not fully (but partly - some of the children) selected
237
238 };
239
240 //--------------------------------------------------------------------------------
241 //--------------------------------------------------------------------------------
242 //--------------------------------------------------------------------------------
243 //--------------------------------------------------------------------------------
244
Selector(QWidget * parent,KActionCollection * actionCollection)245 Selector::Selector(QWidget *parent, KActionCollection *actionCollection)
246 : QTreeView(parent)
247 {
248 itemModel = new Model(this);
249
250 setModel(itemModel);
251
252 itemModel->setSortRole(Qt::UserRole);
253 itemModel->setHorizontalHeaderLabels(QStringList() << i18n("Name") << i18n("Size") << i18n("Last Modified"));
254
255 setRootIsDecorated(true);
256
257 // start with / as root node
258 ListItem *item = new ListItem(itemModel->invisibleRootItem(), QStringLiteral("/"), true);
259 QFileInfo info(QStringLiteral("/"));
260 item->setSize(info.size());
261 item->setLastModified(info.lastModified());
262 item->setIcon(QIcon::fromTheme(QStringLiteral("folder")));
263 setExpanded(item->index(), true);
264
265 fillTree(item, QStringLiteral("/"), false);
266
267 connect(this, &Selector::expanded, this, &Selector::expandedSlot);
268
269 minSize = QSize(columnWidth(0) + columnWidth(1), -1);
270 resizeColumnToContents(0);
271 resizeColumnToContents(1);
272 resizeColumnToContents(2);
273
274 sortByColumn(0, Qt::AscendingOrder);
275
276 // context menu
277 menu = new QMenu(this);
278 QAction *action;
279
280 action = KStandardAction::open(this, SLOT(open()), actionCollection);
281 menu->addAction(action);
282
283 connect(this, &Selector::doubleClicked, this, &Selector::doubleClickedSlot);
284
285 openWithSubMenu = new QMenu(i18n("Open With"), this);
286 menu->addMenu(openWithSubMenu);
287 connect(openWithSubMenu, &QMenu::aboutToShow, this, &Selector::populateOpenMenu);
288 connect(openWithSubMenu, &QMenu::triggered, this, &Selector::openWith);
289
290 // just since KF 5.25
291 //deleteFileAction = KStandardAction::deleteFile(this, SLOT(deleteFile()), actionCollection);
292 deleteFileAction = actionCollection->addAction(QStringLiteral("deleteFile"), this, SLOT(deleteFile()));
293 deleteFileAction->setText(i18n("Delete File"));
294 deleteFileAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
295 deleteFileAction->setShortcut(QKeySequence(Qt::SHIFT | Qt::Key_Delete));
296 menu->addAction(deleteFileAction);
297
298 action = actionCollection->addAction(QStringLiteral("properties"), this, SLOT(properties()));
299 action->setText(i18n("Properties..."));
300 menu->addAction(action);
301 }
302
303 //--------------------------------------------------------------------------------
304
openHomeDir()305 void Selector::openHomeDir()
306 {
307 const char *home = ::getenv("HOME");
308 if ( home )
309 {
310 QStandardItem *homeItem = findItemByPath(QFile::decodeName(home));
311 if ( homeItem )
312 {
313 setExpanded(homeItem->index(), true);
314 scrollTo(homeItem->index());
315 }
316 }
317 }
318
319 //--------------------------------------------------------------------------------
320
minimumSizeHint() const321 QSize Selector::minimumSizeHint() const
322 {
323 return minSize;
324 }
325
326 //--------------------------------------------------------------------------------
327
fillTree(ListItem * parent,const QString & path,bool on)328 void Selector::fillTree(ListItem *parent, const QString &path, bool on)
329 {
330 setSortingEnabled(false);
331
332 const QDir::Filters filter = QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot;
333
334 QDir dir(path, QString(), QDir::NoSort, filter);
335 const QFileInfoList list = dir.entryInfoList();
336
337 ListItem *item;
338
339 for (int i = 0; i < list.count(); i++)
340 {
341 if ( parent )
342 item = new ListItem(parent, list[i].fileName(), list[i].isDir());
343 else
344 item = new ListItem(itemModel->invisibleRootItem(), list[i].fileName(), list[i].isDir());
345
346 item->setOn(on);
347 item->setSize(list[i].size());
348 item->setLastModified(list[i].lastModified());
349 item->setShowHiddenFiles(showHiddenFiles);
350
351 if ( item->isDir() )
352 {
353 QDir dir(list[i].absoluteFilePath(), QString(), QDir::NoSort, filter);
354
355 // symlinked dirs can not be expanded as they are stored as single files in the archive
356 if ( (dir.count() > 0) && !list[i].isSymLink() )
357 ; // can have children
358 else
359 item->setFlags(item->flags() | Qt::ItemNeverHasChildren);
360
361 static QPixmap folderIcon;
362 static QPixmap folderLinkIcon;
363 static QPixmap folderIconHidden;
364 static QPixmap folderLinkIconHidden;
365
366 if ( folderIcon.isNull() ) // only get the icons once
367 {
368 KIconEffect effect;
369
370 folderIcon = QIcon::fromTheme(QStringLiteral("folder")).pixmap(KIconLoader::SizeSmall);
371 folderIconHidden = effect.apply(folderIcon, KIconEffect::DeSaturate, 0, QColor(), true);
372
373 folderLinkIcon = KIconUtils::addOverlay(folderIcon,
374 QIcon::fromTheme(QStringLiteral("emblem-symbolic-link")),
375 Qt::BottomRightCorner).pixmap(KIconLoader::SizeSmall);
376
377 folderLinkIconHidden = effect.apply(folderLinkIcon, KIconEffect::DeSaturate, 0, QColor(), true);
378 }
379
380 item->setIcon(list[i].isSymLink() ?
381 (list[i].isHidden() ? folderLinkIconHidden : folderLinkIcon)
382 : (list[i].isHidden() ? folderIconHidden : folderIcon));
383 }
384 else
385 {
386 static QPixmap documentIcon;
387 static QPixmap documentLinkIcon;
388 static QPixmap documentIconHidden;
389 static QPixmap documentLinkIconHidden;
390
391 if ( documentIcon.isNull() ) // only get the icons once
392 {
393 KIconEffect effect;
394
395 documentIcon = QIcon::fromTheme(QStringLiteral("text-x-generic")).pixmap(KIconLoader::SizeSmall);
396 documentIconHidden = effect.apply(documentIcon, KIconEffect::DeSaturate, 0, QColor(), true);
397
398 documentLinkIcon = KIconUtils::addOverlay(documentIcon,
399 QIcon::fromTheme(QStringLiteral("emblem-symbolic-link")),
400 Qt::BottomRightCorner).pixmap(KIconLoader::SizeSmall);
401
402 documentLinkIconHidden = effect.apply(documentLinkIcon, KIconEffect::DeSaturate, 0, QColor(), true);
403 }
404
405 item->setIcon(list[i].isSymLink() ?
406 (list[i].isHidden() ? documentLinkIconHidden : documentLinkIcon)
407 : (list[i].isHidden() ? documentIconHidden : documentIcon));
408 }
409 }
410 setSortingEnabled(true);
411 }
412
413 //--------------------------------------------------------------------------------
414
getPath(QStandardItem * item) const415 QString Selector::getPath(QStandardItem *item) const
416 {
417 if ( !item )
418 return QString();
419 else if ( !item->parent() )
420 return item->text(); // root
421 else if ( item->parent() == itemModel->item(0) )
422 return QStringLiteral("/") + item->text();
423 else
424 return getPath(item->parent()) + QStringLiteral("/") + item->text();
425 }
426
427 //--------------------------------------------------------------------------------
428
expandedSlot(const QModelIndex & index)429 void Selector::expandedSlot(const QModelIndex &index)
430 {
431 QStandardItem *item = itemModel->itemFromIndex(index);
432
433 if ( item->rowCount() ) return; // already done
434
435 fillTree(static_cast<ListItem *>(item), getPath(item), static_cast<ListItem *>(item)->isOn());
436 }
437
438 //--------------------------------------------------------------------------------
439
getBackupList(QStringList & includes,QStringList & excludes) const440 void Selector::getBackupList(QStringList &includes, QStringList &excludes) const
441 {
442 for (int i = 0; i < itemModel->rowCount(); i++)
443 getBackupLists(itemModel->item(i, 0), includes, excludes);
444
445 /*
446 cerr << "includes:" << includes.count() << endl;
447 for (QStringList::const_iterator it = includes.begin(); (it != includes.end()); ++it)
448 cerr << *it << endl;
449
450 cerr << "excludes:" << excludes.count() << endl;
451 for (QStringList::const_iterator it = excludes.begin(); (it != excludes.end()); ++it)
452 cerr << *it << endl;
453
454 cerr << endl;
455 */
456 }
457
458 //--------------------------------------------------------------------------------
459
getBackupLists(QStandardItem * start,QStringList & includes,QStringList & excludes,bool add) const460 void Selector::getBackupLists(QStandardItem *start, QStringList &includes, QStringList &excludes, bool add) const
461 {
462 if ( static_cast<ListItem*>(start)->isOn() )
463 {
464 if ( add )
465 includes.append(getPath(start)); // include it
466
467 if ( static_cast<ListItem*>(start)->isDir() )
468 {
469 // get excludes from this dir
470 for (int i = 0; i < start->rowCount(); i++)
471 {
472 QStandardItem *item = start->child(i);
473
474 if ( !static_cast<ListItem*>(item)->isOn() )
475 excludes.append(getPath(item));
476
477 if ( static_cast<ListItem*>(item)->isDir() )
478 getBackupLists(item, includes, excludes, false);
479 }
480 }
481 }
482 else
483 if ( static_cast<ListItem*>(start)->isDir() )
484 {
485 for (int i = 0; i < start->rowCount(); i++)
486 getBackupLists(start->child(i), includes, excludes);
487 }
488 }
489
490 //--------------------------------------------------------------------------------
491
setBackupList(const QStringList & includes,const QStringList & excludes)492 void Selector::setBackupList(const QStringList &includes, const QStringList &excludes)
493 {
494 // clear all current settings
495 for (int i = 0; i < itemModel->rowCount(); i++)
496 static_cast<ListItem*>(itemModel->item(i, 0))->recursActivate(false);
497
498 for (QStringList::const_iterator it = includes.begin(); (it != includes.end()); ++it)
499 {
500 QStandardItem *item = findItemByPath(*it);
501 if ( item )
502 static_cast<ListItem*>(item)->recursActivate(true);
503 }
504
505 for (QStringList::const_iterator it = excludes.begin(); (it != excludes.end()); ++it)
506 {
507 QStandardItem *item = findItemByPath(*it);
508 if ( item )
509 static_cast<ListItem*>(item)->setOn(false);
510 }
511 }
512
513 //--------------------------------------------------------------------------------
514
findItemByPath(const QString & path)515 QStandardItem *Selector::findItemByPath(const QString &path)
516 {
517 QStringList items = path.split(QLatin1Char('/'), Qt::SkipEmptyParts);
518 QStandardItem *item = itemModel->invisibleRootItem()->child(0);
519
520 for (int i = 0; i < items.count(); i++)
521 {
522 item = findItem(item, items[i]);
523
524 if ( !item )
525 return nullptr;
526 else
527 {
528 if ( (i != (items.count() - 1)) &&
529 static_cast<ListItem*>(item)->isDir() && (item->rowCount() == 0) )
530 expandedSlot(item->index());
531 }
532 }
533
534 return item;
535 }
536
537 //--------------------------------------------------------------------------------
538
findItem(QStandardItem * start,const QString & toFind) const539 QStandardItem *Selector::findItem(QStandardItem *start, const QString &toFind) const
540 {
541 for (int i = 0; i < (start ? start->rowCount() : itemModel->rowCount()); i++)
542 {
543 QStandardItem *item = start ? start->child(i) : itemModel->item(i, 0);
544
545 if ( item->text() == toFind )
546 return item;
547 }
548
549 return nullptr;
550 }
551
552 //--------------------------------------------------------------------------------
553
getSelectedItem() const554 ListItem *Selector::getSelectedItem() const
555 {
556 QModelIndex index = selectionModel()->currentIndex();
557 if ( !index.isValid() )
558 return nullptr;
559
560 QStandardItem *item = itemModel->itemFromIndex(itemModel->index(index.row(), 0, index.parent()));
561
562 if ( !item || (item->type() != QStandardItem::UserType) ) // just be safe
563 return nullptr;
564
565 return static_cast<ListItem *>(item);
566 }
567
568 //--------------------------------------------------------------------------------
569
contextMenuEvent(QContextMenuEvent *)570 void Selector::contextMenuEvent(QContextMenuEvent *)
571 {
572 ListItem *item = getSelectedItem();
573
574 if ( !item )
575 return;
576
577 bool canDelete = true;
578
579 if ( item->isDir() )
580 {
581 // only if it's empty
582 canDelete = QDir(getPath(item), QString(), QDir::NoSort,
583 QDir::AllEntries | QDir::System | QDir::NoDotAndDotDot).count() == 0;
584 }
585
586 deleteFileAction->setEnabled(canDelete);
587
588 menu->exec(QCursor::pos());
589 }
590
591 //--------------------------------------------------------------------------------
592
deleteFile()593 void Selector::deleteFile()
594 {
595 ListItem *item = getSelectedItem();
596
597 if ( !item )
598 return;
599
600 QUrl sourceUrl = QUrl::fromLocalFile(getPath(item));
601
602 if ( KMessageBox::questionYesNo(this,
603 i18n("Do you really want to delete '%1'?", sourceUrl.path()),
604 i18n("Delete"),
605 KStandardGuiItem::yes(), KStandardGuiItem::no(),
606 QStringLiteral("dontAskAgainDelete")) == KMessageBox::Yes )
607 {
608 QStandardItem *parent = nullptr;
609
610 if ( item->isDir() )
611 {
612 QDir dir(sourceUrl.path());
613
614 if ( !dir.removeRecursively() )
615 KMessageBox::error(this, i18n("Could not delete directory '%1'.", sourceUrl.path()));
616 else
617 parent = item->parent();
618 }
619 else
620 {
621 QFile theFile(sourceUrl.path());
622
623 if ( !theFile.remove(sourceUrl.path()) )
624 KMessageBox::error(this, i18n("Could not delete file '%1'.\nReason: %2", sourceUrl.path(), theFile.errorString()));
625 else
626 parent = item->parent();
627 }
628
629 if ( parent )
630 {
631 parent->removeRow(item->row());
632
633 if ( parent->type() == QStandardItem::UserType )
634 static_cast<ListItem *>(parent)->stateChanged(); // make sure removed item is taken into account
635 }
636 }
637 }
638
639 //--------------------------------------------------------------------------------
640
properties()641 void Selector::properties()
642 {
643 ListItem *item = getSelectedItem();
644
645 if ( !item )
646 return;
647
648 QUrl sourceUrl = QUrl::fromLocalFile(getPath(item));
649
650 QPointer<KPropertiesDialog> dialog = new KPropertiesDialog(sourceUrl, this);
651 connect(dialog.data(), &KPropertiesDialog::applied, this,
652 [item, dialog]()
653 {
654 // make sure a renamed file is shown with the new name in the tree
655 item->setText(0, dialog->item().name(), item->key(dialog->item().name()));
656 });
657
658 dialog->exec();
659 delete dialog;
660 }
661
662 //--------------------------------------------------------------------------------
663
populateOpenMenu()664 void Selector::populateOpenMenu()
665 {
666 ListItem *item = getSelectedItem();
667
668 if ( !item )
669 return;
670
671 QUrl sourceUrl = QUrl::fromLocalFile(getPath(item));
672
673 qDeleteAll(openWithSubMenu->actions());
674 serviceForName.clear();
675
676 KFileItem fileItem(sourceUrl);
677 QString mimeType(fileItem.determineMimeType().name());
678
679 const KService::List services = KApplicationTrader::queryByMimeType(mimeType);
680
681 for (const KService::Ptr &service : services)
682 {
683 QString text = service->name().replace(QLatin1Char('&'), QStringLiteral("&&"));
684 QAction* action = openWithSubMenu->addAction(text);
685 action->setIcon(QIcon::fromTheme(service->icon()));
686 action->setData(service->name());
687
688 serviceForName[service->name()] = service;
689 }
690
691 openWithSubMenu->addSeparator();
692 openWithSubMenu->addAction(i18n("Other Application..."));
693
694 QAction* action = openWithSubMenu->addAction(i18n("File Manager"));
695 action->setIcon(QIcon::fromTheme(QStringLiteral("folder")));
696 action->setData(QStringLiteral("-"));
697 }
698
699 //--------------------------------------------------------------------------------
700
doubleClickedSlot()701 void Selector::doubleClickedSlot()
702 {
703 ListItem *item = getSelectedItem();
704
705 if ( !item || item->isDir() )
706 return;
707
708 open();
709 }
710
711 //--------------------------------------------------------------------------------
712
open()713 void Selector::open()
714 {
715 ListItem *item = getSelectedItem();
716
717 if ( !item )
718 return;
719
720 QUrl sourceUrl = QUrl::fromLocalFile(getPath(item));
721
722 auto *job = new KIO::OpenUrlJob(sourceUrl, window());
723 job->setRunExecutables(false);
724 job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
725 job->start();
726 }
727
728 //--------------------------------------------------------------------------------
729
openWith(QAction * action)730 void Selector::openWith(QAction *action)
731 {
732 ListItem *item = getSelectedItem();
733
734 if ( !item )
735 return;
736
737 QUrl sourceUrl = QUrl::fromLocalFile(getPath(item));
738
739 QString name = action->data().toString();
740
741 if ( name.isEmpty() ) // Other Application...
742 {
743 KIO::ApplicationLauncherJob *job = new KIO::ApplicationLauncherJob();
744 job->setUrls(QList<QUrl>() << sourceUrl);
745 job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
746 job->start();
747 return;
748 }
749
750 if ( name == QLatin1String("-") ) // File Manager
751 {
752 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(sourceUrl.adjusted(QUrl::RemoveFilename), QStringLiteral("inode/directory"));
753 job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
754 job->start();
755
756 return;
757 }
758
759 KService::Ptr service = serviceForName[name];
760 KIO::ApplicationLauncherJob *job = new KIO::ApplicationLauncherJob(service);
761 job->setUrls(QList<QUrl>() << sourceUrl);
762 job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
763 job->start();
764 }
765
766 //--------------------------------------------------------------------------------
767
setShowHiddenFiles(bool show)768 void Selector::setShowHiddenFiles(bool show)
769 {
770 showHiddenFiles = show;
771
772 for (int i = 0; i < itemModel->invisibleRootItem()->rowCount(); i++)
773 static_cast<ListItem *>(itemModel->item(i, 0))->setShowHiddenFiles(show);
774 }
775
776 //--------------------------------------------------------------------------------
777