added search class and search box widget

pull/554/head
Marc Zinnschlag 10 years ago
parent 413b35de6c
commit 78c6268891

@ -40,7 +40,7 @@ opencs_units (model/tools
opencs_units_noqt (model/tools
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck
startscriptcheck
startscriptcheck search
)
@ -91,7 +91,7 @@ opencs_hdrs_noqt (view/render
opencs_units (view/tools
reportsubview reporttable searchsubview
reportsubview reporttable searchsubview searchbox
)
opencs_units_noqt (view/tools

@ -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

@ -19,7 +19,77 @@ std::string CSMWorld::ColumnBase::getTitle() const
return Columns::getName (static_cast<Columns::ColumnId> (mColumnId));
}
int CSMWorld::ColumnBase::getId() const
int CSMWorld::ColumnBase::getId() const
{
return mColumnId;
}
bool CSMWorld::ColumnBase::isId (Display display)
{
static const Display ids[] =
{
Display_Skill,
Display_Class,
Display_Faction,
Display_Race,
Display_Sound,
Display_Region,
Display_Birthsign,
Display_Spell,
Display_Cell,
Display_Referenceable,
Display_Activator,
Display_Potion,
Display_Apparatus,
Display_Armor,
Display_Book,
Display_Clothing,
Display_Container,
Display_Creature,
Display_Door,
Display_Ingredient,
Display_CreatureLevelledList,
Display_ItemLevelledList,
Display_Light,
Display_Lockpick,
Display_Miscellaneous,
Display_Npc,
Display_Probe,
Display_Repair,
Display_Static,
Display_Weapon,
Display_Reference,
Display_Filter,
Display_Topic,
Display_Journal,
Display_TopicInfo,
Display_JournalInfo,
Display_Scene,
Display_GlobalVariable,
Display_Mesh,
Display_Icon,
Display_Music,
Display_SoundRes,
Display_Texture,
Display_Video,
Display_None
};
for (int i=0; ids[i]!=Display_None; ++i)
if (ids[i]==display)
return true;
return false;
}
bool CSMWorld::ColumnBase::isText (Display display)
{
return display==Display_String || display==Display_LongString;
}
bool CSMWorld::ColumnBase::isScript (Display display)
{
return display==Display_Script || display==Display_ScriptLines;
}

@ -122,6 +122,12 @@ namespace CSMWorld
virtual std::string getTitle() const;
virtual int getId() const;
static bool isId (Display display);
static bool isText (Display display);
static bool isScript (Display display);
};
template<typename ESXRecordT>

@ -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

@ -1,15 +1,37 @@
#include "searchsubview.hpp"
#include <QVBoxLayout>
#include "../../model/doc/document.hpp"
#include "reporttable.hpp"
#include "searchbox.hpp"
CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
: CSVDoc::SubView (id)
{
setWidget (mTable = new ReportTable (document, id, this));
QVBoxLayout *layout = new QVBoxLayout;
layout->setContentsMargins (QMargins (0, 0, 0, 0));
layout->addWidget (&mSearchBox);
layout->addWidget (mTable = new ReportTable (document, id), 2);
QWidget *widget = new QWidget;
widget->setLayout (layout);
setWidget (widget);
stateChanged (document.getState(), &document);
connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)),
SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)));
connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)),
this, SLOT (stateChanged (int, CSMDoc::Document *)));
}
void CSVTools::SearchSubView::setEditLock (bool locked)
@ -21,3 +43,8 @@ void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStr
{
mTable->updateUserSetting (name, list);
}
void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *document)
{
mSearchBox.setSearchMode (!(state & CSMDoc::State_Searching));
}

@ -3,6 +3,8 @@
#include "../doc/subview.hpp"
#include "searchbox.hpp"
class QTableView;
class QModelIndex;
@ -20,6 +22,7 @@ namespace CSVTools
Q_OBJECT
ReportTable *mTable;
SearchBox mSearchBox;
public:
@ -28,6 +31,10 @@ namespace CSVTools
virtual void setEditLock (bool locked);
virtual void updateUserSetting (const QString &, const QStringList &);
private slots:
void stateChanged (int state, CSMDoc::Document *document);
};
}

Loading…
Cancel
Save