mirror of https://github.com/OpenMW/openmw.git
added search class and search box widget
parent
413b35de6c
commit
78c6268891
@ -0,0 +1,213 @@
|
||||
|
||||
#include "search.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
#include "../../model/doc/messages.hpp"
|
||||
|
||||
#include "../../model/world/idtablebase.hpp"
|
||||
#include "../../model/world/columnbase.hpp"
|
||||
#include "../../model/world/universalid.hpp"
|
||||
|
||||
void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model,
|
||||
const QModelIndex& index, const CSMWorld::UniversalId& id, bool multiple,
|
||||
CSMDoc::Messages& messages) const
|
||||
{
|
||||
// using QString here for easier handling of case folding.
|
||||
|
||||
QString search = QString::fromUtf8 (mText.c_str());
|
||||
QString text = model->data (index).toString();
|
||||
|
||||
int pos = 0;
|
||||
|
||||
while ((pos = text.indexOf (search, pos, Qt::CaseInsensitive))!=-1)
|
||||
{
|
||||
std::ostringstream message;
|
||||
message << text.mid (pos).toUtf8().data();
|
||||
|
||||
std::ostringstream hint;
|
||||
message << "r: " << index.column() << " " << pos << " " << search.length();
|
||||
|
||||
messages.add (id, message.str(), hint.str());
|
||||
|
||||
if (!multiple)
|
||||
break;
|
||||
|
||||
pos += search.length();
|
||||
}
|
||||
}
|
||||
|
||||
void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model,
|
||||
const QModelIndex& index, const CSMWorld::UniversalId& id, bool multiple,
|
||||
CSMDoc::Messages& messages) const
|
||||
{
|
||||
QString text = model->data (index).toString();
|
||||
|
||||
int pos = 0;
|
||||
|
||||
while ((pos = mRegExp.indexIn (text, pos))!=-1)
|
||||
{
|
||||
std::ostringstream message;
|
||||
message << text.mid (pos).toUtf8().data();
|
||||
|
||||
int length = mRegExp.matchedLength();
|
||||
|
||||
std::ostringstream hint;
|
||||
message << "r: " << index.column() << " " << pos << " " << length;
|
||||
|
||||
messages.add (id, message.str(), hint.str());
|
||||
|
||||
if (!multiple)
|
||||
break;
|
||||
|
||||
pos += length;
|
||||
}
|
||||
}
|
||||
|
||||
void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model,
|
||||
const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const
|
||||
{
|
||||
int data = model->data (index).toInt();
|
||||
|
||||
if (data==mValue)
|
||||
{
|
||||
std::vector<std::string> states =
|
||||
CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification);
|
||||
|
||||
std::ostringstream message;
|
||||
message << id.getId() << " " << states.at (data);
|
||||
|
||||
std::ostringstream hint;
|
||||
message << "r: " << index.column();
|
||||
|
||||
messages.add (id, message.str(), hint.str());
|
||||
}
|
||||
}
|
||||
|
||||
CSMTools::Search::Search() : mType (Type_None) {}
|
||||
|
||||
CSMTools::Search::Search (Type type, const std::string& value)
|
||||
: mType (type), mText (value)
|
||||
{
|
||||
if (type!=Type_Text && type!=Type_Reference)
|
||||
throw std::logic_error ("Invalid search parameter (string)");
|
||||
}
|
||||
|
||||
CSMTools::Search::Search (Type type, const QRegExp& value)
|
||||
: mType (type), mRegExp (value)
|
||||
{
|
||||
if (type!=Type_TextRegEx && type!=Type_ReferenceRegEx)
|
||||
throw std::logic_error ("Invalid search parameter (RegExp)");
|
||||
}
|
||||
|
||||
CSMTools::Search::Search (Type type, int value)
|
||||
: mType (type), mValue (value)
|
||||
{
|
||||
if (type!=Type_RecordState)
|
||||
throw std::logic_error ("invalid search parameter (int)");
|
||||
}
|
||||
|
||||
void CSMTools::Search::configure (const CSMWorld::IdTableBase *model)
|
||||
{
|
||||
mColumns.clear();
|
||||
|
||||
int columns = model->columnCount();
|
||||
|
||||
for (int i=0; i<columns; ++i)
|
||||
{
|
||||
CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display> (
|
||||
model->headerData (
|
||||
i, Qt::Horizontal, static_cast<int> (CSMWorld::ColumnBase::Role_Display)).toInt());
|
||||
|
||||
bool consider = false;
|
||||
bool multiple = false;
|
||||
|
||||
switch (mType)
|
||||
{
|
||||
case Type_Text:
|
||||
case Type_TextRegEx:
|
||||
|
||||
if (CSMWorld::ColumnBase::isText (display) ||
|
||||
CSMWorld::ColumnBase::isScript (display))
|
||||
{
|
||||
consider = true;
|
||||
multiple = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Type_Reference:
|
||||
case Type_ReferenceRegEx:
|
||||
|
||||
if (CSMWorld::ColumnBase::isId (display))
|
||||
{
|
||||
consider = true;
|
||||
}
|
||||
else if (CSMWorld::ColumnBase::isScript (display))
|
||||
{
|
||||
consider = true;
|
||||
multiple = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Type_RecordState:
|
||||
|
||||
if (display==CSMWorld::ColumnBase::Display_RecordState)
|
||||
consider = true;
|
||||
|
||||
break;
|
||||
|
||||
case Type_None:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (consider)
|
||||
mColumns.insert (std::make_pair (i, multiple));
|
||||
}
|
||||
|
||||
mIdColumn = model->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
||||
mTypeColumn = model->findColumnIndex (CSMWorld::Columns::ColumnId_RecordType);
|
||||
}
|
||||
|
||||
void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row,
|
||||
CSMDoc::Messages& messages) const
|
||||
{
|
||||
for (std::map<int, bool>::const_iterator iter (mColumns.begin()); iter!=mColumns.end();
|
||||
++iter)
|
||||
{
|
||||
QModelIndex index = model->index (row, iter->first);
|
||||
|
||||
CSMWorld::UniversalId::Type type = static_cast<CSMWorld::UniversalId::Type> (
|
||||
model->data (model->index (row, mTypeColumn)).toInt());
|
||||
|
||||
CSMWorld::UniversalId id (
|
||||
type, model->data (model->index (row, mIdColumn)).toString().toUtf8().data());
|
||||
|
||||
switch (mType)
|
||||
{
|
||||
case Type_Text:
|
||||
case Type_Reference:
|
||||
|
||||
searchTextCell (model, index, id, iter->second, messages);
|
||||
break;
|
||||
|
||||
case Type_TextRegEx:
|
||||
case Type_ReferenceRegEx:
|
||||
|
||||
searchRegExCell (model, index, id, iter->second, messages);
|
||||
break;
|
||||
|
||||
case Type_RecordState:
|
||||
|
||||
searchRecordStateCell (model, index, id, messages);
|
||||
break;
|
||||
|
||||
case Type_None:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
#ifndef CSM_TOOLS_SEARCH_H
|
||||
#define CSM_TOOLS_SEARCH_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QMetaType>
|
||||
|
||||
class QModelIndex;
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Messages;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdTableBase;
|
||||
class UniversalId;
|
||||
}
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class Search
|
||||
{
|
||||
public:
|
||||
|
||||
enum Type
|
||||
{
|
||||
Type_Text = 0,
|
||||
Type_TextRegEx = 1,
|
||||
Type_Reference = 2,
|
||||
Type_ReferenceRegEx = 3,
|
||||
Type_RecordState = 4,
|
||||
Type_None
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Type mType;
|
||||
std::string mText;
|
||||
QRegExp mRegExp;
|
||||
int mValue;
|
||||
std::map<int, bool> mColumns; // column, multiple finds per cell
|
||||
int mIdColumn;
|
||||
int mTypeColumn;
|
||||
|
||||
void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index,
|
||||
const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const;
|
||||
|
||||
void searchRegExCell (const CSMWorld::IdTableBase *model, const QModelIndex& index,
|
||||
const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const;
|
||||
|
||||
void searchRecordStateCell (const CSMWorld::IdTableBase *model,
|
||||
const QModelIndex& index, const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Messages& messages) const;
|
||||
|
||||
public:
|
||||
|
||||
Search();
|
||||
|
||||
Search (Type type, const std::string& value);
|
||||
|
||||
Search (Type type, const QRegExp& value);
|
||||
|
||||
Search (Type type, int value);
|
||||
|
||||
// Configure search for the specified model.
|
||||
void configure (const CSMWorld::IdTableBase *model);
|
||||
|
||||
// Search row in \a model and store results in \a messages.
|
||||
//
|
||||
// \attention *this needs to be configured for \a model.
|
||||
void searchRow (const CSMWorld::IdTableBase *model, int row,
|
||||
CSMDoc::Messages& messages) const;
|
||||
};
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE (CSMTools::Search)
|
||||
|
||||
#endif
|
@ -0,0 +1,145 @@
|
||||
|
||||
#include "searchbox.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QComboBox>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "../../model/world/columns.hpp"
|
||||
|
||||
#include "../../model/tools/search.hpp"
|
||||
|
||||
void CSVTools::SearchBox::updateSearchButton()
|
||||
{
|
||||
if (!mSearchEnabled)
|
||||
mSearch.setEnabled (false);
|
||||
else
|
||||
{
|
||||
switch (mMode.currentIndex())
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
|
||||
mSearch.setEnabled (!mText.text().isEmpty());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
|
||||
mSearch.setEnabled (true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CSVTools::SearchBox::SearchBox (QWidget *parent)
|
||||
: QWidget (parent), mSearch ("Search"), mSearchEnabled (false)
|
||||
{
|
||||
std::vector<std::string> states =
|
||||
CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification);
|
||||
states.resize (states.size()-1); // ignore erased state
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (states.begin()); iter!=states.end();
|
||||
++iter)
|
||||
mRecordState.addItem (QString::fromUtf8 (iter->c_str()));
|
||||
|
||||
mLayout = new QGridLayout (this);
|
||||
|
||||
mMode.addItem ("Text");
|
||||
mMode.addItem ("Text (RegEx)");
|
||||
mMode.addItem ("Reference");
|
||||
mMode.addItem ("Reference (RegEx)");
|
||||
mMode.addItem ("Record State");
|
||||
|
||||
mLayout->addWidget (&mMode, 0, 0);
|
||||
|
||||
mLayout->addWidget (&mSearch, 0, 3);
|
||||
|
||||
mInput.insertWidget (0, &mText);
|
||||
mInput.insertWidget (1, &mRecordState);
|
||||
|
||||
mLayout->addWidget (&mInput, 0, 1);
|
||||
|
||||
mLayout->setColumnMinimumWidth (2, 50);
|
||||
mLayout->setColumnStretch (1, 1);
|
||||
|
||||
mLayout->setContentsMargins (0, 0, 0, 0);
|
||||
|
||||
connect (&mMode, SIGNAL (activated (int)), this, SLOT (modeSelected (int)));
|
||||
|
||||
connect (&mText, SIGNAL (textChanged (const QString&)),
|
||||
this, SLOT (textChanged (const QString&)));
|
||||
|
||||
connect (&mSearch, SIGNAL (clicked (bool)), this, SLOT (startSearch (bool)));
|
||||
|
||||
modeSelected (0);
|
||||
|
||||
updateSearchButton();
|
||||
}
|
||||
|
||||
void CSVTools::SearchBox::setSearchMode (bool enabled)
|
||||
{
|
||||
mSearchEnabled = enabled;
|
||||
updateSearchButton();
|
||||
}
|
||||
|
||||
CSMTools::Search CSVTools::SearchBox::getSearch() const
|
||||
{
|
||||
CSMTools::Search::Type type = static_cast<CSMTools::Search::Type> (mMode.currentIndex());
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CSMTools::Search::Type_Text:
|
||||
case CSMTools::Search::Type_Reference:
|
||||
|
||||
return CSMTools::Search (type, std::string (mText.text().toUtf8().data()));
|
||||
|
||||
case CSMTools::Search::Type_TextRegEx:
|
||||
case CSMTools::Search::Type_ReferenceRegEx:
|
||||
|
||||
return CSMTools::Search (type, QRegExp (mText.text().toUtf8().data(), Qt::CaseInsensitive));
|
||||
|
||||
case CSMTools::Search::Type_RecordState:
|
||||
|
||||
return CSMTools::Search (type, mRecordState.currentIndex());
|
||||
|
||||
case CSMTools::Search::Type_None:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
throw std::logic_error ("invalid search mode index");
|
||||
}
|
||||
|
||||
void CSVTools::SearchBox::modeSelected (int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case CSMTools::Search::Type_Text:
|
||||
case CSMTools::Search::Type_TextRegEx:
|
||||
case CSMTools::Search::Type_Reference:
|
||||
case CSMTools::Search::Type_ReferenceRegEx:
|
||||
|
||||
mInput.setCurrentIndex (0);
|
||||
break;
|
||||
|
||||
case CSMTools::Search::Type_RecordState:
|
||||
mInput.setCurrentIndex (1);
|
||||
break;
|
||||
}
|
||||
|
||||
updateSearchButton();
|
||||
}
|
||||
|
||||
void CSVTools::SearchBox::textChanged (const QString& text)
|
||||
{
|
||||
updateSearchButton();
|
||||
}
|
||||
|
||||
void CSVTools::SearchBox::startSearch (bool checked)
|
||||
{
|
||||
emit startSearch (getSearch());
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
#ifndef CSV_TOOLS_SEARCHBOX_H
|
||||
#define CSV_TOOLS_SEARCHBOX_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QComboBox>
|
||||
#include <QStackedWidget>
|
||||
#include <QPushButton>
|
||||
|
||||
class QGridLayout;
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class Search;
|
||||
}
|
||||
|
||||
namespace CSVTools
|
||||
{
|
||||
class SearchBox : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QStackedWidget mInput;
|
||||
QLineEdit mText;
|
||||
QComboBox mRecordState;
|
||||
QPushButton mSearch;
|
||||
QGridLayout *mLayout;
|
||||
QComboBox mMode;
|
||||
bool mSearchEnabled;
|
||||
|
||||
private:
|
||||
|
||||
void updateSearchButton();
|
||||
|
||||
public:
|
||||
|
||||
SearchBox (QWidget *parent = 0);
|
||||
|
||||
void setSearchMode (bool enabled);
|
||||
|
||||
CSMTools::Search getSearch() const;
|
||||
|
||||
private slots:
|
||||
|
||||
void modeSelected (int index);
|
||||
|
||||
void textChanged (const QString& text);
|
||||
|
||||
void startSearch (bool checked);
|
||||
|
||||
signals:
|
||||
|
||||
void startSearch (const CSMTools::Search& search);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue