Merge branch 'master' into irc-support
This commit is contained in:
@@ -133,6 +133,8 @@ ChannelView::ChannelView(BaseWidget *parent)
|
||||
this->clickTimer_ = new QTimer(this);
|
||||
this->clickTimer_->setSingleShot(true);
|
||||
this->clickTimer_->setInterval(500);
|
||||
|
||||
this->setFocusPolicy(Qt::FocusPolicy::StrongFocus);
|
||||
}
|
||||
|
||||
void ChannelView::initializeLayout()
|
||||
@@ -1526,14 +1528,8 @@ void ChannelView::addContextMenuItems(
|
||||
QString url = hoveredElement->getLink().value;
|
||||
|
||||
// open link
|
||||
bool incognitoByDefault = supportsIncognitoLinks() &&
|
||||
layout->getMessage()->loginName == "hemirt";
|
||||
menu->addAction("Open link", [url, incognitoByDefault] {
|
||||
if (incognitoByDefault)
|
||||
openLinkIncognito(url);
|
||||
else
|
||||
QDesktopServices::openUrl(QUrl(url));
|
||||
});
|
||||
menu->addAction("Open link",
|
||||
[url] { QDesktopServices::openUrl(QUrl(url)); });
|
||||
// open link default
|
||||
if (supportsIncognitoLinks())
|
||||
{
|
||||
@@ -1699,7 +1695,10 @@ void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link,
|
||||
|
||||
case Link::Url:
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl(link.value));
|
||||
if (getSettings()->openLinksIncognito && supportsIncognitoLinks())
|
||||
openLinkIncognito(link.value);
|
||||
else
|
||||
QDesktopServices::openUrl(QUrl(link.value));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -1,65 +1,65 @@
|
||||
#include "ComboBoxItemDelegate.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
ComboBoxItemDelegate::ComboBoxItemDelegate(QObject *parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ComboBoxItemDelegate::~ComboBoxItemDelegate()
|
||||
{
|
||||
}
|
||||
|
||||
QWidget *ComboBoxItemDelegate::createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
QVariant data = index.data(Qt::UserRole + 1);
|
||||
|
||||
if (data.type() != QVariant::StringList)
|
||||
{
|
||||
return QStyledItemDelegate::createEditor(parent, option, index);
|
||||
}
|
||||
|
||||
QComboBox *combo = new QComboBox(parent);
|
||||
combo->addItems(data.toStringList());
|
||||
return combo;
|
||||
}
|
||||
|
||||
void ComboBoxItemDelegate::setEditorData(QWidget *editor,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
if (QComboBox *cb = qobject_cast<QComboBox *>(editor))
|
||||
{
|
||||
// get the index of the text in the combobox that matches the current
|
||||
// value of the itenm
|
||||
QString currentText = index.data(Qt::EditRole).toString();
|
||||
int cbIndex = cb->findText(currentText);
|
||||
|
||||
// if it is valid, adjust the combobox
|
||||
if (cbIndex >= 0)
|
||||
{
|
||||
cb->setCurrentIndex(cbIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QStyledItemDelegate::setEditorData(editor, index);
|
||||
}
|
||||
}
|
||||
|
||||
void ComboBoxItemDelegate::setModelData(QWidget *editor,
|
||||
QAbstractItemModel *model,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
if (QComboBox *cb = qobject_cast<QComboBox *>(editor))
|
||||
// save the current text of the combo box as the current value of the
|
||||
// item
|
||||
model->setData(index, cb->currentText(), Qt::EditRole);
|
||||
else
|
||||
QStyledItemDelegate::setModelData(editor, model, index);
|
||||
}
|
||||
} // namespace chatterino
|
||||
#include "ComboBoxItemDelegate.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
ComboBoxItemDelegate::ComboBoxItemDelegate(QObject *parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ComboBoxItemDelegate::~ComboBoxItemDelegate()
|
||||
{
|
||||
}
|
||||
|
||||
QWidget *ComboBoxItemDelegate::createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
QVariant data = index.data(Qt::UserRole + 1);
|
||||
|
||||
if (data.type() != QVariant::StringList)
|
||||
{
|
||||
return QStyledItemDelegate::createEditor(parent, option, index);
|
||||
}
|
||||
|
||||
QComboBox *combo = new QComboBox(parent);
|
||||
combo->addItems(data.toStringList());
|
||||
return combo;
|
||||
}
|
||||
|
||||
void ComboBoxItemDelegate::setEditorData(QWidget *editor,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
if (QComboBox *cb = qobject_cast<QComboBox *>(editor))
|
||||
{
|
||||
// get the index of the text in the combobox that matches the current
|
||||
// value of the itenm
|
||||
QString currentText = index.data(Qt::EditRole).toString();
|
||||
int cbIndex = cb->findText(currentText);
|
||||
|
||||
// if it is valid, adjust the combobox
|
||||
if (cbIndex >= 0)
|
||||
{
|
||||
cb->setCurrentIndex(cbIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QStyledItemDelegate::setEditorData(editor, index);
|
||||
}
|
||||
}
|
||||
|
||||
void ComboBoxItemDelegate::setModelData(QWidget *editor,
|
||||
QAbstractItemModel *model,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
if (QComboBox *cb = qobject_cast<QComboBox *>(editor))
|
||||
// save the current text of the combo box as the current value of the
|
||||
// item
|
||||
model->setData(index, cb->currentText(), Qt::EditRole);
|
||||
else
|
||||
QStyledItemDelegate::setModelData(editor, model, index);
|
||||
}
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
// stolen from https://wiki.qt.io/Combo_Boxes_in_Item_Views
|
||||
|
||||
class ComboBoxItemDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ComboBoxItemDelegate(QObject *parent = nullptr);
|
||||
~ComboBoxItemDelegate();
|
||||
|
||||
virtual QWidget *createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const;
|
||||
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const;
|
||||
virtual void setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
// stolen from https://wiki.qt.io/Combo_Boxes_in_Item_Views
|
||||
|
||||
class ComboBoxItemDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ComboBoxItemDelegate(QObject *parent = nullptr);
|
||||
~ComboBoxItemDelegate();
|
||||
|
||||
virtual QWidget *createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const;
|
||||
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const;
|
||||
virtual void setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
#include "DebugPopup.hpp"
|
||||
|
||||
#include "util/DebugCount.hpp"
|
||||
|
||||
#include <QFontDatabase>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
DebugPopup::DebugPopup()
|
||||
{
|
||||
auto *layout = new QHBoxLayout(this);
|
||||
auto *text = new QLabel(this);
|
||||
auto *timer = new QTimer(this);
|
||||
|
||||
timer->setInterval(300);
|
||||
QObject::connect(timer, &QTimer::timeout,
|
||||
[text] { text->setText(DebugCount::getDebugText()); });
|
||||
timer->start();
|
||||
|
||||
text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
|
||||
|
||||
layout->addWidget(text);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "DebugPopup.hpp"
|
||||
|
||||
#include "util/DebugCount.hpp"
|
||||
|
||||
#include <QFontDatabase>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
DebugPopup::DebugPopup()
|
||||
{
|
||||
auto *layout = new QHBoxLayout(this);
|
||||
auto *text = new QLabel(this);
|
||||
auto *timer = new QTimer(this);
|
||||
|
||||
timer->setInterval(300);
|
||||
QObject::connect(timer, &QTimer::timeout,
|
||||
[text] { text->setText(DebugCount::getDebugText()); });
|
||||
timer->start();
|
||||
|
||||
text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
|
||||
|
||||
layout->addWidget(text);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class DebugPopup : public QWidget
|
||||
{
|
||||
public:
|
||||
DebugPopup();
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class DebugPopup : public QWidget
|
||||
{
|
||||
public:
|
||||
DebugPopup();
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,97 +1,97 @@
|
||||
#include "EditableModelView.hpp"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QPushButton>
|
||||
#include <QTableView>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
EditableModelView::EditableModelView(QAbstractTableModel *model)
|
||||
: tableView_(new QTableView(this))
|
||||
, model_(model)
|
||||
{
|
||||
this->model_->setParent(this);
|
||||
this->tableView_->setModel(model);
|
||||
this->tableView_->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
this->tableView_->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
this->tableView_->verticalHeader()->hide();
|
||||
|
||||
// create layout
|
||||
QVBoxLayout *vbox = new QVBoxLayout(this);
|
||||
vbox->setMargin(0);
|
||||
|
||||
// create button layout
|
||||
QHBoxLayout *buttons = new QHBoxLayout(this);
|
||||
this->buttons_ = buttons;
|
||||
vbox->addLayout(buttons);
|
||||
|
||||
// add
|
||||
QPushButton *add = new QPushButton("Add");
|
||||
buttons->addWidget(add);
|
||||
QObject::connect(add, &QPushButton::clicked,
|
||||
[this] { this->addButtonPressed.invoke(); });
|
||||
|
||||
// remove
|
||||
QPushButton *remove = new QPushButton("Remove");
|
||||
buttons->addWidget(remove);
|
||||
QObject::connect(remove, &QPushButton::clicked, [this] {
|
||||
QModelIndexList list;
|
||||
while ((list = this->getTableView()->selectionModel()->selectedRows(0))
|
||||
.length() > 0)
|
||||
{
|
||||
model_->removeRow(list[0].row());
|
||||
}
|
||||
});
|
||||
|
||||
buttons->addStretch();
|
||||
|
||||
// add tableview
|
||||
vbox->addWidget(this->tableView_);
|
||||
|
||||
// finish button layout
|
||||
buttons->addStretch(1);
|
||||
}
|
||||
|
||||
void EditableModelView::setTitles(std::initializer_list<QString> titles)
|
||||
{
|
||||
int i = 0;
|
||||
for (const QString &title : titles)
|
||||
{
|
||||
if (this->model_->columnCount() == i)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
this->model_->setHeaderData(i++, Qt::Horizontal, title,
|
||||
Qt::DisplayRole);
|
||||
}
|
||||
}
|
||||
|
||||
QTableView *EditableModelView::getTableView()
|
||||
{
|
||||
return this->tableView_;
|
||||
}
|
||||
|
||||
QAbstractTableModel *EditableModelView::getModel()
|
||||
{
|
||||
return this->model_;
|
||||
}
|
||||
|
||||
void EditableModelView::addCustomButton(QWidget *widget)
|
||||
{
|
||||
this->buttons_->addWidget(widget);
|
||||
}
|
||||
|
||||
void EditableModelView::addRegexHelpLink()
|
||||
{
|
||||
auto regexHelpLabel =
|
||||
new QLabel("<a href='https://chatterino.com/help/regex'><span "
|
||||
"style='color:#99f'>regex info</span></a>");
|
||||
regexHelpLabel->setOpenExternalLinks(true);
|
||||
this->addCustomButton(regexHelpLabel);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "EditableModelView.hpp"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QPushButton>
|
||||
#include <QTableView>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
EditableModelView::EditableModelView(QAbstractTableModel *model)
|
||||
: tableView_(new QTableView(this))
|
||||
, model_(model)
|
||||
{
|
||||
this->model_->setParent(this);
|
||||
this->tableView_->setModel(model);
|
||||
this->tableView_->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
this->tableView_->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
this->tableView_->verticalHeader()->hide();
|
||||
|
||||
// create layout
|
||||
QVBoxLayout *vbox = new QVBoxLayout(this);
|
||||
vbox->setMargin(0);
|
||||
|
||||
// create button layout
|
||||
QHBoxLayout *buttons = new QHBoxLayout(this);
|
||||
this->buttons_ = buttons;
|
||||
vbox->addLayout(buttons);
|
||||
|
||||
// add
|
||||
QPushButton *add = new QPushButton("Add");
|
||||
buttons->addWidget(add);
|
||||
QObject::connect(add, &QPushButton::clicked,
|
||||
[this] { this->addButtonPressed.invoke(); });
|
||||
|
||||
// remove
|
||||
QPushButton *remove = new QPushButton("Remove");
|
||||
buttons->addWidget(remove);
|
||||
QObject::connect(remove, &QPushButton::clicked, [this] {
|
||||
QModelIndexList list;
|
||||
while ((list = this->getTableView()->selectionModel()->selectedRows(0))
|
||||
.length() > 0)
|
||||
{
|
||||
model_->removeRow(list[0].row());
|
||||
}
|
||||
});
|
||||
|
||||
buttons->addStretch();
|
||||
|
||||
// add tableview
|
||||
vbox->addWidget(this->tableView_);
|
||||
|
||||
// finish button layout
|
||||
buttons->addStretch(1);
|
||||
}
|
||||
|
||||
void EditableModelView::setTitles(std::initializer_list<QString> titles)
|
||||
{
|
||||
int i = 0;
|
||||
for (const QString &title : titles)
|
||||
{
|
||||
if (this->model_->columnCount() == i)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
this->model_->setHeaderData(i++, Qt::Horizontal, title,
|
||||
Qt::DisplayRole);
|
||||
}
|
||||
}
|
||||
|
||||
QTableView *EditableModelView::getTableView()
|
||||
{
|
||||
return this->tableView_;
|
||||
}
|
||||
|
||||
QAbstractTableModel *EditableModelView::getModel()
|
||||
{
|
||||
return this->model_;
|
||||
}
|
||||
|
||||
void EditableModelView::addCustomButton(QWidget *widget)
|
||||
{
|
||||
this->buttons_->addWidget(widget);
|
||||
}
|
||||
|
||||
void EditableModelView::addRegexHelpLink()
|
||||
{
|
||||
auto regexHelpLabel =
|
||||
new QLabel("<a href='https://chatterino.com/help/regex'><span "
|
||||
"style='color:#99f'>regex info</span></a>");
|
||||
regexHelpLabel->setOpenExternalLinks(true);
|
||||
this->addCustomButton(regexHelpLabel);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
class QAbstractTableModel;
|
||||
class QTableView;
|
||||
class QHBoxLayout;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class EditableModelView : public QWidget
|
||||
{
|
||||
public:
|
||||
EditableModelView(QAbstractTableModel *model);
|
||||
|
||||
void setTitles(std::initializer_list<QString> titles);
|
||||
|
||||
QTableView *getTableView();
|
||||
QAbstractTableModel *getModel();
|
||||
|
||||
pajlada::Signals::NoArgSignal addButtonPressed;
|
||||
|
||||
void addCustomButton(QWidget *widget);
|
||||
void addRegexHelpLink();
|
||||
|
||||
private:
|
||||
QTableView *tableView_{};
|
||||
QAbstractTableModel *model_{};
|
||||
QHBoxLayout *buttons_{};
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
class QAbstractTableModel;
|
||||
class QTableView;
|
||||
class QHBoxLayout;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class EditableModelView : public QWidget
|
||||
{
|
||||
public:
|
||||
EditableModelView(QAbstractTableModel *model);
|
||||
|
||||
void setTitles(std::initializer_list<QString> titles);
|
||||
|
||||
QTableView *getTableView();
|
||||
QAbstractTableModel *getModel();
|
||||
|
||||
pajlada::Signals::NoArgSignal addButtonPressed;
|
||||
|
||||
void addCustomButton(QWidget *widget);
|
||||
void addRegexHelpLink();
|
||||
|
||||
private:
|
||||
QTableView *tableView_{};
|
||||
QAbstractTableModel *model_{};
|
||||
QHBoxLayout *buttons_{};
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
+48
-48
@@ -1,48 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Line : public BaseWidget
|
||||
{
|
||||
public:
|
||||
Line(bool vertical)
|
||||
: BaseWidget(nullptr)
|
||||
, vertical_(vertical)
|
||||
{
|
||||
if (this->vertical_)
|
||||
{
|
||||
this->setScaleIndependantWidth(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setScaleIndependantHeight(8);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
painter.setPen(QColor("#999"));
|
||||
|
||||
if (this->vertical_)
|
||||
{
|
||||
painter.drawLine(this->width() / 2, 0, this->width() / 2,
|
||||
this->height());
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.drawLine(0, this->height() / 2, this->width(),
|
||||
this->height() / 2);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool vertical_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Line : public BaseWidget
|
||||
{
|
||||
public:
|
||||
Line(bool vertical)
|
||||
: BaseWidget(nullptr)
|
||||
, vertical_(vertical)
|
||||
{
|
||||
if (this->vertical_)
|
||||
{
|
||||
this->setScaleIndependantWidth(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setScaleIndependantHeight(8);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
painter.setPen(QColor("#999"));
|
||||
|
||||
if (this->vertical_)
|
||||
{
|
||||
painter.drawLine(this->width() / 2, 0, this->width() / 2,
|
||||
this->height());
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.drawLine(0, this->height() / 2, this->width(),
|
||||
this->height() / 2);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool vertical_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
+183
-104
@@ -1,104 +1,183 @@
|
||||
#include "SearchPopup.hpp"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
SearchPopup::SearchPopup()
|
||||
{
|
||||
this->initLayout();
|
||||
this->resize(400, 600);
|
||||
}
|
||||
|
||||
void SearchPopup::setChannel(ChannelPtr channel)
|
||||
{
|
||||
this->channelName_ = channel->getName();
|
||||
this->snapshot_ = channel->getMessageSnapshot();
|
||||
this->performSearch();
|
||||
|
||||
this->setWindowTitle("Searching in " + channel->getName() + "s history");
|
||||
}
|
||||
|
||||
void SearchPopup::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
if (e->key() == Qt::Key_Escape)
|
||||
{
|
||||
this->close();
|
||||
return;
|
||||
}
|
||||
|
||||
BaseWidget::keyPressEvent(e);
|
||||
}
|
||||
|
||||
void SearchPopup::initLayout()
|
||||
{
|
||||
// VBOX
|
||||
{
|
||||
QVBoxLayout *layout1 = new QVBoxLayout(this);
|
||||
layout1->setMargin(0);
|
||||
|
||||
// HBOX
|
||||
{
|
||||
QHBoxLayout *layout2 = new QHBoxLayout(this);
|
||||
layout2->setMargin(6);
|
||||
|
||||
// SEARCH INPUT
|
||||
{
|
||||
this->searchInput_ = new QLineEdit(this);
|
||||
layout2->addWidget(this->searchInput_);
|
||||
QObject::connect(this->searchInput_, &QLineEdit::returnPressed,
|
||||
[this] { this->performSearch(); });
|
||||
}
|
||||
|
||||
// SEARCH BUTTON
|
||||
{
|
||||
QPushButton *searchButton = new QPushButton(this);
|
||||
searchButton->setText("Search");
|
||||
layout2->addWidget(searchButton);
|
||||
QObject::connect(searchButton, &QPushButton::clicked,
|
||||
[this] { this->performSearch(); });
|
||||
}
|
||||
|
||||
layout1->addLayout(layout2);
|
||||
}
|
||||
|
||||
// CHANNELVIEW
|
||||
{
|
||||
this->channelView_ = new ChannelView(this);
|
||||
|
||||
layout1->addWidget(this->channelView_);
|
||||
}
|
||||
|
||||
this->setLayout(layout1);
|
||||
}
|
||||
}
|
||||
|
||||
void SearchPopup::performSearch()
|
||||
{
|
||||
QString text = searchInput_->text();
|
||||
|
||||
ChannelPtr channel(new Channel(this->channelName_, Channel::Type::None));
|
||||
|
||||
for (size_t i = 0; i < this->snapshot_.size(); i++)
|
||||
{
|
||||
MessagePtr message = this->snapshot_[i];
|
||||
|
||||
if (text.isEmpty() ||
|
||||
message->searchText.indexOf(this->searchInput_->text(), 0,
|
||||
Qt::CaseInsensitive) != -1)
|
||||
{
|
||||
channel->addMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
this->channelView_->setChannel(channel);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "SearchPopup.hpp"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "messages/search/AuthorPredicate.hpp"
|
||||
#include "messages/search/LinkPredicate.hpp"
|
||||
#include "messages/search/SubstringPredicate.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
ChannelPtr SearchPopup::filter(const QString &text, const QString &channelName,
|
||||
const LimitedQueueSnapshot<MessagePtr> &snapshot)
|
||||
{
|
||||
ChannelPtr channel(new Channel(channelName, Channel::Type::None));
|
||||
|
||||
// Parse predicates from tags in "text"
|
||||
auto predicates = parsePredicates(text);
|
||||
|
||||
// Check for every message whether it fulfills all predicates that have
|
||||
// been registered
|
||||
for (size_t i = 0; i < snapshot.size(); ++i)
|
||||
{
|
||||
MessagePtr message = snapshot[i];
|
||||
|
||||
bool accept = true;
|
||||
for (const auto &pred : predicates)
|
||||
{
|
||||
// Discard the message as soon as one predicate fails
|
||||
if (!pred->appliesTo(*message))
|
||||
{
|
||||
accept = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If all predicates match, add the message to the channel
|
||||
if (accept)
|
||||
channel->addMessage(message);
|
||||
}
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
SearchPopup::SearchPopup()
|
||||
{
|
||||
this->initLayout();
|
||||
this->resize(400, 600);
|
||||
}
|
||||
|
||||
void SearchPopup::setChannel(const ChannelPtr &channel)
|
||||
{
|
||||
this->channelName_ = channel->getName();
|
||||
this->snapshot_ = channel->getMessageSnapshot();
|
||||
this->search();
|
||||
|
||||
this->updateWindowTitle();
|
||||
}
|
||||
|
||||
void SearchPopup::updateWindowTitle()
|
||||
{
|
||||
this->setWindowTitle("Searching in " + this->channelName_ + "s history");
|
||||
}
|
||||
|
||||
void SearchPopup::search()
|
||||
{
|
||||
this->channelView_->setChannel(filter(this->searchInput_->text(),
|
||||
this->channelName_, this->snapshot_));
|
||||
}
|
||||
|
||||
void SearchPopup::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
if (e->key() == Qt::Key_Escape)
|
||||
{
|
||||
this->close();
|
||||
return;
|
||||
}
|
||||
|
||||
BaseWidget::keyPressEvent(e);
|
||||
}
|
||||
|
||||
void SearchPopup::initLayout()
|
||||
{
|
||||
// VBOX
|
||||
{
|
||||
QVBoxLayout *layout1 = new QVBoxLayout(this);
|
||||
layout1->setMargin(0);
|
||||
layout1->setSpacing(0);
|
||||
|
||||
// HBOX
|
||||
{
|
||||
QHBoxLayout *layout2 = new QHBoxLayout(this);
|
||||
layout2->setMargin(8);
|
||||
layout2->setSpacing(8);
|
||||
|
||||
// SEARCH INPUT
|
||||
{
|
||||
this->searchInput_ = new QLineEdit(this);
|
||||
layout2->addWidget(this->searchInput_);
|
||||
QObject::connect(this->searchInput_, &QLineEdit::returnPressed,
|
||||
[this] { this->search(); });
|
||||
}
|
||||
|
||||
// SEARCH BUTTON
|
||||
{
|
||||
QPushButton *searchButton = new QPushButton(this);
|
||||
searchButton->setText("Search");
|
||||
layout2->addWidget(searchButton);
|
||||
QObject::connect(searchButton, &QPushButton::clicked,
|
||||
[this] { this->search(); });
|
||||
}
|
||||
|
||||
layout1->addLayout(layout2);
|
||||
}
|
||||
|
||||
// CHANNELVIEW
|
||||
{
|
||||
this->channelView_ = new ChannelView(this);
|
||||
|
||||
layout1->addWidget(this->channelView_);
|
||||
}
|
||||
|
||||
this->setLayout(layout1);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<MessagePredicate>> SearchPopup::parsePredicates(
|
||||
const QString &input)
|
||||
{
|
||||
static QRegularExpression predicateRegex(R"(^(\w+):([\w,]+)$)");
|
||||
|
||||
auto predicates = std::vector<std::unique_ptr<MessagePredicate>>();
|
||||
auto words = input.split(' ', QString::SkipEmptyParts);
|
||||
auto authors = QStringList();
|
||||
|
||||
for (auto it = words.begin(); it != words.end();)
|
||||
{
|
||||
if (auto match = predicateRegex.match(*it); match.hasMatch())
|
||||
{
|
||||
QString name = match.captured(1);
|
||||
QString value = match.captured(2);
|
||||
|
||||
bool remove = true;
|
||||
|
||||
// match predicates
|
||||
if (name == "from")
|
||||
{
|
||||
authors.append(value);
|
||||
}
|
||||
else if (name == "has" && value == "link")
|
||||
{
|
||||
predicates.push_back(std::make_unique<LinkPredicate>());
|
||||
}
|
||||
else
|
||||
{
|
||||
remove = false;
|
||||
}
|
||||
|
||||
// remove or advance
|
||||
it = remove ? words.erase(it) : ++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (!authors.empty())
|
||||
predicates.push_back(std::make_unique<AuthorPredicate>(authors));
|
||||
|
||||
if (!words.empty())
|
||||
predicates.push_back(
|
||||
std::make_unique<SubstringPredicate>(words.join(" ")));
|
||||
|
||||
return predicates;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,38 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "messages/LimitedQueueSnapshot.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Channel;
|
||||
class ChannelView;
|
||||
|
||||
struct Message;
|
||||
using MessagePtr = std::shared_ptr<const Message>;
|
||||
|
||||
class SearchPopup : public BaseWindow
|
||||
{
|
||||
public:
|
||||
SearchPopup();
|
||||
|
||||
void setChannel(std::shared_ptr<Channel> channel);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
void initLayout();
|
||||
void performSearch();
|
||||
|
||||
LimitedQueueSnapshot<MessagePtr> snapshot_;
|
||||
QLineEdit *searchInput_;
|
||||
ChannelView *channelView_;
|
||||
QString channelName_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include "ForwardDecl.hpp"
|
||||
#include "messages/LimitedQueueSnapshot.hpp"
|
||||
#include "messages/search/MessagePredicate.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class SearchPopup : public BaseWindow
|
||||
{
|
||||
public:
|
||||
SearchPopup();
|
||||
|
||||
virtual void setChannel(const ChannelPtr &channel);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
virtual void updateWindowTitle();
|
||||
|
||||
private:
|
||||
void initLayout();
|
||||
void search();
|
||||
|
||||
/**
|
||||
* @brief Only retains those message from a list of messages that satisfy a
|
||||
* search query.
|
||||
*
|
||||
* @param text the search query -- will be parsed for MessagePredicates
|
||||
* @param channelName name of the channel to be returned
|
||||
* @param snapshot list of messages to filter
|
||||
*
|
||||
* @return a ChannelPtr with "channelName" and the filtered messages from
|
||||
* "snapshot"
|
||||
*/
|
||||
static ChannelPtr filter(const QString &text, const QString &channelName,
|
||||
const LimitedQueueSnapshot<MessagePtr> &snapshot);
|
||||
|
||||
/**
|
||||
* @brief Checks the input for tags and registers their corresponding
|
||||
* predicates.
|
||||
*
|
||||
* @param input the string to check for tags
|
||||
* @return a vector of MessagePredicates requested in the input
|
||||
*/
|
||||
static std::vector<std::unique_ptr<MessagePredicate>> parsePredicates(
|
||||
const QString &input);
|
||||
|
||||
LimitedQueueSnapshot<MessagePtr> snapshot_;
|
||||
QLineEdit *searchInput_{};
|
||||
ChannelView *channelView_{};
|
||||
QString channelName_{};
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
Reference in New Issue
Block a user