Changeset View
Standalone View
src/widgets/kopenwithdialog.cpp
Show All 24 Lines | |||||
25 | #include "kopenwithdialog_p.h" | 25 | #include "kopenwithdialog_p.h" | ||
26 | #include "kio_widgets_debug.h" | 26 | #include "kio_widgets_debug.h" | ||
27 | 27 | | |||
28 | #include <QApplication> | 28 | #include <QApplication> | ||
29 | #include <QDesktopWidget> | 29 | #include <QDesktopWidget> | ||
30 | #include <QDialogButtonBox> | 30 | #include <QDialogButtonBox> | ||
31 | #include <QtCore/QtAlgorithms> | 31 | #include <QtCore/QtAlgorithms> | ||
32 | #include <QtCore/QList> | 32 | #include <QtCore/QList> | ||
33 | #include <QKeyEvent> | ||||
33 | #include <QLabel> | 34 | #include <QLabel> | ||
34 | #include <QLayout> | 35 | #include <QLayout> | ||
35 | #include <QCheckBox> | 36 | #include <QCheckBox> | ||
36 | #include <QStyle> | 37 | #include <QStyle> | ||
37 | #include <QStyleOptionButton> | 38 | #include <QStyleOptionButton> | ||
38 | #include <qstandardpaths.h> | 39 | #include <qstandardpaths.h> | ||
39 | #include <qmimedatabase.h> | 40 | #include <qmimedatabase.h> | ||
40 | 41 | | |||
▲ Show 20 Lines • Show All 145 Lines • ▼ Show 20 Line(s) | 136 | { | |||
186 | } | 187 | } | ||
187 | qStableSort(node->children.begin(), node->children.end(), KDEPrivate::AppNodeLessThan); | 188 | qStableSort(node->children.begin(), node->children.end(), KDEPrivate::AppNodeLessThan); | ||
188 | } | 189 | } | ||
189 | 190 | | |||
190 | KApplicationModel::KApplicationModel(QObject *parent) | 191 | KApplicationModel::KApplicationModel(QObject *parent) | ||
191 | : QAbstractItemModel(parent), d(new KApplicationModelPrivate(this)) | 192 | : QAbstractItemModel(parent), d(new KApplicationModelPrivate(this)) | ||
192 | { | 193 | { | ||
193 | d->fillNode(QString(), d->root); | 194 | d->fillNode(QString(), d->root); | ||
195 | const int nRows = rowCount(); | ||||
dfaure: spaces around '=' and '<'
I would put rowCount() into a local var, the compiler can't optimize… | |||||
196 | for (int i = 0; i < nRows; i++) { | ||||
dfaure: space after comma | |||||
197 | fetchAll(index(i, 0)); | ||||
198 | } | ||||
194 | } | 199 | } | ||
195 | 200 | | |||
196 | KApplicationModel::~KApplicationModel() | 201 | KApplicationModel::~KApplicationModel() | ||
197 | { | 202 | { | ||
198 | delete d; | 203 | delete d; | ||
199 | } | 204 | } | ||
200 | 205 | | |||
201 | bool KApplicationModel::canFetchMore(const QModelIndex &parent) const | 206 | bool KApplicationModel::canFetchMore(const QModelIndex &parent) const | ||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Line(s) | 245 | { | |||
248 | } | 253 | } | ||
249 | 254 | | |||
250 | emit layoutAboutToBeChanged(); | 255 | emit layoutAboutToBeChanged(); | ||
251 | d->fillNode(node->entryPath, node); | 256 | d->fillNode(node->entryPath, node); | ||
252 | node->fetched = true; | 257 | node->fetched = true; | ||
253 | emit layoutChanged(); | 258 | emit layoutChanged(); | ||
254 | } | 259 | } | ||
255 | 260 | | |||
261 | void KApplicationModel::fetchAll(const QModelIndex &parent) | ||||
262 | { | ||||
263 | if (!parent.isValid() || !canFetchMore(parent)) { | ||||
264 | return; | ||||
265 | } | ||||
266 | | ||||
267 | fetchMore(parent); | ||||
268 | | ||||
269 | int childCount = rowCount(parent); | ||||
270 | for (int i = 0; i < childCount; i++) { | ||||
271 | const QModelIndex &child = parent.child(i, 0); | ||||
272 | // Recursively call the function for each child node. | ||||
273 | fetchAll(child); | ||||
274 | } | ||||
275 | } | ||||
dfaure: remove useless statement | |||||
276 | | ||||
256 | bool KApplicationModel::hasChildren(const QModelIndex &parent) const | 277 | bool KApplicationModel::hasChildren(const QModelIndex &parent) const | ||
257 | { | 278 | { | ||
258 | if (!parent.isValid()) { | 279 | if (!parent.isValid()) { | ||
259 | return true; | 280 | return true; | ||
260 | } | 281 | } | ||
261 | 282 | | |||
262 | KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode *>(parent.internalPointer()); | 283 | KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode *>(parent.internalPointer()); | ||
263 | return node->isDir; | 284 | return node->isDir; | ||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Line(s) | 370 | { | |||
350 | if (!index.isValid()) { | 371 | if (!index.isValid()) { | ||
351 | return false; | 372 | return false; | ||
352 | } | 373 | } | ||
353 | 374 | | |||
354 | KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode *>(index.internalPointer()); | 375 | KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode *>(index.internalPointer()); | ||
355 | return node->isDir; | 376 | return node->isDir; | ||
356 | } | 377 | } | ||
357 | 378 | | |||
379 | | ||||
380 | QTreeViewProxyFilter::QTreeViewProxyFilter(QObject *parent) | ||||
381 | : QSortFilterProxyModel(parent) | ||||
382 | { | ||||
dfaure: weird indentation, please indent these to column 0 | |||||
383 | } | ||||
384 | | ||||
385 | bool QTreeViewProxyFilter::filterAcceptsRow(int sourceRow, const QModelIndex &parent) const | ||||
386 | { | ||||
387 | QModelIndex index = sourceModel()->index(sourceRow, 0, parent); | ||||
388 | | ||||
389 | if (!index.isValid()) { | ||||
390 | return false; | ||||
391 | } | ||||
392 | | ||||
393 | // Match the regexp only on leaf nodes | ||||
394 | if (!sourceModel()->hasChildren(index) && index.data().toString().contains(filterRegExp())) { | ||||
395 | return true; | ||||
396 | } | ||||
397 | | ||||
398 | //Show the non-leaf node also if the regexp matches one one of its children | ||||
Ah. Filipe and I implemented recursive filtering in QSortFilterProxyModel but that's only in Qt 5.10. Too bad ;) We'll have to keep this for now then (easier here since the data doesn't change, anyway) dfaure: Ah. Filipe and I implemented recursive filtering in QSortFilterProxyModel but that's only in Qt… | |||||
simgunz: I saw the new feature in Qt 5.10 indeed. | |||||
399 | int rows = sourceModel()->rowCount(index); | ||||
400 | for (int crow = 0; crow < rows; crow++) { | ||||
401 | if (filterAcceptsRow(crow, index)) { | ||||
402 | return true; | ||||
403 | } | ||||
404 | } | ||||
405 | | ||||
406 | return false; | ||||
407 | } | ||||
408 | | ||||
358 | class KApplicationViewPrivate | 409 | class KApplicationViewPrivate | ||
359 | { | 410 | { | ||
360 | public: | 411 | public: | ||
361 | KApplicationViewPrivate() | 412 | KApplicationViewPrivate() | ||
362 | : appModel(nullptr) | 413 | : appModel(nullptr), | ||
414 | m_proxyModel(nullptr) | ||||
363 | { | 415 | { | ||
364 | } | 416 | } | ||
365 | 417 | | |||
366 | KApplicationModel *appModel; | 418 | KApplicationModel *appModel; | ||
419 | QSortFilterProxyModel *m_proxyModel; | ||||
367 | }; | 420 | }; | ||
368 | 421 | | |||
369 | KApplicationView::KApplicationView(QWidget *parent) | 422 | KApplicationView::KApplicationView(QWidget *parent) | ||
370 | : QTreeView(parent), d(new KApplicationViewPrivate) | 423 | : QTreeView(parent), d(new KApplicationViewPrivate) | ||
371 | { | 424 | { | ||
372 | setHeaderHidden(true); | 425 | setHeaderHidden(true); | ||
373 | } | 426 | } | ||
374 | 427 | | |||
375 | KApplicationView::~KApplicationView() | 428 | KApplicationView::~KApplicationView() | ||
376 | { | 429 | { | ||
377 | delete d; | 430 | delete d; | ||
378 | } | 431 | } | ||
379 | 432 | | |||
380 | void KApplicationView::setModel(QAbstractItemModel *model) | 433 | void KApplicationView::setModels(KApplicationModel *model, QSortFilterProxyModel *proxyModel) | ||
381 | { | 434 | { | ||
382 | if (d->appModel) { | 435 | if (d->appModel) { | ||
383 | disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), | 436 | disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), | ||
384 | this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); | 437 | this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); | ||
385 | } | 438 | } | ||
386 | 439 | | |||
387 | QTreeView::setModel(model); | 440 | QTreeView::setModel(proxyModel); // Here we set the proxy model | ||
441 | d->m_proxyModel = proxyModel; // Also store it in a member property to avoid many casts later | ||||
388 | 442 | | |||
389 | d->appModel = qobject_cast<KApplicationModel *>(model); | 443 | d->appModel = model; | ||
Urgh. Why don't we change this method to be setModels(QSortFilterProxyModel *, KApplicationModel *) to avoid all these casts? dfaure: Urgh. Why don't we change this method to be setModels(QSortFilterProxyModel *… | |||||
390 | if (d->appModel) { | 444 | if (d->appModel) { | ||
391 | connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), | 445 | connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), | ||
392 | this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); | 446 | this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); | ||
393 | } | 447 | } | ||
394 | } | 448 | } | ||
395 | 449 | | |||
450 | QSortFilterProxyModel* KApplicationView::proxyModel() | ||||
451 | { | ||||
452 | return d->m_proxyModel; | ||||
453 | } | ||||
454 | | ||||
396 | bool KApplicationView::isDirSel() const | 455 | bool KApplicationView::isDirSel() const | ||
397 | { | 456 | { | ||
398 | if (d->appModel) { | 457 | if (d->appModel) { | ||
399 | QModelIndex index = selectionModel()->currentIndex(); | 458 | QModelIndex index = selectionModel()->currentIndex(); | ||
459 | index = d->m_proxyModel->mapToSource(index); | ||||
dfaure: ... and keep a QSFPM * member variable to avoid these casts here. | |||||
400 | return d->appModel->isDirectory(index); | 460 | return d->appModel->isDirectory(index); | ||
401 | } | 461 | } | ||
402 | return false; | 462 | return false; | ||
403 | } | 463 | } | ||
404 | 464 | | |||
405 | void KApplicationView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) | 465 | void KApplicationView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) | ||
406 | { | 466 | { | ||
407 | QTreeView::currentChanged(current, previous); | 467 | QTreeView::currentChanged(current, previous); | ||
408 | 468 | | |||
409 | if (d->appModel && !d->appModel->isDirectory(current)) { | 469 | if (d->appModel) { | ||
dfaure: Use the member var instead of casting. | |||||
Segmentation fault happens if I use the member var. Accessing the member var is the cause of the fault, because even qDebug() << d->m_proxyModel generates the same error. It is not clear to me why. simgunz: Segmentation fault happens if I use the member var. Accessing the member var is the cause of… | |||||
dfaure: Please try moving that code inside `if (d->appModel) { ... }`.
| |||||
410 | QString exec = d->appModel->execFor(current); | 470 | QModelIndex sourceCurrent = d->m_proxyModel->mapToSource(current); | ||
471 | if(!d->appModel->isDirectory(sourceCurrent)) { | ||||
472 | QString exec = d->appModel->execFor(sourceCurrent); | ||||
411 | if (!exec.isEmpty()) { | 473 | if (!exec.isEmpty()) { | ||
412 | emit highlighted(d->appModel->entryPathFor(current), exec); | 474 | emit highlighted(d->appModel->entryPathFor(sourceCurrent), exec); | ||
475 | } | ||||
413 | } | 476 | } | ||
414 | } | 477 | } | ||
415 | } | 478 | } | ||
416 | 479 | | |||
417 | void KApplicationView::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) | 480 | void KApplicationView::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) | ||
418 | { | 481 | { | ||
419 | Q_UNUSED(deselected) | 482 | Q_UNUSED(deselected) | ||
420 | 483 | | |||
421 | const QModelIndexList indexes = selected.indexes(); | 484 | QItemSelection sourceSelected = d->m_proxyModel->mapSelectionToSource(selected); | ||
422 | if (indexes.count() == 1 && !d->appModel->isDirectory(indexes.at(0))) { | 485 | | ||
486 | const QModelIndexList indexes = sourceSelected.indexes(); | ||||
487 | if (indexes.count() == 1) { | ||||
423 | QString exec = d->appModel->execFor(indexes.at(0)); | 488 | QString exec = d->appModel->execFor(indexes.at(0)); | ||
424 | if (!exec.isEmpty()) { | | |||
425 | emit this->selected(d->appModel->entryPathFor(indexes.at(0)), exec); | 489 | emit this->selected(d->appModel->entryPathFor(indexes.at(0)), exec); | ||
426 | } | 490 | } | ||
427 | } | 491 | } | ||
428 | } | | |||
429 | 492 | | |||
dfaure: space after if | |||||
430 | /*************************************************************** | 493 | /*************************************************************** | ||
431 | * | 494 | * | ||
432 | * KOpenWithDialog | 495 | * KOpenWithDialog | ||
433 | * | 496 | * | ||
434 | ***************************************************************/ | 497 | ***************************************************************/ | ||
435 | class KOpenWithDialogPrivate | 498 | class KOpenWithDialogPrivate | ||
436 | { | 499 | { | ||
437 | public: | 500 | public: | ||
▲ Show 20 Lines • Show All 153 Lines • ▼ Show 20 Line(s) | 646 | { | |||
591 | q->setLayout(topLayout); | 654 | q->setLayout(topLayout); | ||
592 | label = new QLabel(_text, q); | 655 | label = new QLabel(_text, q); | ||
593 | label->setWordWrap(true); | 656 | label->setWordWrap(true); | ||
594 | topLayout->addWidget(label); | 657 | topLayout->addWidget(label); | ||
595 | 658 | | |||
596 | if (!bReadOnly) { | 659 | if (!bReadOnly) { | ||
597 | // init the history combo and insert it into the URL-Requester | 660 | // init the history combo and insert it into the URL-Requester | ||
598 | KHistoryComboBox *combo = new KHistoryComboBox(); | 661 | KHistoryComboBox *combo = new KHistoryComboBox(); | ||
662 | combo->setToolTip(i18n("Type to filter the applications below, or specify the name of a command.\nPress down arrow to navigate the results.")); | ||||
663 | KLineEdit *lineEdit = new KLineEdit(q); | ||||
664 | lineEdit->setClearButtonShown(true); | ||||
665 | combo->setLineEdit(lineEdit); | ||||
599 | combo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); | 666 | combo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); | ||
600 | combo->setDuplicatesEnabled(false); | 667 | combo->setDuplicatesEnabled(false); | ||
601 | KConfigGroup cg(KSharedConfig::openConfig(), QStringLiteral("Open-with settings")); | 668 | KConfigGroup cg(KSharedConfig::openConfig(), QStringLiteral("Open-with settings")); | ||
602 | int max = cg.readEntry("Maximum history", 15); | 669 | int max = cg.readEntry("Maximum history", 15); | ||
603 | combo->setMaxCount(max); | 670 | combo->setMaxCount(max); | ||
604 | int mode = cg.readEntry("CompletionMode", int(KCompletion::CompletionPopup)); | 671 | int mode = cg.readEntry("CompletionMode", int(KCompletion::CompletionNone)); | ||
605 | combo->setCompletionMode(static_cast<KCompletion::CompletionMode>(mode)); | 672 | combo->setCompletionMode(static_cast<KCompletion::CompletionMode>(mode)); | ||
606 | const QStringList list = cg.readEntry("History", QStringList()); | 673 | const QStringList list = cg.readEntry("History", QStringList()); | ||
607 | combo->setHistoryItems(list, true); | 674 | combo->setHistoryItems(list, true); | ||
608 | edit = new KUrlRequester(combo, q); | 675 | edit = new KUrlRequester(combo, q); | ||
676 | edit->installEventFilter(q); | ||||
609 | } else { | 677 | } else { | ||
610 | edit = new KUrlRequester(q); | 678 | edit = new KUrlRequester(q); | ||
611 | edit->lineEdit()->setReadOnly(true); | 679 | edit->lineEdit()->setReadOnly(true); | ||
612 | edit->button()->hide(); | 680 | edit->button()->hide(); | ||
613 | } | 681 | } | ||
614 | 682 | | |||
615 | edit->setText(_value); | 683 | edit->setText(_value); | ||
616 | edit->setWhatsThis(i18n( | 684 | edit->setWhatsThis(i18n( | ||
Show All 15 Lines | 699 | if (edit->comboBox()) { | |||
632 | KUrlCompletion *comp = new KUrlCompletion(KUrlCompletion::ExeCompletion); | 700 | KUrlCompletion *comp = new KUrlCompletion(KUrlCompletion::ExeCompletion); | ||
633 | edit->comboBox()->setCompletionObject(comp); | 701 | edit->comboBox()->setCompletionObject(comp); | ||
634 | edit->comboBox()->setAutoDeleteCompletionObject(true); | 702 | edit->comboBox()->setAutoDeleteCompletionObject(true); | ||
635 | } | 703 | } | ||
636 | 704 | | |||
637 | QObject::connect(edit, SIGNAL(textChanged(QString)), q, SLOT(slotTextChanged())); | 705 | QObject::connect(edit, SIGNAL(textChanged(QString)), q, SLOT(slotTextChanged())); | ||
638 | QObject::connect(edit, SIGNAL(urlSelected(QUrl)), q, SLOT(_k_slotFileSelected())); | 706 | QObject::connect(edit, SIGNAL(urlSelected(QUrl)), q, SLOT(_k_slotFileSelected())); | ||
639 | 707 | | |||
708 | QTreeViewProxyFilter *proxyModel = new QTreeViewProxyFilter(view); | ||||
709 | KApplicationModel *appModel = new KApplicationModel(proxyModel); | ||||
710 | proxyModel->setSourceModel(appModel); | ||||
711 | proxyModel->setFilterKeyColumn(0); | ||||
712 | proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); | ||||
640 | view = new KApplicationView(q); | 713 | view = new KApplicationView(q); | ||
641 | view->setModel(new KApplicationModel(view)); | 714 | view->setModels(appModel, proxyModel); | ||
642 | topLayout->addWidget(view); | 715 | topLayout->addWidget(view); | ||
643 | topLayout->setStretchFactor(view, 1); | 716 | topLayout->setStretchFactor(view, 1); | ||
644 | 717 | | |||
645 | QObject::connect(view, SIGNAL(selected(QString,QString)), | 718 | QObject::connect(view, SIGNAL(selected(QString,QString)), | ||
646 | q, SLOT(slotSelected(QString,QString))); | 719 | q, SLOT(slotSelected(QString,QString))); | ||
647 | QObject::connect(view, SIGNAL(highlighted(QString,QString)), | 720 | QObject::connect(view, SIGNAL(highlighted(QString,QString)), | ||
648 | q, SLOT(slotHighlighted(QString,QString))); | 721 | q, SLOT(slotHighlighted(QString,QString))); | ||
649 | QObject::connect(view, SIGNAL(doubleClicked(QModelIndex)), | 722 | QObject::connect(view, SIGNAL(doubleClicked(QModelIndex)), | ||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Line(s) | |||||
722 | { | 795 | { | ||
723 | delete d; | 796 | delete d; | ||
724 | } | 797 | } | ||
725 | 798 | | |||
726 | // ---------------------------------------------------------------------- | 799 | // ---------------------------------------------------------------------- | ||
727 | 800 | | |||
728 | void KOpenWithDialog::slotSelected(const QString & /*_name*/, const QString &_exec) | 801 | void KOpenWithDialog::slotSelected(const QString & /*_name*/, const QString &_exec) | ||
729 | { | 802 | { | ||
730 | KService::Ptr pService = d->curService; | 803 | d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!_exec.isEmpty()); | ||
731 | d->edit->setText(_exec); // calls slotTextChanged :( | | |||
732 | d->curService = pService; | | |||
733 | } | 804 | } | ||
734 | 805 | | |||
735 | // ---------------------------------------------------------------------- | 806 | // ---------------------------------------------------------------------- | ||
736 | 807 | | |||
737 | void KOpenWithDialog::slotHighlighted(const QString &entryPath, const QString &) | 808 | void KOpenWithDialog::slotHighlighted(const QString &entryPath, const QString &) | ||
738 | { | 809 | { | ||
739 | d->curService = KService::serviceByDesktopPath(entryPath); | 810 | d->curService = KService::serviceByDesktopPath(entryPath); | ||
740 | if (d->curService && !d->m_terminaldirty) { | 811 | if (d->curService && !d->m_terminaldirty) { | ||
741 | // ### indicate that default value was restored | 812 | // ### indicate that default value was restored | ||
742 | d->terminal->setChecked(d->curService->terminal()); | 813 | d->terminal->setChecked(d->curService->terminal()); | ||
743 | QString terminalOptions = d->curService->terminalOptions(); | 814 | QString terminalOptions = d->curService->terminalOptions(); | ||
744 | d->nocloseonexit->setChecked((terminalOptions.contains(QLatin1String("--noclose")))); | 815 | d->nocloseonexit->setChecked((terminalOptions.contains(QLatin1String("--noclose")))); | ||
745 | d->m_terminaldirty = false; // slotTerminalToggled changed it | 816 | d->m_terminaldirty = false; // slotTerminalToggled changed it | ||
746 | } | 817 | } | ||
747 | } | 818 | } | ||
748 | 819 | | |||
749 | // ---------------------------------------------------------------------- | 820 | // ---------------------------------------------------------------------- | ||
750 | 821 | | |||
751 | void KOpenWithDialog::slotTextChanged() | 822 | void KOpenWithDialog::slotTextChanged() | ||
752 | { | 823 | { | ||
753 | // Forget about the service | 824 | // Forget about the service only when the selection is empty | ||
825 | // otherwise changing text but hitting the same result clears curService | ||||
826 | bool selectionEmpty = !d->view->currentIndex().isValid(); | ||||
I think this would be more readable as const bool selectionEmpty = !d->view->currentIndex().isValid(); dfaure: I think this would be more readable as
const bool selectionEmpty = !d->view->currentIndex(). | |||||
827 | if (d->curService && selectionEmpty) { | ||||
754 | d->curService = nullptr; | 828 | d->curService = nullptr; | ||
755 | d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!d->edit->text().isEmpty()); | 829 | } | ||
830 | d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!d->edit->text().isEmpty() || d->curService); | ||||
831 | | ||||
832 | //Update the filter regexp with the new text in the lineedit | ||||
833 | d->view->proxyModel()->setFilterFixedString(d->edit->text()); | ||||
Please use QRegularExpression; QRegExp is deprecated. Although, if this is about FixedString, why not just use setFilterFixedString? dfaure: Please use QRegularExpression; QRegExp is deprecated.
Although, if this is about FixedString… | |||||
@simgunz This is marked as done, but still uses QRegExp and not QRegularExpression? rkflx: @simgunz This is marked as done, but still uses `QRegExp` and not `QRegularExpression`? | |||||
I was using the regular expression only to provide cases insensitive filter, but I saw now I can achieve it with fixed string filter as well. The interface of the method setFilterRegExp only accepts QRegExp. Thanks for pointing this out. simgunz: I was using the regular expression only to provide cases insensitive filter, but I saw now I… | |||||
Could the view have a method that returns the proxymodel (possibly as a QSortFilterProxyModel* if we don't actually need a subclass-typed pointer), to avoid this cast? dfaure: Could the view have a method that returns the proxymodel (possibly as a QSortFilterProxyModel*… | |||||
simgunz: Ok I'll add a method. | |||||
834 | | ||||
835 | //Expand all the nodes when the search string is 3 characters long | ||||
836 | //If the search string doesn't match anything there will be no nodes to expand | ||||
837 | if (d->edit->text().size() > 2) { | ||||
dfaure: s/not/no/ ? | |||||
838 | d->view->expandAll(); | ||||
839 | //Automatically select the first result (first leaf node) when the filter has match | ||||
840 | QModelIndex leafNodeIdx = d->view->model()->index(0, 0); | ||||
841 | while (d->view->model()->hasChildren(leafNodeIdx)) { | ||||
842 | leafNodeIdx = leafNodeIdx.child(0,0); | ||||
843 | } | ||||
844 | d->view->setCurrentIndex(leafNodeIdx); | ||||
845 | } else { | ||||
846 | d->view->collapseAll(); | ||||
847 | d->view->setCurrentIndex(d->view->rootIndex()); // Unset and deselect all the elements | ||||
848 | d->curService = nullptr; | ||||
849 | } | ||||
756 | } | 850 | } | ||
757 | 851 | | |||
758 | // ---------------------------------------------------------------------- | 852 | // ---------------------------------------------------------------------- | ||
759 | 853 | | |||
760 | void KOpenWithDialog::slotTerminalToggled(bool) | 854 | void KOpenWithDialog::slotTerminalToggled(bool) | ||
761 | { | 855 | { | ||
762 | // ### indicate that default value was overridden | 856 | // ### indicate that default value was overridden | ||
763 | d->m_terminaldirty = true; | 857 | d->m_terminaldirty = true; | ||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Line(s) | 896 | { | |||
826 | 920 | | |||
827 | // could be nullptr if the user canceled the dialog... | 921 | // could be nullptr if the user canceled the dialog... | ||
828 | m_pService = KService::serviceByStorageId(serviceId); | 922 | m_pService = KService::serviceByStorageId(serviceId); | ||
829 | } | 923 | } | ||
830 | 924 | | |||
831 | bool KOpenWithDialogPrivate::checkAccept() | 925 | bool KOpenWithDialogPrivate::checkAccept() | ||
832 | { | 926 | { | ||
833 | const QString typedExec(edit->text()); | 927 | const QString typedExec(edit->text()); | ||
834 | if (typedExec.isEmpty()) { | | |||
835 | return false; | | |||
836 | } | | |||
I checked this, but AFAIK it's fine to remove. @dfaure introduced this 10 years ago in R446:d6903613f07b, but I guess we are covered both by the disabled button for empty line edits as well as the checks below. rkflx: I checked this, but AFAIK it's fine to remove. @dfaure introduced this 10 years ago in R446… | |||||
837 | QString fullExec(typedExec); | 928 | QString fullExec(typedExec); | ||
838 | 929 | | |||
839 | QString serviceName; | 930 | QString serviceName; | ||
840 | QString initialServiceName; | 931 | QString initialServiceName; | ||
841 | QString preferredTerminal; | 932 | QString preferredTerminal; | ||
842 | QString configPath; | 933 | QString configPath; | ||
843 | QString serviceExec; | 934 | QString serviceExec; | ||
844 | m_pService = curService; | 935 | m_pService = curService; | ||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Line(s) | 1057 | #endif | |||
992 | } | 1083 | } | ||
993 | } | 1084 | } | ||
994 | } | 1085 | } | ||
995 | 1086 | | |||
996 | saveComboboxHistory(); | 1087 | saveComboboxHistory(); | ||
997 | return true; | 1088 | return true; | ||
998 | } | 1089 | } | ||
999 | 1090 | | |||
1091 | bool KOpenWithDialog::eventFilter(QObject *object, QEvent *event) | ||||
1092 | { | ||||
1093 | // Detect DownArrow to navigate the results in the QTreeView | ||||
1094 | if (object == d->edit && event->type() == QEvent::ShortcutOverride) { | ||||
1095 | QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); | ||||
1096 | if (keyEvent->key() == Qt::Key_Down) { | ||||
1097 | KHistoryComboBox *combo = static_cast<KHistoryComboBox *>(d->edit->comboBox()); | ||||
1098 | // FIXME: Disable arrow down in CompletionPopup and CompletionPopupAuto only when the dropdown list is shown. | ||||
1099 | // When popup completion mode is used the down arrow is used to navigate the dropdown list of results | ||||
rkflx: Is this a "fixme-before-commit" or a "fixme-sometimes-in-the-future" FIXME? | |||||
It is a fixme-sometimes-in-the-future. Actually I am not even sure how much of a problem that is, so any other opinion is welcomed. To be more clear on this point. Currently ↓ moves the focus to the tree view, while ↑ moves it back in the line edit history of commands. When the search provides no results, ↓ moves forward in the history. This is true for any completion type. Before my changes, ↓ was just moving forward in the history of commands. When we use CompletionPopup or CompletionPopupAuto we want ↓ to let use navigate the entries in the popup, so it shouldn't be used to focus on the treeview. At this point there are two possibilities:
At this point, once the popup is closed, one could use ↓ to focus the tree view, but currently ↓ is disabled. So in this sense the behavior is not consistent with the cases where other completion modes are used. (Note that when the popup is closed ↓ does not open it again, only typing more text opens it) simgunz: It is a fixme-sometimes-in-the-future. Actually I am not even sure how much of a problem that… | |||||
1100 | if (combo->completionMode() != KCompletion::CompletionPopup && combo->completionMode() != KCompletion::CompletionPopupAuto) { | ||||
1101 | QModelIndex leafNodeIdx = d->view->model()->index(0, 0); | ||||
1102 | // Check if we have at least one result or the focus is passed to the empty QTreeView | ||||
1103 | if (d->view->model()->hasChildren(leafNodeIdx)) { | ||||
1104 | d->view->setFocus(Qt::OtherFocusReason); | ||||
1105 | QApplication::sendEvent(d->view, keyEvent); | ||||
1106 | return true; | ||||
1107 | } | ||||
1108 | } | ||||
All this "return false" cascade isn't really needed, a single return false at the end would do the job, or even better, calling the eventFilter method of the base class, just in case that's implemented for other reasons. dfaure: All this "return false" cascade isn't really needed, a single return false at the end would do… | |||||
Yes, the cascade of return false doesn't make sense. You mean calling eventFilter of QDialog instead of returning false at the end? eventFilter of QDialog is virtual. simgunz: Yes, the cascade of return false doesn't make sense. You mean calling eventFilter of QDialog… | |||||
dfaure: Yes. | |||||
1109 | } | ||||
1110 | } | ||||
1111 | return QDialog::eventFilter(object, event); | ||||
1112 | } | ||||
1113 | | ||||
1000 | void KOpenWithDialog::accept() | 1114 | void KOpenWithDialog::accept() | ||
1001 | { | 1115 | { | ||
1002 | if (d->checkAccept()) { | 1116 | if (d->checkAccept()) { | ||
1003 | QDialog::accept(); | 1117 | QDialog::accept(); | ||
1004 | } | 1118 | } | ||
1005 | } | 1119 | } | ||
1006 | 1120 | | |||
1007 | QString KOpenWithDialog::text() const | 1121 | QString KOpenWithDialog::text() const | ||
▲ Show 20 Lines • Show All 43 Lines • Show Last 20 Lines |
spaces around '=' and '<'
I would put rowCount() into a local var, the compiler can't optimize away that call.