| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- #include "vsimplesearchinput.h"
- #include <QHBoxLayout>
- #include <QKeyEvent>
- #include <QFocusEvent>
- #include <QRegExpValidator>
- #include <QRegExp>
- #include <QLabel>
- #include "vlineedit.h"
- #include "utils/vutils.h"
- #include "vconfigmanager.h"
- extern VConfigManager *g_config;
- VSimpleSearchInput::VSimpleSearchInput(ISimpleSearch *p_obj, QWidget *p_parent)
- : QWidget(p_parent),
- m_obj(p_obj),
- m_inSearchMode(false),
- m_currentIdx(-1),
- m_wildCardEnabled(g_config->getEnableWildCardInSimpleSearch()),
- m_navigationKeyEnabled(false)
- {
- if (m_wildCardEnabled) {
- m_matchFlags = Qt::MatchWildcard | Qt::MatchWrap | Qt::MatchRecursive;
- } else {
- m_matchFlags = Qt::MatchContains | Qt::MatchWrap | Qt::MatchRecursive;
- }
- m_searchEdit = new VLineEdit();
- m_searchEdit->setPlaceholderText(tr("Type to search"));
- m_searchEdit->setCtrlKEnabled(false);
- connect(m_searchEdit, &QLineEdit::textChanged,
- this, &VSimpleSearchInput::handleEditTextChanged);
- QValidator *validator = new QRegExpValidator(QRegExp(VUtils::c_fileNameRegExp),
- m_searchEdit);
- m_searchEdit->setValidator(validator);
- m_searchEdit->installEventFilter(this);
- m_infoLabel = new QLabel();
- QLayout *layout = new QHBoxLayout();
- layout->addWidget(m_searchEdit);
- layout->addWidget(m_infoLabel);
- layout->setContentsMargins(0, 0, 0, 0);
- setLayout(layout);
- }
- void VSimpleSearchInput::clear()
- {
- m_inSearchMode = false;
- clearSearch();
- }
- // If it is the / leader key to trigger search mode.
- static bool isLeaderKey(int p_key, int p_modifiers)
- {
- return p_key == Qt::Key_Slash && p_modifiers == Qt::NoModifier;
- }
- static bool isCharKey(int p_key, int p_modifiers)
- {
- return p_key >= Qt::Key_A
- && p_key <= Qt::Key_Z
- && (p_modifiers == Qt::NoModifier || p_modifiers == Qt::ShiftModifier);
- }
- static bool isDigitKey(int p_key, int p_modifiers)
- {
- return p_key >= Qt::Key_0
- && p_key <= Qt::Key_9
- && (p_modifiers == Qt::NoModifier || p_modifiers == Qt::KeypadModifier);
- }
- static QChar keyToChar(int p_key, int p_modifiers)
- {
- if (isCharKey(p_key, p_modifiers)) {
- char ch = p_modifiers == Qt::ShiftModifier ? 'A' : 'a';
- return QChar(ch + (p_key - Qt::Key_A));
- } else if (isDigitKey(p_key, p_modifiers)) {
- return QChar('0' + (p_key - Qt::Key_0));
- }
- return QChar();
- }
- bool VSimpleSearchInput::tryHandleKeyPressEvent(QKeyEvent *p_event)
- {
- int key = p_event->key();
- Qt::KeyboardModifiers modifiers = p_event->modifiers();
- if (!m_inSearchMode) {
- // Try to trigger search mode.
- QChar ch;
- if (isCharKey(key, modifiers)
- || isDigitKey(key, modifiers)) {
- m_inSearchMode = true;
- ch = keyToChar(key, modifiers);
- } else if (isLeaderKey(key, modifiers)) {
- m_inSearchMode = true;
- }
- if (m_inSearchMode) {
- emit triggered(m_inSearchMode, false);
- clearSearch();
- m_searchEdit->setFocus();
- if (!ch.isNull()) {
- m_searchEdit->setText(ch);
- }
- return true;
- }
- } else {
- // Try to exit search mode.
- if (key == Qt::Key_Escape
- || (key == Qt::Key_BracketLeft
- && VUtils::isControlModifierForVim(modifiers))) {
- m_inSearchMode = false;
- emit triggered(m_inSearchMode, true);
- return true;
- }
- }
- // Ctrl+N/P to activate next hit item.
- if (VUtils::isControlModifierForVim(modifiers)
- && (key == Qt::Key_N || key == Qt::Key_P)) {
- int delta = key == Qt::Key_N ? 1 : -1;
- if (!m_inSearchMode) {
- m_inSearchMode = true;
- emit triggered(m_inSearchMode, false);
- m_searchEdit->setFocus();
- m_obj->highlightHitItems(m_hitItems);
- }
- if (!m_hitItems.isEmpty()) {
- m_currentIdx += delta;
- if (m_currentIdx < 0) {
- m_currentIdx = m_hitItems.size() - 1;
- } else if (m_currentIdx >= m_hitItems.size()) {
- m_currentIdx = 0;
- }
- m_obj->selectHitItem(currentItem());
- }
- return true;
- }
- // Up/Down Ctrl+K/J to navigate to next item.
- // QTreeWidget may not response to the key event if it does not have the focus.
- if (m_inSearchMode && m_navigationKeyEnabled) {
- if (key == Qt::Key_Down
- || key == Qt::Key_Up
- || (VUtils::isControlModifierForVim(modifiers)
- && (key == Qt::Key_J || key == Qt::Key_K))) {
- bool forward = true;
- if (key == Qt::Key_Up || key == Qt::Key_K) {
- forward = false;
- }
- m_obj->selectNextItem(forward);
- return true;
- }
- }
- return false;
- }
- void VSimpleSearchInput::clearSearch()
- {
- m_searchEdit->clear();
- m_hitItems.clear();
- m_currentIdx = -1;
- m_obj->clearItemsHighlight();
- updateInfoLabel(0, m_obj->totalNumberOfItems());
- }
- bool VSimpleSearchInput::eventFilter(QObject *p_watched, QEvent *p_event)
- {
- Q_UNUSED(p_watched);
- if (p_event->type() == QEvent::FocusOut) {
- QFocusEvent *eve = static_cast<QFocusEvent *>(p_event);
- if (eve->reason() != Qt::ActiveWindowFocusReason) {
- m_inSearchMode = false;
- emit triggered(m_inSearchMode, false);
- }
- }
- return QWidget::eventFilter(p_watched, p_event);
- }
- void VSimpleSearchInput::handleEditTextChanged(const QString &p_text)
- {
- if (!m_inSearchMode) {
- goto exit;
- }
- if (p_text.isEmpty()) {
- clearSearch();
- m_obj->selectHitItem(NULL);
- goto exit;
- }
- if (m_wildCardEnabled) {
- QString wildcardText(p_text.size() * 2 + 1, '*');
- for (int i = 0, j = 1; i < p_text.size(); ++i, j += 2) {
- wildcardText[j] = p_text[i];
- }
- m_hitItems = m_obj->searchItems(wildcardText, m_matchFlags);
- } else {
- m_hitItems = m_obj->searchItems(p_text, m_matchFlags);
- }
- updateInfoLabel(m_hitItems.size(), m_obj->totalNumberOfItems());
- m_obj->highlightHitItems(m_hitItems);
- m_currentIdx = m_hitItems.isEmpty() ? -1 : 0;
- m_obj->selectHitItem(currentItem());
- exit:
- emit inputTextChanged(p_text);
- }
- void VSimpleSearchInput::updateInfoLabel(int p_nrHit, int p_total)
- {
- m_infoLabel->setText(tr("%1/%2").arg(p_nrHit).arg(p_total));
- }
|