|
|
@@ -0,0 +1,216 @@
|
|
|
+#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())
|
|
|
+{
|
|
|
+ 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);
|
|
|
+
|
|
|
+ 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);
|
|
|
+ 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);
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return QWidget::eventFilter(p_watched, p_event);
|
|
|
+}
|
|
|
+
|
|
|
+void VSimpleSearchInput::handleEditTextChanged(const QString &p_text)
|
|
|
+{
|
|
|
+ if (!m_inSearchMode) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (p_text.isEmpty()) {
|
|
|
+ clearSearch();
|
|
|
+ m_obj->selectHitItem(NULL);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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());
|
|
|
+}
|
|
|
+
|
|
|
+void VSimpleSearchInput::updateInfoLabel(int p_nrHit, int p_total)
|
|
|
+{
|
|
|
+ m_infoLabel->setText(tr("%1/%2").arg(p_nrHit).arg(p_total));
|
|
|
+}
|