Support keyboard search selection

This commit is contained in:
reionwong 2021-09-20 11:04:33 +08:00
parent a324a3b771
commit 8587b0c040
10 changed files with 181 additions and 28 deletions

View file

@ -45,6 +45,7 @@ add_executable(cutefish-filemanager
helper/fm.cpp helper/fm.cpp
helper/shortcut.cpp helper/shortcut.cpp
helper/filelauncher.cpp helper/filelauncher.cpp
helper/keyboardsearchmanager.cpp
mimetype/mimeappmanager.cpp mimetype/mimeappmanager.cpp
mimetype/xdgdesktopfile.cpp mimetype/xdgdesktopfile.cpp

View file

@ -0,0 +1,56 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: Reion Wong <reion@cutefishos.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "keyboardsearchmanager.h"
KeyboardSearchManager *KEYBORDSRARCH_MANAGER_SELF = nullptr;
KeyboardSearchManager *KeyboardSearchManager::self()
{
if (!KEYBORDSRARCH_MANAGER_SELF)
KEYBORDSRARCH_MANAGER_SELF = new KeyboardSearchManager;
return KEYBORDSRARCH_MANAGER_SELF;
}
KeyboardSearchManager::KeyboardSearchManager(QObject *parent)
: QObject(parent)
, m_timeout(500)
{
// m_timer.setInterval(m_timeout);
// connect(&m_timer, &QTimer::timeout, this, [=] {
// m_searchText.clear();
// });
}
void KeyboardSearchManager::addKeys(const QString &keys)
{
if (!keys.isEmpty()) {
// m_timer.stop();
// m_searchText.append(keys);
// const QChar firstKey = m_searchText.length() > 0 ? m_searchText.at(0) : QChar();
// const bool sameKey = m_searchText.length() > 1 && m_searchText.count(firstKey) == m_searchText.length();
// emit searchTextChanged(sameKey ? firstKey : m_searchText, false);
emit searchTextChanged(keys, false);
// m_timer.start();
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: Reion Wong <reion@cutefishos.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEYBOARDSEARCHMANAGER_H
#define KEYBOARDSEARCHMANAGER_H
#include <QObject>
#include <QTimer>
class KeyboardSearchManager : public QObject
{
Q_OBJECT
public:
static KeyboardSearchManager *self();
explicit KeyboardSearchManager(QObject *parent = nullptr);
void addKeys(const QString &keys);
signals:
void searchTextChanged(const QString &string, bool searchFromNextItem);
private:
QString m_searchText;
qint64 m_timeout;
// QTimer m_timer;
};
#endif // KEYBOARDSEARCHMANAGER_H

View file

@ -1,5 +1,5 @@
/*************************************************************************** /***************************************************************************
* Copyright 2021 Reion Wong <aj@cutefishos.com> * * Copyright 2021 Reion Wong <reion@cutefishos.com> *
* Copyright Ken <https://stackoverflow.com/users/1568857/ken> * * Copyright Ken <https://stackoverflow.com/users/1568857/ken> *
* Copyright 2016 Leslie Zhai <xiangzhai83@gmail.com> * * Copyright 2016 Leslie Zhai <xiangzhai83@gmail.com> *
* * * *
@ -20,6 +20,7 @@
***************************************************************************/ ***************************************************************************/
#include "shortcut.h" #include "shortcut.h"
#include "keyboardsearchmanager.h"
#include <QKeyEvent> #include <QKeyEvent>
@ -67,6 +68,10 @@ bool ShortCut::eventFilter(QObject *obj, QEvent *e)
emit deleteFile(); emit deleteFile();
} else if (keyEvent->key() == Qt::Key_F5) { } else if (keyEvent->key() == Qt::Key_F5) {
emit refresh(); emit refresh();
} else if (keyEvent->key() >= Qt::Key_A && keyEvent->key() <= Qt::Key_Z) {
// Handle select
KeyboardSearchManager::self()->addKeys(keyEvent->text());
keyEvent->ignore();
} }
} }

View file

@ -1,5 +1,5 @@
/*************************************************************************** /***************************************************************************
* Copyright 2021 Reion Wong <aj@cutefishos.com> * * Copyright 2021 Reion Wong <reion@cutefishos.com> *
* Copyright Ken <https://stackoverflow.com/users/1568857/ken> * * Copyright Ken <https://stackoverflow.com/users/1568857/ken> *
* Copyright 2016 Leslie Zhai <xiangzhai83@gmail.com> * * Copyright 2016 Leslie Zhai <xiangzhai83@gmail.com> *
* * * *
@ -24,17 +24,6 @@
#include <QObject> #include <QObject>
/**
* TODO: ShortCut is a stopgap solution and should be dropped when Qt's StandardKey
* gains support for these actions. QTBUG-54926 https://bugreports.qt.io/browse/QTBUG-54926
* And it is *NOT* encouraged registering C++ types with the QML by using EventFilter
* but for special case QTBUG-40327 https://bugreports.qt.io/browse/QTBUG-40327
*
* ShortCut was copied from Ken's answer.
* https://stackoverflow.com/questions/12192780/assigning-keyboard-shortcuts-to-qml-components
* it uses cc by-sa 3.0 license by default compatible with GPL.
* https://www.gnu.org/licenses/license-list.en.html#ccbysa
*/
class ShortCut : public QObject class ShortCut : public QObject
{ {
Q_OBJECT Q_OBJECT

View file

@ -90,6 +90,7 @@ FolderModel::FolderModel(QObject *parent)
, m_viewAdapter(nullptr) , m_viewAdapter(nullptr)
, m_mimeAppManager(MimeAppManager::self()) , m_mimeAppManager(MimeAppManager::self())
, m_sizeJob(nullptr) , m_sizeJob(nullptr)
, m_keyboardSearchManager(KeyboardSearchManager::self())
{ {
QSettings settings("cutefishos", qApp->applicationName()); QSettings settings("cutefishos", qApp->applicationName());
m_showHiddenFiles = settings.value("showHiddenFiles", false).toBool(); m_showHiddenFiles = settings.value("showHiddenFiles", false).toBool();
@ -119,6 +120,9 @@ FolderModel::FolderModel(QObject *parent)
connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)), SIGNAL(countChanged())); connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)), SIGNAL(countChanged()));
connect(this, SIGNAL(rowsRemoved(QModelIndex, int, int)), SIGNAL(countChanged())); connect(this, SIGNAL(rowsRemoved(QModelIndex, int, int)), SIGNAL(countChanged()));
connect(this, SIGNAL(modelReset()), SIGNAL(countChanged())); connect(this, SIGNAL(modelReset()), SIGNAL(countChanged()));
connect(m_keyboardSearchManager, &KeyboardSearchManager::searchTextChanged,
this, &FolderModel::keyboardSearchChanged);
} }
FolderModel::~FolderModel() FolderModel::~FolderModel()
@ -232,11 +236,39 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const
return QSortFilterProxyModel::data(index, role); return QSortFilterProxyModel::data(index, role);
} }
int FolderModel::indexForKeyboardSearch(const QString &text, int startFromIndex) const
{
startFromIndex = qMax(0, startFromIndex);
for (int i = startFromIndex; i < rowCount(); ++i) {
if (fileItem(i).text().startsWith(text, Qt::CaseInsensitive)) {
return i;
}
}
for (int i = 0; i < startFromIndex; ++i) {
if (fileItem(i).text().startsWith(text, Qt::CaseInsensitive)) {
return i;
}
}
return -1;
}
KFileItem FolderModel::itemForIndex(const QModelIndex &index) const KFileItem FolderModel::itemForIndex(const QModelIndex &index) const
{ {
return m_dirModel->itemForIndex(mapToSource(index)); return m_dirModel->itemForIndex(mapToSource(index));
} }
KFileItem FolderModel::fileItem(int index) const
{
if (index >= 0 && index < count()) {
return itemForIndex(FolderModel::index(index, 0));
}
return KFileItem();
}
QList<QUrl> FolderModel::selectedUrls() const QList<QUrl> FolderModel::selectedUrls() const
{ {
const auto indexes = m_selectionModel->selectedIndexes(); const auto indexes = m_selectionModel->selectedIndexes();
@ -1241,6 +1273,37 @@ void FolderModel::dragSelectedInternal(int x, int y)
} }
} }
void FolderModel::keyboardSearchChanged(const QString &text, bool searchFromNextItem)
{
Q_UNUSED(searchFromNextItem);
if (rowCount() == 0)
return;
int index;
int currentIndex = -1;
if (m_selectionModel->hasSelection()) {
currentIndex = m_selectionModel->selectedIndexes().first().row();
}
// if (searchFromNextItem) {
// index = indexForKeyboardSearch(text, (currentIndex + 1) % rowCount());
// } else {
// index = indexForKeyboardSearch(text, 0);
// }
index = indexForKeyboardSearch(text, (currentIndex + 1) % rowCount());
if (index < 0 || currentIndex == index)
return;
if (index >= 0) {
clearSelection();
setSelected(index);
}
}
bool FolderModel::isSupportThumbnails(const QString &mimeType) const bool FolderModel::isSupportThumbnails(const QString &mimeType) const
{ {
const QStringList supportsMimetypes = {"image/bmp", "image/png", "image/gif", "image/jpeg", "image/web", const QStringList supportsMimetypes = {"image/bmp", "image/png", "image/gif", "image/jpeg", "image/web",

View file

@ -26,6 +26,7 @@
#define FOLDERMODEL_H #define FOLDERMODEL_H
#include "../widgets/itemviewadapter.h" #include "../widgets/itemviewadapter.h"
#include "../helper/keyboardsearchmanager.h"
#include "../helper/pathhistory.h" #include "../helper/pathhistory.h"
#include "../mimetype/mimeappmanager.h" #include "../mimetype/mimeappmanager.h"
@ -109,8 +110,11 @@ public:
static QHash<int, QByteArray> staticRoleNames(); static QHash<int, QByteArray> staticRoleNames();
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int indexForKeyboardSearch(const QString &text, int startFromIndex = 0) const;
KFileItem itemForIndex(const QModelIndex &index) const; KFileItem itemForIndex(const QModelIndex &index) const;
KFileItem fileItem(int index) const;
QList<QUrl> selectedUrls() const; QList<QUrl> selectedUrls() const;
QString url() const; QString url() const;
@ -238,6 +242,7 @@ signals:
private slots: private slots:
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void dragSelectedInternal(int x, int y); void dragSelectedInternal(int x, int y);
void keyboardSearchChanged(const QString &text, bool searchFromNextItem);
private: private:
void invalidateIfComplete(); void invalidateIfComplete();
@ -294,6 +299,8 @@ private:
MimeAppManager *m_mimeAppManager; MimeAppManager *m_mimeAppManager;
CFileSizeJob *m_sizeJob; CFileSizeJob *m_sizeJob;
KeyboardSearchManager *m_keyboardSearchManager;
}; };
#endif // FOLDERMODEL_H #endif // FOLDERMODEL_H

View file

@ -111,7 +111,7 @@ Item {
anchors.fill: _icon anchors.fill: _icon
source: _icon source: _icon
color: "white" color: "white"
opacity: FishUI.Theme.darkMode ? 0.3 : 0.4 opacity: 0.3
visible: control.hovered && !control.selected visible: control.hovered && !control.selected
} }
} }

View file

@ -46,7 +46,6 @@ GridView {
property bool ctrlPressed: false property bool ctrlPressed: false
property bool shiftPressed: false property bool shiftPressed: false
property int previouslySelectedItemIndex: -1
property variant cPress: null property variant cPress: null
property Item editor: null property Item editor: null
property int anchorIndex: 0 property int anchorIndex: 0
@ -138,7 +137,6 @@ GridView {
function reset() { function reset() {
currentIndex = -1 currentIndex = -1
anchorIndex = 0 anchorIndex = 0
previouslySelectedItemIndex = -1
cancelRename() cancelRename()
hoveredItem = null hoveredItem = null
pressedItem = null pressedItem = null
@ -174,7 +172,6 @@ GridView {
} }
Keys.onEscapePressed: { Keys.onEscapePressed: {
if (!editor || !editor.targetItem) { if (!editor || !editor.targetItem) {
previouslySelectedItemIndex = -1
dirModel.clearSelection() dirModel.clearSelection()
event.accepted = false event.accepted = false
} }
@ -602,9 +599,6 @@ GridView {
} else { } else {
dirModel.clearSelection() dirModel.clearSelection()
dirModel.setSelected(currentIndex) dirModel.setSelected(currentIndex)
if (currentIndex == -1)
previouslySelectedItemIndex = -1
previouslySelectedItemIndex = currentIndex
} }
} }

View file

@ -40,7 +40,6 @@ ListView {
property bool ctrlPressed: false property bool ctrlPressed: false
property bool shiftPressed: false property bool shiftPressed: false
property int previouslySelectedItemIndex: -1
property variant cPress: null property variant cPress: null
property Item editor: null property Item editor: null
property int anchorIndex: 0 property int anchorIndex: 0
@ -86,7 +85,6 @@ ListView {
function reset() { function reset() {
currentIndex = -1 currentIndex = -1
anchorIndex = 0 anchorIndex = 0
previouslySelectedItemIndex = -1
cancelRename() cancelRename()
hoveredItem = null hoveredItem = null
pressedItem = null pressedItem = null
@ -119,7 +117,6 @@ ListView {
Keys.onEscapePressed: { Keys.onEscapePressed: {
if (!editor || !editor.targetItem) { if (!editor || !editor.targetItem) {
previouslySelectedItemIndex = -1
dirModel.clearSelection() dirModel.clearSelection()
event.accepted = false event.accepted = false
} }
@ -215,7 +212,6 @@ ListView {
if (!hoveredItem || hoveredItem.blank) { if (!hoveredItem || hoveredItem.blank) {
if (!control.ctrlPressed) { if (!control.ctrlPressed) {
control.currentIndex = -1 control.currentIndex = -1
control.previouslySelectedItemIndex = -1
dirModel.clearSelection() dirModel.clearSelection()
} }
@ -231,7 +227,6 @@ ListView {
dirModel.setRangeSelected(control.anchorIndex, hoveredItem.index) dirModel.setRangeSelected(control.anchorIndex, hoveredItem.index)
} else { } else {
if (!control.ctrlPressed && !dirModel.isSelected(hoveredItem.index)) { if (!control.ctrlPressed && !dirModel.isSelected(hoveredItem.index)) {
previouslySelectedItemIndex = -1
dirModel.clearSelection() dirModel.clearSelection()
} }
@ -395,9 +390,6 @@ ListView {
} else { } else {
dirModel.clearSelection() dirModel.clearSelection()
dirModel.setSelected(currentIndex) dirModel.setSelected(currentIndex)
if (currentIndex == -1)
previouslySelectedItemIndex = -1
previouslySelectedItemIndex = currentIndex
} }
} }