Add saving of filters

* The current filter is preserved across runs even if it's not explicitly saved.
  Saved filters are only updated with an explicit save - loading a filter then
  making a change just cahnges the current scratch filter, it doesn't update the
  saved filter until the user explicitly saves it.
This commit is contained in:
baldurk
2021-06-09 15:43:58 +01:00
parent c5457a141b
commit ca3e3afa66
4 changed files with 323 additions and 3 deletions
@@ -163,6 +163,18 @@ struct LegacyData
QVariantMap _ConfigSettings;
};
static rdcarray<rdcpair<rdcstr, CustomPersistentStorage *>> &GetCustomStorage()
{
static rdcarray<rdcpair<rdcstr, CustomPersistentStorage *>> ret;
return ret;
}
CustomPersistentStorage::CustomPersistentStorage(rdcstr name)
{
if(!name.empty())
GetCustomStorage().push_back({name, this});
}
QVariantMap PersistantConfig::storeValues() const
{
QVariantMap ret;
@@ -186,6 +198,11 @@ QVariantMap PersistantConfig::storeValues() const
ret[lit("ShaderViewer_FriendlyNaming")] = m_Legacy->_ShaderViewer_FriendlyNaming;
ret[lit("ConfigSettings")] = m_Legacy->_ConfigSettings;
for(const rdcpair<rdcstr, CustomPersistentStorage *> &ps : GetCustomStorage())
{
ps.second->save(ret[QString(ps.first)]);
}
return ret;
}
@@ -295,6 +312,9 @@ void PersistantConfig::applyValues(const QVariantMap &values)
if(saveConfig)
RENDERDOC_SaveConfigSettings();
for(const rdcpair<rdcstr, CustomPersistentStorage *> &ps : GetCustomStorage())
ps.second->load(values[QString(ps.first)]);
}
static QMutex RemoteHostLock;
@@ -702,6 +702,19 @@ void RemoveRecentFile(rdcarray<rdcstr> &recentList, const rdcstr &file);
struct LegacyData;
#if !defined(SWIG)
class QVariant;
// not exposed to swig - allow windows to have completely custom persistent storage that aren't
// "settings".
struct CustomPersistentStorage
{
CustomPersistentStorage(rdcstr name);
virtual void save(QVariant &v) const = 0;
virtual void load(const QVariant &v) = 0;
};
#endif
DOCUMENT(R"(A persistant config file that is automatically loaded and saved, which contains any
settings and information that needs to be preserved from one run to the next.
+282 -3
View File
@@ -26,10 +26,12 @@
#include <QAbstractItemModel>
#include <QAbstractSpinBox>
#include <QComboBox>
#include <QCompleter>
#include <QDialogButtonBox>
#include <QKeyEvent>
#include <QLineEdit>
#include <QMenu>
#include <QPushButton>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QScrollBar>
@@ -50,6 +52,59 @@
#include "scintilla/include/qt/ScintillaEdit.h"
#include "ui_EventBrowser.h"
struct EventBrowserPersistentStorage : public CustomPersistentStorage
{
EventBrowserPersistentStorage() : CustomPersistentStorage(rdcstr()) {}
EventBrowserPersistentStorage(rdcstr name) : CustomPersistentStorage(name) {}
void save(QVariant &v) const
{
QVariantMap settings;
settings[lit("current")] = CurrentFilter;
QVariantList filters;
for(const QPair<QString, QString> &f : SavedFilters)
filters << QVariant(QVariantList({f.first, f.second}));
settings[lit("filters")] = filters;
v = settings;
}
void load(const QVariant &v)
{
QVariantMap settings = v.toMap();
QVariant current = settings[lit("current")];
if(current.isValid() && current.type() == QVariant::String)
CurrentFilter = current.toString();
QVariant saved = settings[lit("filters")];
if(saved.isValid() && saved.type() == QVariant::List)
{
QVariantList filters = saved.toList();
for(QVariant filter : filters)
{
QVariantList filterPair = filter.toList();
if(filterPair.count() == 2 && filterPair[0].type() == QVariant::String &&
filterPair[1].type() == QVariant::String)
{
QString name = filterPair[0].toString();
QString expr = filterPair[1].toString();
if(!name.isEmpty())
SavedFilters.push_back({name, expr});
}
}
}
}
QString CurrentFilter = lit("$draw()");
QList<QPair<QString, QString>> SavedFilters;
};
static EventBrowserPersistentStorage persistantStorage("EventBrowser");
enum
{
COL_NAME,
@@ -3084,8 +3139,34 @@ EventBrowser::EventBrowser(ICaptureContext &ctx, QWidget *parent)
ui->filterExpression->enableCompletion();
ui->filterExpression->setAcceptRichText(false);
// set default filter, include only draws that aren't pop markers
ui->filterExpression->setText(lit("$draw()"));
ui->filterExpression->setText(persistantStorage.CurrentFilter);
m_SavedCompleter = new QCompleter(this);
m_SavedCompleter->setWidget(ui->filterExpression);
m_SavedCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
m_SavedCompleter->setWrapAround(false);
m_SavedCompletionModel = new QStringListModel(this);
m_SavedCompleter->setModel(m_SavedCompletionModel);
m_SavedCompleter->setCompletionRole(Qt::DisplayRole);
QObject::connect(m_SavedCompleter, OverloadedSlot<const QModelIndex &>::of(&QCompleter::activated),
[this](const QModelIndex &idx) {
int i = idx.row();
if(i >= 0 && i < persistantStorage.SavedFilters.count())
{
m_CurrentFilterText->setPlainText(persistantStorage.SavedFilters[i].second);
QTextCursor c = m_CurrentFilterText->textCursor();
c.movePosition(QTextCursor::EndOfLine);
m_CurrentFilterText->setTextCursor(c);
}
});
QObject::connect(ui->filterExpression, &RDTextEdit::keyPress, this,
&EventBrowser::savedFilter_keyPress);
QObject::connect(ui->recentFilters, &QToolButton::clicked,
[this]() { ShowSavedFilterCompleter(ui->filterExpression); });
QObject::connect(ui->filterSettings, &QToolButton::clicked, this,
&EventBrowser::filterSettings_clicked);
@@ -3317,7 +3398,7 @@ void EventBrowser::CreateFilterDialog()
m_FilterSettings.FuncList = new QListWidget(this);
m_FilterSettings.Explanation = new RDTreeWidget(this);
m_FilterSettings.Dialog->setWindowTitle(lit("Event Filter Configuration"));
m_FilterSettings.Dialog->setWindowTitle(tr("Event Filter Configuration"));
m_FilterSettings.Dialog->setWindowFlags(m_FilterSettings.Dialog->windowFlags() &
~Qt::WindowContextHelpButtonHint);
m_FilterSettings.Dialog->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
@@ -3376,6 +3457,151 @@ void EventBrowser::CreateFilterDialog()
QObject::connect(m_FilterSettings.Filter, &RDTextEdit::completionEnd, m_FilterSettings.Filter,
&RDTextEdit::textChanged);
QObject::connect(m_FilterSettings.Filter, &RDTextEdit::keyPress, this,
&EventBrowser::savedFilter_keyPress);
QObject::connect(recentFilters, &QToolButton::clicked,
[this]() { ShowSavedFilterCompleter(m_FilterSettings.Filter); });
QObject::connect(saveFilter, &QToolButton::clicked, [this]() {
QDialog *dialog = new QDialog(this);
dialog->setWindowTitle(tr("Save filters"));
dialog->setWindowFlags(dialog->windowFlags() & ~Qt::WindowContextHelpButtonHint);
dialog->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
RDLineEdit saveName;
saveName.setPlaceholderText(tr("Name of filter"));
RDListWidget filters;
for(const QPair<QString, QString> &f : persistantStorage.SavedFilters)
filters.addItem(f.first);
QPushButton saveButton;
saveButton.setText(tr("Save"));
saveButton.setIcon(Icons::save());
QPushButton deleteButton;
deleteButton.setText(tr("Delete"));
QDialogButtonBox saveDialogButtons;
saveDialogButtons.addButton(QDialogButtonBox::Ok);
QObject::connect(&saveDialogButtons, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
QGridLayout grid;
grid.addWidget(&saveName, 0, 0, 1, 1);
grid.addWidget(&saveButton, 0, 1, 1, 1);
grid.addWidget(&filters, 1, 0, 1, 1);
grid.addWidget(&deleteButton, 1, 1, 1, 1, Qt::AlignHCenter | Qt::AlignTop);
grid.addWidget(&saveDialogButtons, 2, 0, 1, 2);
dialog->setLayout(&grid);
auto enterCallback = [this, &saveButton, &deleteButton](QKeyEvent *e) {
if(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter)
{
saveButton.click();
e->accept();
}
if(e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete)
{
deleteButton.click();
e->accept();
}
};
QObject::connect(&saveName, &RDLineEdit::keyPress, enterCallback);
QObject::connect(&filters, &RDListWidget::keyPress, enterCallback);
QObject::connect(&filters, &RDListWidget::itemActivated,
[&saveButton](QListWidgetItem *) { saveButton.click(); });
QObject::connect(&saveName, &RDLineEdit::textChanged, [this, &saveName, &filters]() {
for(int i = 0; i < persistantStorage.SavedFilters.count(); i++)
{
if(saveName.text().trimmed().toLower() == persistantStorage.SavedFilters[i].first.toLower())
{
if(filters.currentRow() != i)
filters.setCurrentRow(i);
return;
}
}
filters.setCurrentItem(NULL);
});
QObject::connect(&filters, &QListWidget::currentRowChanged, [this, &saveName](int row) {
if(row >= 0 && row < persistantStorage.SavedFilters.count())
saveName.setText(persistantStorage.SavedFilters[row].first);
});
QObject::connect(&saveButton, &QPushButton::clicked, [this, dialog, &saveName, &filters]() {
QString n = saveName.text().trimmed();
QString f = m_FilterSettings.Filter->toPlainText();
for(int i = 0; i < persistantStorage.SavedFilters.count(); i++)
{
if(n.toLower() == persistantStorage.SavedFilters[i].first.toLower())
{
if(persistantStorage.SavedFilters[i].second.trimmed() == f.trimmed())
{
dialog->accept();
return;
}
QMessageBox::StandardButton res = RDDialog::question(
dialog, tr("Delete filter?"),
tr("Are you sure you want to overwrite the %1 filter? From:\n\n%2\n\nTo:\n\n%3")
.arg(persistantStorage.SavedFilters[i].first)
.arg(persistantStorage.SavedFilters[i].second)
.arg(f),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if(res != QMessageBox::Yes)
return;
delete filters.takeItem(i);
persistantStorage.SavedFilters.erase(persistantStorage.SavedFilters.begin() + i);
break;
}
}
persistantStorage.SavedFilters.insert(0, {n, f});
dialog->accept();
});
QObject::connect(&deleteButton, &QPushButton::clicked, [this, dialog, &filters]() {
QListWidgetItem *item = filters.currentItem();
if(!item)
return;
for(int i = 0; i < persistantStorage.SavedFilters.count(); i++)
{
if(item->text().trimmed().toLower() == persistantStorage.SavedFilters[i].first.toLower())
{
QMessageBox::StandardButton res =
RDDialog::question(dialog, tr("Delete filter?"),
tr("Are you sure you want to delete the %1 filter?\n\n%2")
.arg(persistantStorage.SavedFilters[i].first)
.arg(persistantStorage.SavedFilters[i].second),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if(res == QMessageBox::Yes)
{
delete filters.takeItem(i);
persistantStorage.SavedFilters.erase(persistantStorage.SavedFilters.begin() + i);
}
return;
}
}
});
RDDialog::show(dialog);
dialog->deleteLater();
});
recentFilters->setAutoRaise(true);
recentFilters->setIcon(Icons::filter_reapply());
recentFilters->setToolTip(tr("Load saved filters"));
@@ -3438,6 +3664,11 @@ void EventBrowser::CreateFilterDialog()
m_FilterSettings.Timeout->stop();
m_FilterSettings.Timeout->timeout({});
}
if(e->key() == Qt::Key_Down)
{
ShowSavedFilterCompleter(m_FilterSettings.Filter);
}
});
QObject::connect(m_FilterSettings.Explanation, &RDTreeWidget::currentItemChanged, this,
@@ -3683,6 +3914,7 @@ void EventBrowser::filter_apply()
ui->events->updateExpansion(m_EventsExpansion, keygen);
QString expression = ui->filterExpression->toPlainText();
persistantStorage.CurrentFilter = expression;
rdcarray<EventFilter> filters;
*m_ParseTrace = m_FilterModel->ParseExpressionToFilters(expression, filters);
@@ -3872,6 +4104,11 @@ void EventBrowser::on_filterExpression_keyPress(QKeyEvent *e)
filter_apply();
}
if(e->key() == Qt::Key_Down)
{
ShowSavedFilterCompleter(ui->filterExpression);
}
}
void EventBrowser::filter_forceCompletion_keyPress(QKeyEvent *e)
@@ -3911,6 +4148,48 @@ void EventBrowser::filter_forceCompletion_keyPress(QKeyEvent *e)
}
}
void EventBrowser::ShowSavedFilterCompleter(RDTextEdit *filter)
{
QStringList strs;
for(QPair<QString, QString> &f : persistantStorage.SavedFilters)
strs << f.first + lit(": ") + f.second;
m_SavedCompletionModel->setStringList(strs);
m_SavedCompleter->setWidget(filter);
QRect r = filter->rect();
m_SavedCompleter->complete(r);
m_CurrentFilterText = filter;
}
void EventBrowser::savedFilter_keyPress(QKeyEvent *e)
{
if(!m_SavedCompleter->popup()->isVisible())
return;
switch(e->key())
{
// if a completion is in progress ignore any events the completer will process
case Qt::Key_Return:
case Qt::Key_Enter:
m_SavedCompleter->activated(m_SavedCompleter->popup()->selectionModel()->currentIndex());
m_SavedCompleter->popup()->hide();
return;
// allow key scrolling
case Qt::Key_Up:
case Qt::Key_Down:
case Qt::Key_PageUp:
case Qt::Key_PageDown: return;
default: break;
}
// all other keys close the popup
m_SavedCompleter->popup()->hide();
}
void EventBrowser::on_filterExpression_textChanged()
{
if(!ui->filterExpression->completionInProgress())
+8
View File
@@ -47,6 +47,8 @@ class RDTreeWidgetItem;
class RDTextEdit;
class QListWidget;
class QCheckBox;
class QCompleter;
class QStringListModel;
typedef QSet<uint> RDTreeViewExpansionState;
@@ -167,6 +169,7 @@ private slots:
void settings_filterApply();
void filterSettings_clicked();
void filter_forceCompletion_keyPress(QKeyEvent *e);
void savedFilter_keyPress(QKeyEvent *e);
void filter_CompletionBegin(QString prefix);
void filter_apply();
void events_keyPress(QKeyEvent *event);
@@ -190,6 +193,7 @@ private:
int FindEvent(QString filter, uint32_t after, bool forward);
void Find(bool forward);
void ShowSavedFilterCompleter(RDTextEdit *filter);
void CreateFilterDialog();
void AddFilterExplanations(QString parentFunc, RDTreeWidgetItem *root,
@@ -237,6 +241,10 @@ private:
QTimer *Timeout;
} m_FilterSettings;
QCompleter *m_SavedCompleter;
QStringListModel *m_SavedCompletionModel;
RDTextEdit *m_CurrentFilterText;
void RefreshShaderMessages();
Ui::EventBrowser *ui;
ICaptureContext &m_Ctx;