mumble-voip_mumble/src/mumble/SearchDialog.h

148 lines
4.0 KiB
C++

// Copyright 2021-2023 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#ifndef MUMBLE_MUMBLE_SEARCHDIALOG_H_
#define MUMBLE_MUMBLE_SEARCHDIALOG_H_
#include "MultiStyleWidgetWrapper.h"
#include <QString>
#include <map>
#include <memory>
#include <unordered_set>
#include "ui_SearchDialog.h"
class QWidget;
class QTreeWidgetItem;
class QKeyEvent;
class QContextMenuEvent;
class QHideEvent;
class QShowEvent;
class SearchDialogItemDelegate;
namespace Search {
/**
* The type of a search result
*/
enum class SearchType { User, Channel };
/**
* This struct represents a search result and contains some metainformation
* on it.
*/
struct SearchResult {
int32_t begin = -1;
int32_t length = -1;
SearchType type;
QString fullText;
QString channelHierarchy;
operator bool() {
// A search result is only valid if it has start and end
return begin >= 0 && length > 0;
}
};
class SearchResultItem;
class ChannelItem;
/**
* This comparator is used to sort search results
*/
struct SearchResultSortComparator {
bool operator()(const SearchResult &lhs, const SearchResult &rhs) const {
// Prioritize longer matches (only relevant if match is obtained via RegEx)
if (lhs.length != rhs.length) {
return lhs.length > rhs.length;
}
if (lhs.begin != rhs.begin) {
// The closer to the start a match is found, the higher its priority
return lhs.begin < rhs.begin;
}
if (lhs.fullText != rhs.fullText) {
return lhs.fullText.compare(rhs.fullText) < 0;
}
if (lhs.channelHierarchy != rhs.channelHierarchy) {
return lhs.channelHierarchy.compare(rhs.channelHierarchy) < 0;
}
// Order users before channels
return lhs.type == SearchType::User;
}
};
using SearchResultMap = std::map< SearchResult, unsigned int, SearchResultSortComparator >;
/**
* The search result class is the one that pops up when triggering the search functionality
*/
class SearchDialog : public QWidget, private Ui::SearchDialog {
Q_OBJECT
Q_DISABLE_COPY(SearchDialog)
public:
SearchDialog(QWidget *parent = nullptr);
~SearchDialog() = default;
/**
* Possible actions that can be performed on a selected search
* result, if it is a user.
*/
enum class UserAction { NONE, JOIN };
/**
* Possible actions that can be performed on a selected search
* result, if it is a channel.
*/
enum class ChannelAction { NONE, JOIN };
static QString toString(UserAction action);
static QString toString(ChannelAction action);
public slots:
void on_toggleOptions_clicked();
void on_searchField_returnPressed();
void on_searchField_textChanged(const QString &text);
void on_userOption_clicked(bool checked);
void on_channelOption_clicked(bool checked);
void on_caseSensitiveOption_clicked(bool checked);
void on_regexOption_clicked(bool checked);
void on_searchResultTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
void on_searchResultTree_itemActivated(QTreeWidgetItem *item, int column);
void searchAgain();
void clearSearchResults();
void search(const QString &searchTerm);
void on_serverConnectionSynchronized();
void on_serverDisconnected();
void on_clientDisconnected(unsigned int userSession);
void on_channelRemoved(unsigned int channelID);
private:
MultiStyleWidgetWrapper m_searchFieldStyleWrapper;
std::unordered_set< void * > m_relayedKeyEvents;
std::unique_ptr< SearchDialogItemDelegate > m_itemDelegate;
void setSearchResults(const SearchResultMap &results);
void hideEvent(QHideEvent *event) override;
void showEvent(QShowEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override;
void performDefaultAction(const SearchResultItem &item);
bool removeSearchResult(unsigned int id, bool isUser);
};
} // namespace Search
Q_DECLARE_METATYPE(Search::SearchDialog::UserAction)
Q_DECLARE_METATYPE(Search::SearchDialog::ChannelAction)
#endif // MUMBLE_MUMBLE_SEARCHDIALOG_H_