Merge branch 'dragdetails' into 'master'

[OpenMW-CS] Generate record filters based on cell content and column header

Closes #7161

See merge request OpenMW/openmw!2617
7220-lua-add-a-general-purpose-lexical-parser
psi29a 2 years ago
commit 3f9cae7947

@ -452,6 +452,7 @@
Feature #6024: OpenMW-CS: Selecting terrain in "Terrain land editing" should support "Add to selection" and "Remove from selection" modes
Feature #6033: Include pathgrid to navigation mesh
Feature #6034: Find path based on area cost depending on NPC stats
Feature #7161: OpenMW-CS: Make adding and filtering TopicInfos easier
Task #5480: Drop Qt4 support
Task #5520: Improve cell name autocompleter implementation

@ -4,6 +4,7 @@
#include <string>
#include <vector>
#include <QModelIndex>
#include <QStringList>
#include <QtCore/QMimeData>
@ -15,6 +16,11 @@ namespace CSMDoc
class Document;
}
namespace CSVWorld
{
class DragRecordTable;
}
namespace CSMWorld
{
@ -30,6 +36,8 @@ namespace CSMWorld
std::vector<UniversalId> mUniversalId;
QStringList mObjectsFormats;
const CSMDoc::Document& mDocument;
const CSVWorld::DragRecordTable* mTableOfDragStart;
QModelIndex mIndexAtDragStart;
public:
TableMimeData(UniversalId id, const CSMDoc::Document& document);
@ -56,6 +64,14 @@ namespace CSMWorld
UniversalId returnMatching(CSMWorld::ColumnBase::Display type) const;
void setIndexAtDragStart(const QModelIndex& index) { mIndexAtDragStart = index; }
void setTableOfDragStart(const CSVWorld::DragRecordTable* const table) { mTableOfDragStart = table; }
const QModelIndex getIndexAtDragStart() const { return mIndexAtDragStart; }
const CSVWorld::DragRecordTable* getTableOfDragStart() const { return mTableOfDragStart; }
static CSMWorld::UniversalId::Type convertEnums(CSMWorld::ColumnBase::Display type);
static CSMWorld::ColumnBase::Display convertEnums(CSMWorld::UniversalId::Type type);

@ -1,6 +1,7 @@
#include "editwidget.hpp"
#include <sstream>
#include <variant>
#include <QAction>
#include <QApplication>
@ -8,10 +9,14 @@
#include <QMenu>
#include <QRegularExpression>
#include <QString>
#include <QVariant>
#include "filterdata.hpp"
#include <apps/opencs/model/filter/parser.hpp>
#include <apps/opencs/model/world/universalid.hpp>
#include <components/debug/debuglog.hpp>
#include <components/misc/helpviewer.hpp>
#include "../../model/prefs/shortcut.hpp"
@ -93,10 +98,24 @@ void CSVFilter::EditWidget::filterRowsInserted(const QModelIndex& parent, int st
textChanged(text());
}
void CSVFilter::EditWidget::createFilterRequest(
std::vector<std::pair<std::string, std::vector<std::string>>>& filterSource, Qt::DropAction action)
void CSVFilter::EditWidget::createFilterRequest(const std::vector<FilterData>& sourceFilter, Qt::DropAction action)
{
const unsigned count = filterSource.size();
FilterType filterType = FilterType::String;
std::vector<FilterData> newFilter;
for (auto filterData : sourceFilter)
{
FilterData newFilterData;
std::pair<std::string, FilterType> pair = std::visit(FilterVisitor(), filterData.searchData);
std::string searchString = pair.first;
filterType = pair.second;
std::vector<std::string> columns;
newFilterData.searchData = searchString;
newFilterData.columns = filterData.columns;
newFilter.emplace_back(newFilterData);
}
const unsigned count = newFilter.size();
bool multipleElements = false;
switch (count) // setting multipleElements;
@ -164,7 +183,7 @@ void CSVFilter::EditWidget::createFilterRequest(
for (unsigned i = 0; i < count; ++i)
{
ss << generateFilter(filterSource[i]);
ss << generateFilter(newFilter[i], filterType);
if (i + 1 != count)
{
@ -185,7 +204,7 @@ void CSVFilter::EditWidget::createFilterRequest(
ss << '!';
}
ss << generateFilter(filterSource[0]);
ss << generateFilter(newFilter[0], filterType);
if (!replaceMode)
{
@ -200,9 +219,9 @@ void CSVFilter::EditWidget::createFilterRequest(
}
}
std::string CSVFilter::EditWidget::generateFilter(std::pair<std::string, std::vector<std::string>>& seekedString) const
std::string CSVFilter::EditWidget::generateFilter(const FilterData& filterData, const FilterType& filterType) const
{
const unsigned columns = seekedString.second.size();
const unsigned columns = filterData.columns.size();
bool multipleColumns = false;
switch (columns)
@ -219,13 +238,26 @@ std::string CSVFilter::EditWidget::generateFilter(std::pair<std::string, std::ve
break;
}
std::string quotesResolved;
if (std::get_if<std::string>(&filterData.searchData))
quotesResolved = std::get<std::string>(filterData.searchData);
else
{
Log(Debug::Warning) << "Generating record filter failed.";
return "";
}
if (filterType == FilterType::String)
quotesResolved = '"' + quotesResolved + '"';
std::stringstream ss;
if (multipleColumns)
{
ss << "or(";
for (unsigned i = 0; i < columns; ++i)
{
ss << "string(" << '"' << seekedString.second[i] << '"' << ',' << '"' << seekedString.first << '"' << ')';
ss << filterTypeName(filterType) << "(" << '"' << filterData.columns[i] << '"' << ',' << quotesResolved
<< ')';
if (i + 1 != columns)
ss << ',';
}
@ -233,7 +265,7 @@ std::string CSVFilter::EditWidget::generateFilter(std::pair<std::string, std::ve
}
else
{
ss << "string" << '(' << '"' << seekedString.second[0] << "\"," << '"' << seekedString.first << "\")";
ss << filterTypeName(filterType) << '(' << '"' << filterData.columns[0] << "\"," << quotesResolved << ")";
}
return ss.str();

@ -3,12 +3,16 @@
#include <QLineEdit>
#include <QPalette>
#include <QVariant>
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include "filterdata.hpp"
#include "../../model/filter/parser.hpp"
class QModelIndex;
@ -29,6 +33,32 @@ namespace CSMWorld
namespace CSVFilter
{
enum class FilterType
{
String,
Value
};
struct FilterVisitor
{
std::pair<std::string, FilterType> operator()(const std::string& stringData)
{
FilterType filterType = FilterType::String;
return std::make_pair(stringData, filterType);
}
std::pair<std::string, FilterType> operator()(const QVariant& variantData)
{
FilterType filterType = FilterType::String;
QMetaType::Type dataType = static_cast<QMetaType::Type>(variantData.type());
if (dataType == QMetaType::QString || dataType == QMetaType::Bool || dataType == QMetaType::Int)
filterType = FilterType::String;
if (dataType == QMetaType::Int || dataType == QMetaType::Float)
filterType = FilterType::Value;
return std::make_pair(variantData.toString().toStdString(), filterType);
}
};
class EditWidget : public QLineEdit
{
Q_OBJECT
@ -43,17 +73,29 @@ namespace CSVFilter
public:
EditWidget(CSMWorld::Data& data, QWidget* parent = nullptr);
void createFilterRequest(
std::vector<std::pair<std::string, std::vector<std::string>>>& filterSource, Qt::DropAction action);
void createFilterRequest(const std::vector<FilterData>& sourceFilter, Qt::DropAction action);
signals:
void filterChanged(std::shared_ptr<CSMFilter::Node> filter);
private:
std::string generateFilter(std::pair<std::string, std::vector<std::string>>& seekedString) const;
std::string generateFilter(const FilterData& filterData, const FilterType& filterType) const;
void contextMenuEvent(QContextMenuEvent* event) override;
constexpr std::string_view filterTypeName(const FilterType& type) const
{
switch (type)
{
case FilterType::String:
return "string";
case FilterType::Value:
return "value";
}
return "unknown type";
}
private slots:
void textChanged(const QString& text);

@ -2,15 +2,19 @@
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include <QDragEnterEvent>
#include <QHBoxLayout>
#include <QVariant>
#include "filterdata.hpp"
#include "recordfilterbox.hpp"
#include <apps/opencs/model/world/tablemimedata.hpp>
#include <apps/opencs/model/world/universalid.hpp>
#include <apps/opencs/view/world/dragrecordtable.hpp>
CSVFilter::FilterBox::FilterBox(CSMWorld::Data& data, QWidget* parent)
: QWidget(parent)
@ -42,8 +46,18 @@ void CSVFilter::FilterBox::dropEvent(QDropEvent* event)
return;
std::vector<CSMWorld::UniversalId> universalIdData = mime->getData();
emit recordDropped(universalIdData, event->proposedAction());
QModelIndex index = mime->getIndexAtDragStart();
const CSVWorld::DragRecordTable* dragTable = mime->getTableOfDragStart();
QVariant qData;
std::string searchColumn;
if (index.isValid() && dragTable)
{
qData = dragTable->model()->data(index);
searchColumn = dragTable->model()->headerData(index.column(), Qt::Horizontal).toString().toStdString();
}
emit recordDropped(universalIdData, std::make_pair(qData, searchColumn), event->proposedAction());
}
void CSVFilter::FilterBox::dragEnterEvent(QDragEnterEvent* event)
@ -56,8 +70,7 @@ void CSVFilter::FilterBox::dragMoveEvent(QDragMoveEvent* event)
event->accept();
}
void CSVFilter::FilterBox::createFilterRequest(
std::vector<std::pair<std::string, std::vector<std::string>>>& filterSource, Qt::DropAction action)
void CSVFilter::FilterBox::createFilterRequest(const std::vector<FilterData>& sourceFilter, Qt::DropAction action)
{
mRecordFilterBox->createFilterRequest(filterSource, action);
mRecordFilterBox->createFilterRequest(sourceFilter, action);
}

@ -4,10 +4,14 @@
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include <QVariant>
#include <QWidget>
#include "filterdata.hpp"
class QDragEnterEvent;
class QDragMoveEvent;
class QDropEvent;
@ -38,8 +42,7 @@ namespace CSVFilter
void setRecordFilter(const std::string& filter);
void createFilterRequest(
std::vector<std::pair<std::string, std::vector<std::string>>>& filterSource, Qt::DropAction action);
void createFilterRequest(const std::vector<FilterData>& sourceFilter, Qt::DropAction action);
private:
void dragEnterEvent(QDragEnterEvent* event) override;
@ -50,7 +53,8 @@ namespace CSVFilter
signals:
void recordFilterChanged(std::shared_ptr<CSMFilter::Node> filter);
void recordDropped(std::vector<CSMWorld::UniversalId>& types, Qt::DropAction action);
void recordDropped(std::vector<CSMWorld::UniversalId>& types,
const std::pair<QVariant, std::string>& columnSearchData, Qt::DropAction action);
};
}

@ -0,0 +1,19 @@
#ifndef CSV_FILTER_FILTERDATA_H
#define CSV_FILTER_FILTERDATA_H
#include <string>
#include <variant>
#include <vector>
#include <QVariant>
namespace CSVFilter
{
struct FilterData
{
std::variant<std::string, QVariant> searchData;
std::vector<std::string> columns;
};
}
#endif

@ -1,9 +1,13 @@
#include "recordfilterbox.hpp"
#include <variant>
#include <QHBoxLayout>
#include <QLabel>
#include <QVariant>
#include "editwidget.hpp"
#include "filterdata.hpp"
CSVFilter::RecordFilterBox::RecordFilterBox(CSMWorld::Data& data, QWidget* parent)
: QWidget(parent)
@ -31,8 +35,7 @@ void CSVFilter::RecordFilterBox::setFilter(const std::string& filter)
mEdit->setText(QString::fromUtf8(filter.c_str()));
}
void CSVFilter::RecordFilterBox::createFilterRequest(
std::vector<std::pair<std::string, std::vector<std::string>>>& filterSource, Qt::DropAction action)
void CSVFilter::RecordFilterBox::createFilterRequest(const std::vector<FilterData>& sourceFilter, Qt::DropAction action)
{
mEdit->createFilterRequest(filterSource, action);
mEdit->createFilterRequest(sourceFilter, action);
}

@ -4,10 +4,14 @@
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include <QVariant>
#include <QWidget>
#include "filterdata.hpp"
namespace CSMFilter
{
class Node;
@ -35,8 +39,7 @@ namespace CSVFilter
void useFilterRequest(const std::string& idOfFilter);
void createFilterRequest(
std::vector<std::pair<std::string, std::vector<std::string>>>& filterSource, Qt::DropAction action);
void createFilterRequest(const std::vector<FilterData>& sourceFilter, Qt::DropAction action);
signals:

@ -93,7 +93,7 @@ void CSVTools::ReportTable::contextMenuEvent(QContextMenuEvent* event)
void CSVTools::ReportTable::mouseMoveEvent(QMouseEvent* event)
{
if (event->buttons() & Qt::LeftButton)
startDragFromTable(*this);
startDragFromTable(*this, indexAt(event->pos()));
}
void CSVTools::ReportTable::mouseDoubleClickEvent(QMouseEvent* event)

@ -16,7 +16,7 @@
#include "dragdroputils.hpp"
void CSVWorld::DragRecordTable::startDragFromTable(const CSVWorld::DragRecordTable& table)
void CSVWorld::DragRecordTable::startDragFromTable(const CSVWorld::DragRecordTable& table, const QModelIndex& index)
{
std::vector<CSMWorld::UniversalId> records = table.getDraggedRecords();
if (records.empty())
@ -25,6 +25,8 @@ void CSVWorld::DragRecordTable::startDragFromTable(const CSVWorld::DragRecordTab
}
CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData(records, mDocument);
mime->setTableOfDragStart(&table);
mime->setIndexAtDragStart(index);
QDrag* drag = new QDrag(this);
drag->setMimeData(mime);
drag->setPixmap(QString::fromUtf8(mime->getIcon().c_str()));

@ -42,7 +42,7 @@ namespace CSVWorld
void setEditLock(bool locked);
protected:
void startDragFromTable(const DragRecordTable& table);
void startDragFromTable(const DragRecordTable& table, const QModelIndex& index);
void dragEnterEvent(QDragEnterEvent* event) override;

@ -338,7 +338,7 @@ void CSVWorld::RegionMap::viewInTable()
void CSVWorld::RegionMap::mouseMoveEvent(QMouseEvent* event)
{
startDragFromTable(*this);
startDragFromTable(*this, indexAt(event->pos()));
}
std::vector<CSMWorld::UniversalId> CSVWorld::RegionMap::getDraggedRecords() const

@ -871,7 +871,7 @@ void CSVWorld::Table::mouseMoveEvent(QMouseEvent* event)
{
if (event->buttons() & Qt::LeftButton)
{
startDragFromTable(*this);
startDragFromTable(*this, indexAt(event->pos()));
}
}

@ -9,9 +9,11 @@
#include <QPushButton>
#include <QScreen>
#include <QVBoxLayout>
#include <QVariant>
#include <algorithm>
#include <utility>
#include <variant>
#include <apps/opencs/view/doc/subview.hpp>
@ -20,6 +22,7 @@
#include "../doc/sizehint.hpp"
#include "../filter/filterbox.hpp"
#include "../filter/filterdata.hpp"
#include "table.hpp"
#include "tablebottombox.hpp"
@ -150,10 +153,10 @@ void CSVWorld::TableSubView::cloneRequest(const CSMWorld::UniversalId& toClone)
emit cloneRequest(toClone.getId(), toClone.getType());
}
void CSVWorld::TableSubView::createFilterRequest(std::vector<CSMWorld::UniversalId>& types, Qt::DropAction action)
void CSVWorld::TableSubView::createFilterRequest(std::vector<CSMWorld::UniversalId>& types,
const std::pair<QVariant, std::string>& columnSearchData, Qt::DropAction action)
{
std::vector<std::pair<std::string, std::vector<std::string>>> filterSource;
std::vector<CSVFilter::FilterData> sourceFilter;
std::vector<std::string> refIdColumns = mTable->getColumnsWithDisplay(
CSMWorld::TableMimeData::convertEnums(CSMWorld::UniversalId::Type_Referenceable));
bool hasRefIdDisplay = !refIdColumns.empty();
@ -164,16 +167,40 @@ void CSVWorld::TableSubView::createFilterRequest(std::vector<CSMWorld::Universal
std::vector<std::string> col = mTable->getColumnsWithDisplay(CSMWorld::TableMimeData::convertEnums(type));
if (!col.empty())
{
filterSource.emplace_back(it->getId(), col);
CSVFilter::FilterData filterData;
filterData.searchData = it->getId();
filterData.columns = col;
sourceFilter.emplace_back(filterData);
}
if (hasRefIdDisplay && CSMWorld::TableMimeData::isReferencable(type))
{
filterSource.emplace_back(it->getId(), refIdColumns);
CSVFilter::FilterData filterData;
filterData.searchData = it->getId();
filterData.columns = refIdColumns;
sourceFilter.emplace_back(filterData);
}
}
mFilterBox->createFilterRequest(filterSource, action);
if (!sourceFilter.empty())
mFilterBox->createFilterRequest(sourceFilter, action);
else
{
std::vector<CSVFilter::FilterData> sourceFilterByValue;
QVariant qData = columnSearchData.first;
std::string searchColumn = columnSearchData.second;
std::vector<std::string> searchColumns;
searchColumns.emplace_back(searchColumn);
CSVFilter::FilterData filterData;
filterData.searchData = qData;
filterData.columns = searchColumns;
sourceFilterByValue.emplace_back(filterData);
mFilterBox->createFilterRequest(sourceFilterByValue, action);
}
}
bool CSVWorld::TableSubView::eventFilter(QObject* object, QEvent* event)

@ -4,6 +4,7 @@
#include "../doc/subview.hpp"
#include <QModelIndex>
#include <QVariant>
#include <QWidget>
#include <string>
@ -61,7 +62,8 @@ namespace CSVWorld
void editRequest(const CSMWorld::UniversalId& id, const std::string& hint);
void cloneRequest(const CSMWorld::UniversalId& toClone);
void createFilterRequest(std::vector<CSMWorld::UniversalId>& types, Qt::DropAction action);
void createFilterRequest(std::vector<CSMWorld::UniversalId>& types,
const std::pair<QVariant, std::string>& columnSearchData, Qt::DropAction action);
void toggleOptions();
public slots:

Loading…
Cancel
Save