From d053c62032eb57951c242bab41ff4d51ce3eacee Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 17 Mar 2015 12:30:47 +0100 Subject: [PATCH 01/35] setting up global search operation and subview --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/document.cpp | 6 +++++ apps/opencs/model/doc/document.hpp | 2 ++ apps/opencs/model/doc/state.hpp | 2 +- apps/opencs/model/tools/tools.cpp | 23 +++++++++++++--- apps/opencs/model/tools/tools.hpp | 5 ++++ apps/opencs/model/world/universalid.cpp | 1 + apps/opencs/model/world/universalid.hpp | 1 + apps/opencs/view/doc/view.cpp | 9 +++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/tools/searchsubview.cpp | 23 ++++++++++++++++ apps/opencs/view/tools/searchsubview.hpp | 34 ++++++++++++++++++++++++ apps/opencs/view/tools/subviews.cpp | 3 +++ 13 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 apps/opencs/view/tools/searchsubview.cpp create mode 100644 apps/opencs/view/tools/searchsubview.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e618d2961c..e3b44ac91e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -91,7 +91,7 @@ opencs_hdrs_noqt (view/render opencs_units (view/tools - reportsubview reporttable + reportsubview reporttable searchsubview ) opencs_units_noqt (view/tools diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7d27143b47..a06eb0ebf6 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2374,6 +2374,12 @@ CSMWorld::UniversalId CSMDoc::Document::verify() return id; } + +CSMWorld::UniversalId CSMDoc::Document::newSearch() +{ + return mTools.newSearch(); +} + void CSMDoc::Document::abortOperation (int type) { if (type==State_Saving) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 1f96b44a16..4300a9c647 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -120,6 +120,8 @@ namespace CSMDoc CSMWorld::UniversalId verify(); + CSMWorld::UniversalId newSearch(); + void abortOperation (int type); const CSMWorld::Data& getData() const; diff --git a/apps/opencs/model/doc/state.hpp b/apps/opencs/model/doc/state.hpp index 287439a8bb..78f4681010 100644 --- a/apps/opencs/model/doc/state.hpp +++ b/apps/opencs/model/doc/state.hpp @@ -13,7 +13,7 @@ namespace CSMDoc State_Saving = 16, State_Verifying = 32, State_Compiling = 64, // not implemented yet - State_Searching = 128, // not implemented yet + State_Searching = 128, State_Loading = 256 // pseudo-state; can not be encountered in a loaded document }; } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 170ea8ccda..07bd4205b3 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -31,6 +31,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::get (int type) switch (type) { case CSMDoc::State_Verifying: return &mVerifier; + case CSMDoc::State_Searching: return &mSearch; } return 0; @@ -101,7 +102,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() } CSMTools::Tools::Tools (CSMDoc::Document& document) -: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0) +: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0), + mSearchOperation (0) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -116,6 +118,12 @@ CSMTools::Tools::~Tools() delete mVerifierOperation; } + if (mSearchOperation) + { + mSearch.abortAndWait(); + delete mSearchOperation; + } + for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) delete iter->second; } @@ -130,6 +138,13 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier() return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1); } +CSMWorld::UniversalId CSMTools::Tools::newSearch() +{ + mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); + + return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); +} + void CSMTools::Tools::abortOperation (int type) { if (CSMDoc::OperationHolder *operation = get (type)) @@ -141,6 +156,7 @@ int CSMTools::Tools::getRunningOperations() const static const int sOperations[] = { CSMDoc::State_Verifying, + CSMDoc::State_Searching, -1 }; @@ -157,9 +173,10 @@ int CSMTools::Tools::getRunningOperations() const CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& id) { if (id.getType()!=CSMWorld::UniversalId::Type_VerificationResults && - id.getType()!=CSMWorld::UniversalId::Type_LoadErrorLog) + id.getType()!=CSMWorld::UniversalId::Type_LoadErrorLog && + id.getType()!=CSMWorld::UniversalId::Type_Search) throw std::logic_error ("invalid request for report model: " + id.toString()); - + return mReports.at (id.getIndex()); } diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index b8ded8a83c..bd27767a61 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -31,6 +31,8 @@ namespace CSMTools CSMWorld::Data& mData; CSMDoc::Operation *mVerifierOperation; CSMDoc::OperationHolder mVerifier; + CSMDoc::Operation *mSearchOperation; + CSMDoc::OperationHolder mSearch; std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number @@ -56,6 +58,9 @@ namespace CSMTools CSMWorld::UniversalId runVerifier(); ///< \return ID of the report for this verification run + /// Return ID of the report for this search. + CSMWorld::UniversalId newSearch(); + void abortOperation (int type); ///< \attention The operation is not aborted immediately. diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 50ac846dba..6aa129f256 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -128,6 +128,7 @@ namespace { { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 }, { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_LoadErrorLog, "Load Error Log", 0 }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Search, "Global Search", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; } diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index a716aec03f..f01e811caf 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -130,6 +130,7 @@ namespace CSMWorld Type_Pathgrid, Type_StartScripts, Type_StartScript, + Type_Search, Type_RunLog }; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 211f741873..3cabd8737e 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -113,6 +113,10 @@ void CSVDoc::View::setupViewMenu() QAction *filters = new QAction (tr ("Filters"), this); connect (filters, SIGNAL (triggered()), this, SLOT (addFiltersSubView())); view->addAction (filters); + + QAction *search = new QAction (tr ("Search"), this); + connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); + view->addAction (search); } void CSVDoc::View::setupWorldMenu() @@ -725,6 +729,11 @@ void CSVDoc::View::addStartScriptsSubView() addSubView (CSMWorld::UniversalId::Type_StartScripts); } +void CSVDoc::View::addSearchSubView() +{ + addSubView (mDocument->newSearch()); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index baadca85c3..32d7159c28 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -217,6 +217,8 @@ namespace CSVDoc void addStartScriptsSubView(); + void addSearchSubView(); + void toggleShowStatusBar (bool show); void loadErrorLog(); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp new file mode 100644 index 0000000000..7173a66349 --- /dev/null +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -0,0 +1,23 @@ + +#include "searchsubview.hpp" + +#include "reporttable.hpp" + +CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) +: CSVDoc::SubView (id) +{ + setWidget (mTable = new ReportTable (document, id, this)); + + connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), + SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); +} + +void CSVTools::SearchSubView::setEditLock (bool locked) +{ + // ignored. We don't change document state anyway. +} + +void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) +{ + mTable->updateUserSetting (name, list); +} diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp new file mode 100644 index 0000000000..abedd5e6db --- /dev/null +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -0,0 +1,34 @@ +#ifndef CSV_TOOLS_SEARCHSUBVIEW_H +#define CSV_TOOLS_SEARCHSUBVIEW_H + +#include "../doc/subview.hpp" + +class QTableView; +class QModelIndex; + +namespace CSMDoc +{ + class Document; +} + +namespace CSVTools +{ + class ReportTable; + + class SearchSubView : public CSVDoc::SubView + { + Q_OBJECT + + ReportTable *mTable; + + public: + + SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + + virtual void setEditLock (bool locked); + + virtual void updateUserSetting (const QString &, const QStringList &); + }; +} + +#endif diff --git a/apps/opencs/view/tools/subviews.cpp b/apps/opencs/view/tools/subviews.cpp index a50b5724a1..8a343ebe86 100644 --- a/apps/opencs/view/tools/subviews.cpp +++ b/apps/opencs/view/tools/subviews.cpp @@ -4,6 +4,7 @@ #include "../doc/subviewfactoryimp.hpp" #include "reportsubview.hpp" +#include "searchsubview.hpp" void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -11,4 +12,6 @@ void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactory); manager.add (CSMWorld::UniversalId::Type_LoadErrorLog, new CSVDoc::SubViewFactory); + manager.add (CSMWorld::UniversalId::Type_Search, + new CSVDoc::SubViewFactory); } From 413b35de6c8ab3cfccc13965aaef2c20bf3b7f01 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 19 Mar 2015 21:03:24 +0100 Subject: [PATCH 02/35] moved search menu item from view to edit --- apps/opencs/view/doc/view.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 3cabd8737e..533cab0492 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -91,6 +91,10 @@ void CSVDoc::View::setupEditMenu() QAction *userSettings = new QAction (tr ("&Preferences"), this); connect (userSettings, SIGNAL (triggered()), this, SIGNAL (editSettingsRequest())); edit->addAction (userSettings); + + QAction *search = new QAction (tr ("Search"), this); + connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); + edit->addAction (search); } void CSVDoc::View::setupViewMenu() @@ -113,10 +117,6 @@ void CSVDoc::View::setupViewMenu() QAction *filters = new QAction (tr ("Filters"), this); connect (filters, SIGNAL (triggered()), this, SLOT (addFiltersSubView())); view->addAction (filters); - - QAction *search = new QAction (tr ("Search"), this); - connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); - view->addAction (search); } void CSVDoc::View::setupWorldMenu() From 78c6268891020b0da1b30245a05c787e458f983e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 25 Mar 2015 11:56:14 +0100 Subject: [PATCH 03/35] added search class and search box widget --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/tools/search.cpp | 213 +++++++++++++++++++++++ apps/opencs/model/tools/search.hpp | 82 +++++++++ apps/opencs/model/world/columnbase.cpp | 72 +++++++- apps/opencs/model/world/columnbase.hpp | 6 + apps/opencs/view/tools/searchbox.cpp | 145 +++++++++++++++ apps/opencs/view/tools/searchbox.hpp | 57 ++++++ apps/opencs/view/tools/searchsubview.cpp | 29 ++- apps/opencs/view/tools/searchsubview.hpp | 7 + 9 files changed, 611 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/model/tools/search.cpp create mode 100644 apps/opencs/model/tools/search.hpp create mode 100644 apps/opencs/view/tools/searchbox.cpp create mode 100644 apps/opencs/view/tools/searchbox.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e3b44ac91e..eb83b14d5a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -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 diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp new file mode 100644 index 0000000000..1b7be6fbfb --- /dev/null +++ b/apps/opencs/model/tools/search.cpp @@ -0,0 +1,213 @@ + +#include "search.hpp" + +#include +#include + +#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 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 ( + model->headerData ( + i, Qt::Horizontal, static_cast (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::const_iterator iter (mColumns.begin()); iter!=mColumns.end(); + ++iter) + { + QModelIndex index = model->index (row, iter->first); + + CSMWorld::UniversalId::Type type = static_cast ( + 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; + } + } +} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp new file mode 100644 index 0000000000..3683f9c9b2 --- /dev/null +++ b/apps/opencs/model/tools/search.hpp @@ -0,0 +1,82 @@ +#ifndef CSM_TOOLS_SEARCH_H +#define CSM_TOOLS_SEARCH_H + +#include +#include + +#include +#include + +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 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 diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 665ab93545..f4f2310b63 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -19,7 +19,77 @@ std::string CSMWorld::ColumnBase::getTitle() const return Columns::getName (static_cast (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; +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index db9b8b3c64..c49785154e 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -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 diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp new file mode 100644 index 0000000000..1b11d8a4d4 --- /dev/null +++ b/apps/opencs/view/tools/searchbox.cpp @@ -0,0 +1,145 @@ + +#include "searchbox.hpp" + +#include + +#include +#include +#include + +#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 states = + CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); + states.resize (states.size()-1); // ignore erased state + + for (std::vector::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 (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()); +} diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp new file mode 100644 index 0000000000..dc975cac9c --- /dev/null +++ b/apps/opencs/view/tools/searchbox.hpp @@ -0,0 +1,57 @@ +#ifndef CSV_TOOLS_SEARCHBOX_H +#define CSV_TOOLS_SEARCHBOX_H + +#include +#include +#include +#include +#include + +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 diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 7173a66349..bc818df071 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -1,15 +1,37 @@ #include "searchsubview.hpp" +#include + +#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)); +} diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index abedd5e6db..b389805bb0 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -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); }; } From 23cf859fee045877d7a6cc64fea023939f9ab4f2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 27 Mar 2015 16:33:54 +0100 Subject: [PATCH 04/35] added search stages (cell table only for now) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/document.cpp | 5 +++ apps/opencs/model/doc/document.hpp | 2 ++ apps/opencs/model/tools/searchoperation.cpp | 33 ++++++++++++++++++ apps/opencs/model/tools/searchoperation.hpp | 38 +++++++++++++++++++++ apps/opencs/model/tools/searchstage.cpp | 30 ++++++++++++++++ apps/opencs/model/tools/searchstage.hpp | 37 ++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 22 ++++++++++++ apps/opencs/model/tools/tools.hpp | 6 +++- apps/opencs/view/doc/operation.cpp | 1 + apps/opencs/view/doc/view.cpp | 2 +- apps/opencs/view/tools/searchsubview.cpp | 10 +++++- apps/opencs/view/tools/searchsubview.hpp | 3 ++ 13 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/model/tools/searchoperation.cpp create mode 100644 apps/opencs/model/tools/searchoperation.hpp create mode 100644 apps/opencs/model/tools/searchstage.cpp create mode 100644 apps/opencs/model/tools/searchstage.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index eb83b14d5a..f27231c5a4 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -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 search + startscriptcheck search searchoperation searchstage ) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a06eb0ebf6..cb3b4ba187 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2380,6 +2380,11 @@ CSMWorld::UniversalId CSMDoc::Document::newSearch() return mTools.newSearch(); } +void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search) +{ + return mTools.runSearch (searchId, search); +} + void CSMDoc::Document::abortOperation (int type) { if (type==State_Saving) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 4300a9c647..6b1a1fc1e8 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -121,6 +121,8 @@ namespace CSMDoc CSMWorld::UniversalId verify(); CSMWorld::UniversalId newSearch(); + + void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search); void abortOperation (int type); diff --git a/apps/opencs/model/tools/searchoperation.cpp b/apps/opencs/model/tools/searchoperation.cpp new file mode 100644 index 0000000000..134b83b727 --- /dev/null +++ b/apps/opencs/model/tools/searchoperation.cpp @@ -0,0 +1,33 @@ + +#include "searchoperation.hpp" + +#include "../doc/state.hpp" +#include "../doc/document.hpp" + +#include "../world/data.hpp" +#include "../world/idtablebase.hpp" + +#include "searchstage.hpp" + +CSMTools::SearchOperation::SearchOperation (CSMDoc::Document& document) +: CSMDoc::Operation (CSMDoc::State_Searching, false) +{ +appendStage (new SearchStage (&dynamic_cast (*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)))); + +} + +void CSMTools::SearchOperation::configure (const Search& search) +{ + mSearch = search; +} + +void CSMTools::SearchOperation::appendStage (SearchStage *stage) +{ + CSMDoc::Operation::appendStage (stage); + stage->setOperation (this); +} + +const CSMTools::Search& CSMTools::SearchOperation::getSearch() const +{ + return mSearch; +} diff --git a/apps/opencs/model/tools/searchoperation.hpp b/apps/opencs/model/tools/searchoperation.hpp new file mode 100644 index 0000000000..fbbb388981 --- /dev/null +++ b/apps/opencs/model/tools/searchoperation.hpp @@ -0,0 +1,38 @@ +#ifndef CSM_TOOLS_SEARCHOPERATION_H +#define CSM_TOOLS_SEARCHOPERATION_H + +#include "../doc/operation.hpp" + +#include "search.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSMTools +{ + class SearchStage; + + class SearchOperation : public CSMDoc::Operation + { + Search mSearch; + + public: + + SearchOperation (CSMDoc::Document& document); + + /// \attention Do not call this function while a search is running. + void configure (const Search& search); + + void appendStage (SearchStage *stage); + ///< The ownership of \a stage is transferred to *this. + /// + /// \attention Do no call this function while this Operation is running. + + const Search& getSearch() const; + + }; +} + +#endif diff --git a/apps/opencs/model/tools/searchstage.cpp b/apps/opencs/model/tools/searchstage.cpp new file mode 100644 index 0000000000..17859d9309 --- /dev/null +++ b/apps/opencs/model/tools/searchstage.cpp @@ -0,0 +1,30 @@ + +#include "searchstage.hpp" + +#include "../world/idtablebase.hpp" + +#include "searchoperation.hpp" + +CSMTools::SearchStage::SearchStage (const CSMWorld::IdTableBase *model) +: mModel (model), mOperation (0) +{} + +int CSMTools::SearchStage::setup() +{ + if (mOperation) + mSearch = mOperation->getSearch(); + + mSearch.configure (mModel); + + return mModel->rowCount(); +} + +void CSMTools::SearchStage::perform (int stage, CSMDoc::Messages& messages) +{ + mSearch.searchRow (mModel, stage, messages); +} + +void CSMTools::SearchStage::setOperation (const SearchOperation *operation) +{ + mOperation = operation; +} diff --git a/apps/opencs/model/tools/searchstage.hpp b/apps/opencs/model/tools/searchstage.hpp new file mode 100644 index 0000000000..073487c0d2 --- /dev/null +++ b/apps/opencs/model/tools/searchstage.hpp @@ -0,0 +1,37 @@ +#ifndef CSM_TOOLS_SEARCHSTAGE_H +#define CSM_TOOLS_SEARCHSTAGE_H + +#include "../doc/stage.hpp" + +#include "search.hpp" + +namespace CSMWorld +{ + class IdTableBase; +} + +namespace CSMTools +{ + class SearchOperation; + + class SearchStage : public CSMDoc::Stage + { + const CSMWorld::IdTableBase *mModel; + Search mSearch; + const SearchOperation *mOperation; + + public: + + SearchStage (const CSMWorld::IdTableBase *model); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + + void setOperation (const SearchOperation *operation); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 07bd4205b3..957e202960 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -25,6 +25,7 @@ #include "bodypartcheck.hpp" #include "referencecheck.hpp" #include "startscriptcheck.hpp" +#include "searchoperation.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -108,6 +109,12 @@ CSMTools::Tools::Tools (CSMDoc::Document& document) // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); mActiveReports.insert (std::make_pair (CSMDoc::State_Loading, 0)); + + connect (&mSearch, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); + connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); + connect (&mSearch, + SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), + this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); } CSMTools::Tools::~Tools() @@ -145,6 +152,21 @@ CSMWorld::UniversalId CSMTools::Tools::newSearch() return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); } +void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Search& search) +{ + mActiveReports[CSMDoc::State_Searching] = searchId.getIndex(); + + if (!mSearchOperation) + { + mSearchOperation = new SearchOperation (mDocument); + mSearch.setOperation (mSearchOperation); + } + + mSearchOperation->configure (search); + + mSearch.start(); +} + void CSMTools::Tools::abortOperation (int type) { if (CSMDoc::OperationHolder *operation = get (type)) diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index bd27767a61..0f9e570445 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -22,6 +22,8 @@ namespace CSMDoc namespace CSMTools { class ReportModel; + class Search; + class SearchOperation; class Tools : public QObject { @@ -31,7 +33,7 @@ namespace CSMTools CSMWorld::Data& mData; CSMDoc::Operation *mVerifierOperation; CSMDoc::OperationHolder mVerifier; - CSMDoc::Operation *mSearchOperation; + SearchOperation *mSearchOperation; CSMDoc::OperationHolder mSearch; std::map mReports; int mNextReportNumber; @@ -60,6 +62,8 @@ namespace CSMTools /// Return ID of the report for this search. CSMWorld::UniversalId newSearch(); + + void runSearch (const CSMWorld::UniversalId& searchId, const Search& search); void abortOperation (int type); ///< \attention The operation is not aborted immediately. diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index 6977d79535..95cbf012d6 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -18,6 +18,7 @@ void CSVDoc::Operation::updateLabel (int threads) { case CSMDoc::State_Saving: name = "saving"; break; case CSMDoc::State_Verifying: name = "verifying"; break; + case CSMDoc::State_Searching: name = "searching"; break; } std::ostringstream stream; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 533cab0492..e7eb283375 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -447,7 +447,7 @@ void CSVDoc::View::updateDocumentState() static const int operations[] = { - CSMDoc::State_Saving, CSMDoc::State_Verifying, + CSMDoc::State_Saving, CSMDoc::State_Verifying, CSMDoc::State_Searching, -1 // end marker }; diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index bc818df071..b4a0f893a3 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -9,7 +9,7 @@ #include "searchbox.hpp" CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id) +: CSVDoc::SubView (id), mDocument (document) { QVBoxLayout *layout = new QVBoxLayout; @@ -32,6 +32,9 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (stateChanged (int, CSMDoc::Document *))); + + connect (&mSearchBox, SIGNAL (startSearch (const CSMTools::Search&)), + this, SLOT (startSearch (const CSMTools::Search&))); } void CSVTools::SearchSubView::setEditLock (bool locked) @@ -48,3 +51,8 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen { mSearchBox.setSearchMode (!(state & CSMDoc::State_Searching)); } + +void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) +{ + mDocument.runSearch (getUniversalId(), search); +} diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index b389805bb0..d17f7a3407 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -23,6 +23,7 @@ namespace CSVTools ReportTable *mTable; SearchBox mSearchBox; + CSMDoc::Document& mDocument; public: @@ -35,6 +36,8 @@ namespace CSVTools private slots: void stateChanged (int state, CSMDoc::Document *document); + + void startSearch (const CSMTools::Search& search); }; } From 705ee67265ca1028bba2adb143e2219f0c6aab54 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 27 Mar 2015 18:55:48 +0100 Subject: [PATCH 05/35] fixed hints getting mixed up with message text --- apps/opencs/model/tools/search.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 1b7be6fbfb..f37425ea84 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -27,7 +27,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, message << text.mid (pos).toUtf8().data(); std::ostringstream hint; - message << "r: " << index.column() << " " << pos << " " << search.length(); + hint << "r: " << index.column() << " " << pos << " " << search.length(); messages.add (id, message.str(), hint.str()); @@ -54,7 +54,7 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, int length = mRegExp.matchedLength(); std::ostringstream hint; - message << "r: " << index.column() << " " << pos << " " << length; + hint << "r: " << index.column() << " " << pos << " " << length; messages.add (id, message.str(), hint.str()); @@ -79,7 +79,7 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model message << id.getId() << " " << states.at (data); std::ostringstream hint; - message << "r: " << index.column(); + hint << "r: " << index.column(); messages.add (id, message.str(), hint.str()); } From babefacbfac1a2411469620a518632ae9cf05a82 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 27 Mar 2015 19:10:45 +0100 Subject: [PATCH 06/35] improved message text in search results --- apps/opencs/model/tools/search.cpp | 19 ++++++++++++++++--- apps/opencs/model/tools/search.hpp | 2 ++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index f37425ea84..9e22f82dd1 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -24,7 +24,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, while ((pos = text.indexOf (search, pos, Qt::CaseInsensitive))!=-1) { std::ostringstream message; - message << text.mid (pos).toUtf8().data(); + message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); std::ostringstream hint; hint << "r: " << index.column() << " " << pos << " " << search.length(); @@ -49,7 +49,7 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, while ((pos = mRegExp.indexIn (text, pos))!=-1) { std::ostringstream message; - message << text.mid (pos).toUtf8().data(); + message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); int length = mRegExp.matchedLength(); @@ -76,7 +76,7 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); std::ostringstream message; - message << id.getId() << " " << states.at (data); + message << getLocation (model, index, id) << states.at (data); std::ostringstream hint; hint << "r: " << index.column(); @@ -85,6 +85,19 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model } } +std::string CSMTools::Search::getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const +{ + std::ostringstream stream; + + stream + << id.getId() + << ", " + << model->headerData (index.column(), Qt::Horizontal).toString().toUtf8().data() + << ": "; + + return stream.str(); +} + CSMTools::Search::Search() : mType (Type_None) {} CSMTools::Search::Search (Type type, const std::string& value) diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 3683f9c9b2..7e95a28460 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -55,6 +55,8 @@ namespace CSMTools void searchRecordStateCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; + + std::string getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const; public: From be6ee927b906313cc7a19ed4298da725c22aebbd Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 28 Mar 2015 20:05:54 +1300 Subject: [PATCH 07/35] AiWander, use closest two points if distance is too small (Fixes #1317) In AiWander, if wander distance is set too small to get two points, take the closest two points. --- apps/openmw/mwmechanics/aiwander.cpp | 30 ++++++++++++++++++++++++++-- apps/openmw/mwmechanics/aiwander.hpp | 7 +++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index d277b1249d..560e756ce2 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -686,7 +686,8 @@ namespace MWMechanics // If there is no path this actor doesn't go anywhere. See: // https://forum.openmw.org/viewtopic.php?t=1556 // http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833 - if(!pathgrid || pathgrid->mPoints.empty()) + // Note: In order to wander, need at least two points. + if(!pathgrid || (pathgrid->mPoints.size() < 2)) mDistance = 0; // A distance value passed into the constructor indicates how far the @@ -730,12 +731,37 @@ namespace MWMechanics } mCurrentNode = mAllowedNodes[index]; mAllowedNodes.erase(mAllowedNodes.begin() + index); + } + + // In vanilla Morrowind, sometimes distance is too small to include at least two points, + // in which case, we will take the two closest points regardless of the wander distance + // This is a backup option, as std::sort is potentially O(n^2) in time. + if (mAllowedNodes.empty()) + { + // Start with list of PathGrid nodes, sorted by distance from actor + std::vector nodeDistances; + for (unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) + { + float distance = npcPos.squaredDistance(PathFinder::MakeOgreVector3(pathgrid->mPoints[counter])); + nodeDistances.push_back(std::make_pair(distance, &pathgrid->mPoints.at(counter))); + } + std::sort(nodeDistances.begin(), nodeDistances.end(), sortByDistance); - mStoredAvailableNodes = true; // set only if successful in finding allowed nodes + // make closest node the current node + mCurrentNode = *nodeDistances[0].second; + + // give Actor a 2nd node to walk to + mAllowedNodes.push_back(*nodeDistances[1].second); } + mStoredAvailableNodes = true; // set only if successful in finding allowed nodes } } + bool AiWander::sortByDistance(const PathDistance& left, const PathDistance& right) + { + return left.first < right.first; + } + void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr wander(new ESM::AiSequence::AiWander()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 7e138c0012..7f8fc5088a 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -122,6 +122,13 @@ namespace MWMechanics /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; + + /// record distances of pathgrid point nodes to actor + /// first value is distance between actor and node, second value is PathGrid node + typedef std::pair PathDistance; + + /// used to sort array of PathDistance objects into ascending order + static bool sortByDistance(const PathDistance& left, const PathDistance& right); }; From 128ccd81510ab7c216162672801fce24ef9602e1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 11:54:32 +0100 Subject: [PATCH 08/35] improved search type naming --- apps/opencs/model/tools/search.cpp | 12 ++++++------ apps/opencs/model/tools/search.hpp | 4 ++-- apps/opencs/view/tools/searchbox.cpp | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 9e22f82dd1..b873088dee 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -103,14 +103,14 @@ 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) + if (type!=Type_Text && type!=Type_Id) 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) + if (type!=Type_TextRegEx && type!=Type_IdRegEx) throw std::logic_error ("Invalid search parameter (RegExp)"); } @@ -150,8 +150,8 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) break; - case Type_Reference: - case Type_ReferenceRegEx: + case Type_Id: + case Type_IdRegEx: if (CSMWorld::ColumnBase::isId (display)) { @@ -202,13 +202,13 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, switch (mType) { case Type_Text: - case Type_Reference: + case Type_Id: searchTextCell (model, index, id, iter->second, messages); break; case Type_TextRegEx: - case Type_ReferenceRegEx: + case Type_IdRegEx: searchRegExCell (model, index, id, iter->second, messages); break; diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 7e95a28460..46ea996865 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -30,8 +30,8 @@ namespace CSMTools { Type_Text = 0, Type_TextRegEx = 1, - Type_Reference = 2, - Type_ReferenceRegEx = 3, + Type_Id = 2, + Type_IdRegEx = 3, Type_RecordState = 4, Type_None }; diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 1b11d8a4d4..bfae6f50dd 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -50,8 +50,8 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) mMode.addItem ("Text"); mMode.addItem ("Text (RegEx)"); - mMode.addItem ("Reference"); - mMode.addItem ("Reference (RegEx)"); + mMode.addItem ("ID"); + mMode.addItem ("ID (RegEx)"); mMode.addItem ("Record State"); mLayout->addWidget (&mMode, 0, 0); @@ -93,12 +93,12 @@ CSMTools::Search CSVTools::SearchBox::getSearch() const switch (type) { case CSMTools::Search::Type_Text: - case CSMTools::Search::Type_Reference: + case CSMTools::Search::Type_Id: return CSMTools::Search (type, std::string (mText.text().toUtf8().data())); case CSMTools::Search::Type_TextRegEx: - case CSMTools::Search::Type_ReferenceRegEx: + case CSMTools::Search::Type_IdRegEx: return CSMTools::Search (type, QRegExp (mText.text().toUtf8().data(), Qt::CaseInsensitive)); @@ -120,8 +120,8 @@ void CSVTools::SearchBox::modeSelected (int index) { case CSMTools::Search::Type_Text: case CSMTools::Search::Type_TextRegEx: - case CSMTools::Search::Type_Reference: - case CSMTools::Search::Type_ReferenceRegEx: + case CSMTools::Search::Type_Id: + case CSMTools::Search::Type_IdRegEx: mInput.setCurrentIndex (0); break; From eaaf816dd3a9d48fb785954188211cb9b5cddda3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 12:05:49 +0100 Subject: [PATCH 09/35] simplified search rules --- apps/opencs/model/tools/search.cpp | 31 +++++++++--------------------- apps/opencs/model/tools/search.hpp | 8 ++++---- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index b873088dee..2d3e4f952b 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -11,7 +11,7 @@ #include "../../model/world/universalid.hpp" void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, bool multiple, + const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const { // using QString here for easier handling of case folding. @@ -31,15 +31,12 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, 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, + const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const { QString text = model->data (index).toString(); @@ -58,9 +55,6 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, messages.add (id, message.str(), hint.str()); - if (!multiple) - break; - pos += length; } } @@ -134,7 +128,6 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) i, Qt::Horizontal, static_cast (CSMWorld::ColumnBase::Role_Display)).toInt()); bool consider = false; - bool multiple = false; switch (mType) { @@ -145,7 +138,6 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) CSMWorld::ColumnBase::isScript (display)) { consider = true; - multiple = true; } break; @@ -153,14 +145,10 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) case Type_Id: case Type_IdRegEx: - if (CSMWorld::ColumnBase::isId (display)) - { - consider = true; - } - else if (CSMWorld::ColumnBase::isScript (display)) + if (CSMWorld::ColumnBase::isId (display) || + CSMWorld::ColumnBase::isScript (display)) { consider = true; - multiple = true; } break; @@ -178,7 +166,7 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) } if (consider) - mColumns.insert (std::make_pair (i, multiple)); + mColumns.insert (i); } mIdColumn = model->findColumnIndex (CSMWorld::Columns::ColumnId_Id); @@ -188,10 +176,9 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, CSMDoc::Messages& messages) const { - for (std::map::const_iterator iter (mColumns.begin()); iter!=mColumns.end(); - ++iter) + for (std::set::const_iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter) { - QModelIndex index = model->index (row, iter->first); + QModelIndex index = model->index (row, *iter); CSMWorld::UniversalId::Type type = static_cast ( model->data (model->index (row, mTypeColumn)).toInt()); @@ -204,13 +191,13 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, case Type_Text: case Type_Id: - searchTextCell (model, index, id, iter->second, messages); + searchTextCell (model, index, id, messages); break; case Type_TextRegEx: case Type_IdRegEx: - searchRegExCell (model, index, id, iter->second, messages); + searchRegExCell (model, index, id, messages); break; case Type_RecordState: diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 46ea996865..81b8840bf4 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -2,7 +2,7 @@ #define CSM_TOOLS_SEARCH_H #include -#include +#include #include #include @@ -42,15 +42,15 @@ namespace CSMTools std::string mText; QRegExp mRegExp; int mValue; - std::map mColumns; // column, multiple finds per cell + std::set mColumns; int mIdColumn; int mTypeColumn; void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; void searchRegExCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; void searchRecordStateCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id, From 8e9365741f448aa1ab04867fbc7a789d02d795d2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 12:53:01 +0100 Subject: [PATCH 10/35] make search sub-views re-usable (clear before starting a new search) --- apps/opencs/model/tools/reportmodel.cpp | 10 ++++++++++ apps/opencs/model/tools/reportmodel.hpp | 2 ++ apps/opencs/view/tools/reporttable.cpp | 5 +++++ apps/opencs/view/tools/reporttable.hpp | 2 ++ apps/opencs/view/tools/searchsubview.cpp | 1 + 5 files changed, 20 insertions(+) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index ac9dabb25b..acd4728c66 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -79,3 +79,13 @@ std::string CSMTools::ReportModel::getHint (int row) const { return mRows.at (row).second.second; } + +void CSMTools::ReportModel::clear() +{ + if (!mRows.empty()) + { + beginRemoveRows (QModelIndex(), 0, mRows.size()-1); + mRows.clear(); + endRemoveRows(); + } +} diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 709e024a72..71f5bdf731 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -34,6 +34,8 @@ namespace CSMTools const CSMWorld::UniversalId& getUniversalId (int row) const; std::string getHint (int row) const; + + void clear(); }; } diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 809a39fa47..5eb375f46f 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -134,3 +134,8 @@ void CSVTools::ReportTable::removeSelection() selectionModel()->clear(); } + +void CSVTools::ReportTable::clear() +{ + mModel->clear(); +} diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 7a5b232f98..4b686f2d48 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -43,6 +43,8 @@ namespace CSVTools void updateUserSetting (const QString& name, const QStringList& list); + void clear(); + private slots: void showSelection(); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index b4a0f893a3..4afed2c907 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -54,5 +54,6 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { + mTable->clear(); mDocument.runSearch (getUniversalId(), search); } From 13a4fb3fdca30bce5cd7d76f7a7c56e55ff7be1a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 13:05:18 +0100 Subject: [PATCH 11/35] make return key press in search input trigger a new search --- apps/opencs/view/tools/searchbox.cpp | 7 +++++-- apps/opencs/view/tools/searchbox.hpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index bfae6f50dd..178dd1f041 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -74,7 +74,9 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) this, SLOT (textChanged (const QString&))); connect (&mSearch, SIGNAL (clicked (bool)), this, SLOT (startSearch (bool))); - + + connect (&mText, SIGNAL (returnPressed()), this, SLOT (startSearch())); + modeSelected (0); updateSearchButton(); @@ -141,5 +143,6 @@ void CSVTools::SearchBox::textChanged (const QString& text) void CSVTools::SearchBox::startSearch (bool checked) { - emit startSearch (getSearch()); + if (mSearch.isEnabled()) + emit startSearch (getSearch()); } diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp index dc975cac9c..35c656d160 100644 --- a/apps/opencs/view/tools/searchbox.hpp +++ b/apps/opencs/view/tools/searchbox.hpp @@ -46,7 +46,7 @@ namespace CSVTools void textChanged (const QString& text); - void startSearch (bool checked); + void startSearch (bool checked = true); signals: From c5f1c2127d51fc7252e72ccbe5be6e902c8d19c2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 14:36:28 +0100 Subject: [PATCH 12/35] extend global search to all record and reference tables --- apps/opencs/model/tools/searchoperation.cpp | 11 +++++++++-- apps/opencs/model/world/universalid.cpp | 19 +++++++++++++++++++ apps/opencs/model/world/universalid.hpp | 20 +++++++++++--------- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/tools/searchoperation.cpp b/apps/opencs/model/tools/searchoperation.cpp index 134b83b727..4512de5829 100644 --- a/apps/opencs/model/tools/searchoperation.cpp +++ b/apps/opencs/model/tools/searchoperation.cpp @@ -12,8 +12,15 @@ CSMTools::SearchOperation::SearchOperation (CSMDoc::Document& document) : CSMDoc::Operation (CSMDoc::State_Searching, false) { -appendStage (new SearchStage (&dynamic_cast (*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)))); - + std::vector types = CSMWorld::UniversalId::listTypes ( + CSMWorld::UniversalId::Class_RecordList | + CSMWorld::UniversalId::Class_ResourceList + ); + + for (std::vector::const_iterator iter (types.begin()); + iter!=types.end(); ++iter) + appendStage (new SearchStage (&dynamic_cast ( + *document.getData().getTableModel (*iter)))); } void CSMTools::SearchOperation::configure (const Search& search) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 6aa129f256..fbc942f8e2 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -348,6 +348,25 @@ std::vector CSMWorld::UniversalId::listReferenceabl return list; } +std::vector CSMWorld::UniversalId::listTypes (int classes) +{ + std::vector list; + + for (int i=0; sNoArg[i].mName; ++i) + if (sNoArg[i].mClass & classes) + list.push_back (sNoArg[i].mType); + + for (int i=0; sIdArg[i].mName; ++i) + if (sIdArg[i].mClass & classes) + list.push_back (sIdArg[i].mType); + + for (int i=0; sIndexArg[i].mName; ++i) + if (sIndexArg[i].mClass & classes) + list.push_back (sIndexArg[i].mType); + + return list; +} + CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType (Type type) { for (int i=0; sIdArg[i].mType; ++i) diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index f01e811caf..0a9fa38473 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -16,16 +16,16 @@ namespace CSMWorld enum Class { Class_None = 0, - Class_Record, - Class_RefRecord, // referenceable record - Class_SubRecord, - Class_RecordList, - Class_Collection, // multiple types of records combined - Class_Transient, // not part of the world data or the project data - Class_NonRecord, // record like data that is not part of the world - Class_Resource, ///< \attention Resource IDs are unique only within the + Class_Record = 1, + Class_RefRecord = 2, // referenceable record + Class_SubRecord = 4, + Class_RecordList = 8, + Class_Collection = 16, // multiple types of records combined + Class_Transient = 32, // not part of the world data or the project data + Class_NonRecord = 64, // record like data that is not part of the world + Class_Resource = 128, ///< \attention Resource IDs are unique only within the /// respective collection - Class_ResourceList + Class_ResourceList = 256 }; enum ArgumentType @@ -181,6 +181,8 @@ namespace CSMWorld static std::vector listReferenceableTypes(); + static std::vector listTypes (int classes); + /// If \a type is a SubRecord, RefRecord or Record type return the type of the table /// that contains records of type \a type. /// Otherwise return Type_None. From 1ec0db231c4d824683c8fd63485f3d50073e5b0f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 14:48:06 +0100 Subject: [PATCH 13/35] add a separate display type for ID column --- apps/opencs/model/world/columnbase.cpp | 2 ++ apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columnimp.hpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index f4f2310b63..a736c01551 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -73,6 +73,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_SoundRes, Display_Texture, Display_Video, + + Display_Id, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c49785154e..38039c27c0 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -103,7 +103,8 @@ namespace CSMWorld Display_Colour, Display_ScriptLines, // console context Display_SoundGeneratorType, - Display_School + Display_School, + Display_Id }; int mColumnId; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index da14bb4955..47b744b7f3 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -43,7 +43,7 @@ namespace CSMWorld struct StringIdColumn : public Column { StringIdColumn (bool hidden = false) - : Column (Columns::ColumnId_Id, ColumnBase::Display_String, + : Column (Columns::ColumnId_Id, ColumnBase::Display_Id, hidden ? 0 : ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue) {} From 4042b120130a971e234b08a6a9826d4c15b56d0b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 13:43:11 +0200 Subject: [PATCH 14/35] changed data structure for report model --- apps/opencs/model/tools/reportmodel.cpp | 20 +++++++++++++------- apps/opencs/model/tools/reportmodel.hpp | 12 +++++++++++- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index acd4728c66..cc6c5a44cd 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -3,6 +3,12 @@ #include +CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint) +: mId (id), mMessage (message), mHint (hint) +{} + + int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const { if (parent.isValid()) @@ -25,12 +31,12 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const return QVariant(); if (index.column()==0) - return static_cast (mRows.at (index.row()).first.getType()); + return static_cast (mRows.at (index.row()).mId.getType()); if (index.column()==1) - return QString::fromUtf8 (mRows.at (index.row()).second.first.c_str()); + return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); - return QString::fromUtf8 (mRows.at (index.row()).second.second.c_str()); + return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); } QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const @@ -64,20 +70,20 @@ void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::str const std::string& hint) { beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); - - mRows.push_back (std::make_pair (id, std::make_pair (message, hint))); + + mRows.push_back (Line (id, message, hint)); endInsertRows(); } const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const { - return mRows.at (row).first; + return mRows.at (row).mId; } std::string CSMTools::ReportModel::getHint (int row) const { - return mRows.at (row).second.second; + return mRows.at (row).mHint; } void CSMTools::ReportModel::clear() diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 71f5bdf731..64a477b6c9 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -14,7 +14,17 @@ namespace CSMTools { Q_OBJECT - std::vector > > mRows; + struct Line + { + Line (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint); + + CSMWorld::UniversalId mId; + std::string mMessage; + std::string mHint; + }; + + std::vector mRows; public: From a8cdd30124669136d360be0c869c9f1182ea8655 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 13:55:31 +0200 Subject: [PATCH 15/35] added ID column to report table --- apps/opencs/model/tools/reportmodel.cpp | 44 ++++++++++++++++++------- apps/opencs/model/tools/reportmodel.hpp | 5 +++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index cc6c5a44cd..218f391c99 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -22,7 +22,7 @@ int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const if (parent.isValid()) return 0; - return 3; + return 4; } QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const @@ -30,13 +30,32 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const if (role!=Qt::DisplayRole) return QVariant(); - if (index.column()==0) - return static_cast (mRows.at (index.row()).mId.getType()); + switch (index.column()) + { + case Column_Type: + + return static_cast (mRows.at (index.row()).mId.getType()); + + case Column_Id: + { + CSMWorld::UniversalId id = mRows.at (index.row()).mId; + + if (id.getArgumentType()==CSMWorld::UniversalId::ArgumentType_Id) + return QString::fromUtf8 (id.getId().c_str()); - if (index.column()==1) - return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); + return QString ("-"); + } + + case Column_Description: - return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); + return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); + + case Column_Hint: + + return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); + } + + return QVariant(); } QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const @@ -47,13 +66,14 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta if (orientation==Qt::Vertical) return QVariant(); - if (section==0) - return "Type"; - - if (section==1) - return "Description"; + switch (section) + { + case Column_Type: return "Type"; + case Column_Id: return "ID"; + case Column_Description: return "Description"; + } - return "Hint"; + return "-"; } bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& parent) diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 64a477b6c9..5f39316aa0 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -26,6 +26,11 @@ namespace CSMTools std::vector mRows; + enum Columns + { + Column_Type = 0, Column_Id = 1, Column_Hint = 2, Column_Description = 3 + }; + public: virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; From 416b8165cdbd694a8a6690361ef585a2a5adfa52 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 15:28:11 +0200 Subject: [PATCH 16/35] moved getColumnId function from IdTable to IdTable base and made it virtual --- apps/opencs/model/world/idtable.hpp | 2 +- apps/opencs/model/world/idtablebase.hpp | 2 ++ apps/opencs/model/world/resourcetable.cpp | 11 +++++++++++ apps/opencs/model/world/resourcetable.hpp | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ea8ab80f91..6f4be71786 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -82,7 +82,7 @@ namespace CSMWorld /// Is \a id flagged as deleted? virtual bool isDeleted (const std::string& id) const; - int getColumnId(int column) const; + virtual int getColumnId(int column) const; }; } diff --git a/apps/opencs/model/world/idtablebase.hpp b/apps/opencs/model/world/idtablebase.hpp index ef5a9c42ed..0d77d48efc 100644 --- a/apps/opencs/model/world/idtablebase.hpp +++ b/apps/opencs/model/world/idtablebase.hpp @@ -60,6 +60,8 @@ namespace CSMWorld /// Is \a id flagged as deleted? virtual bool isDeleted (const std::string& id) const = 0; + virtual int getColumnId (int column) const = 0; + unsigned int getFeatures() const; }; } diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 9257b9d2a8..36e2b3f3db 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -144,3 +144,14 @@ bool CSMWorld::ResourceTable::isDeleted (const std::string& id) const { return false; } + +int CSMWorld::ResourceTable::getColumnId (int column) const +{ + switch (column) + { + case 0: return Columns::ColumnId_Id; + case 1: return Columns::ColumnId_RecordType; + } + + return -1; +} diff --git a/apps/opencs/model/world/resourcetable.hpp b/apps/opencs/model/world/resourcetable.hpp index f5011ab2bd..88dcc24b0c 100644 --- a/apps/opencs/model/world/resourcetable.hpp +++ b/apps/opencs/model/world/resourcetable.hpp @@ -51,6 +51,8 @@ namespace CSMWorld /// Is \a id flagged as deleted? virtual bool isDeleted (const std::string& id) const; + + virtual int getColumnId (int column) const; }; } From e8091c4e7e21964187d8edd50c5d45685629c7bb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 15:28:31 +0200 Subject: [PATCH 17/35] added field column to report table --- apps/opencs/model/tools/reportmodel.cpp | 51 ++++++++++++++++++++++--- apps/opencs/model/tools/reportmodel.hpp | 9 ++++- apps/opencs/model/tools/search.cpp | 6 ++- apps/opencs/model/tools/tools.cpp | 2 +- 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 218f391c99..627199c22f 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -2,12 +2,29 @@ #include "reportmodel.hpp" #include +#include + +#include "../world/columns.hpp" CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint) : mId (id), mMessage (message), mHint (hint) {} +CSMTools::ReportModel::ReportModel (bool fieldColumn) +{ + if (fieldColumn) + { + mColumnField = 3; + mColumnDescription = 4; + } + else + { + mColumnDescription = 3; + + mColumnField = -1; + } +} int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const { @@ -22,7 +39,7 @@ int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const if (parent.isValid()) return 0; - return 4; + return mColumnDescription+1; } QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const @@ -46,15 +63,32 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const return QString ("-"); } - case Column_Description: - - return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); - case Column_Hint: return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); } + if (index.column()==mColumnDescription) + return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); + + if (index.column()==mColumnField) + { + std::string field; + + std::istringstream stream (mRows.at (index.row()).mHint); + + char type, ignore; + int fieldIndex; + + if ((stream >> type >> ignore >> fieldIndex) && type=='r') + { + field = CSMWorld::Columns::getName ( + static_cast (fieldIndex)); + } + + return QString::fromUtf8 (field.c_str()); + } + return QVariant(); } @@ -70,9 +104,14 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta { case Column_Type: return "Type"; case Column_Id: return "ID"; - case Column_Description: return "Description"; } + if (section==mColumnDescription) + return "Description"; + + if (section==mColumnField) + return "Field"; + return "-"; } diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 5f39316aa0..7e733fab65 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -26,13 +26,20 @@ namespace CSMTools std::vector mRows; + // Fixed columns enum Columns { - Column_Type = 0, Column_Id = 1, Column_Hint = 2, Column_Description = 3 + Column_Type = 0, Column_Id = 1, Column_Hint = 2 }; + // Configurable columns + int mColumnDescription; + int mColumnField; + public: + ReportModel (bool fieldColumn = false); + virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; virtual int columnCount (const QModelIndex & parent = QModelIndex()) const; diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 2d3e4f952b..a0eb429b09 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -27,7 +27,11 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); std::ostringstream hint; - hint << "r: " << index.column() << " " << pos << " " << search.length(); + hint + << "r: " + << model->getColumnId (index.column()) + << " " << pos + << " " << search.length(); messages.add (id, message.str(), hint.str()); diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 957e202960..970a8ac4fe 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -147,7 +147,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier() CSMWorld::UniversalId CSMTools::Tools::newSearch() { - mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); + mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true))); return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); } From 46ccd27a6de028a4e7459a850f26f413289d9011 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 18:16:43 +0200 Subject: [PATCH 18/35] improved find result text --- apps/opencs/model/tools/search.cpp | 48 ++++++++++++++++++------------ apps/opencs/model/tools/search.hpp | 2 +- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index a0eb429b09..9f1beb0642 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -23,9 +23,6 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, while ((pos = text.indexOf (search, pos, Qt::CaseInsensitive))!=-1) { - std::ostringstream message; - message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); - std::ostringstream hint; hint << "r: " @@ -33,7 +30,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, << " " << pos << " " << search.length(); - messages.add (id, message.str(), hint.str()); + messages.add (id, formatDescription (text, pos, search.length()).toUtf8().data(), hint.str()); pos += search.length(); } @@ -49,15 +46,12 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, while ((pos = mRegExp.indexIn (text, pos))!=-1) { - std::ostringstream message; - message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); - int length = mRegExp.matchedLength(); std::ostringstream hint; - hint << "r: " << index.column() << " " << pos << " " << length; + hint << "r: " << model->getColumnId (index.column()) << " " << pos << " " << length; - messages.add (id, message.str(), hint.str()); + messages.add (id, formatDescription (text, pos, length).toUtf8().data(), hint.str()); pos += length; } @@ -74,26 +68,42 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); std::ostringstream message; - message << getLocation (model, index, id) << states.at (data); + message << states.at (data); std::ostringstream hint; - hint << "r: " << index.column(); + hint << "r: " << model->getColumnId (index.column()); messages.add (id, message.str(), hint.str()); } } -std::string CSMTools::Search::getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const +QString CSMTools::Search::formatDescription (const QString& description, int pos, int length) const { - std::ostringstream stream; + int padding = 10; ///< \todo make this configurable + + if (posheaderData (index.column(), Qt::Horizontal).toString().toUtf8().data() - << ": "; + QString text = description.mid (pos, length); + + // compensate for Windows nonsense + text.remove ('\r'); - return stream.str(); + // improve layout for single line display + text.replace ("\n", ""); + text.replace ('\t', ' '); + + return text; } CSMTools::Search::Search() : mType (Type_None) {} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 81b8840bf4..320323f037 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -56,7 +56,7 @@ namespace CSMTools const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; - std::string getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const; + QString formatDescription (const QString& description, int pos, int length) const; public: From 6d165dabb64ab1475cdec15c99435019530b5622 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 18:21:18 +0200 Subject: [PATCH 19/35] improved layout of report table --- apps/opencs/view/tools/reporttable.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 5eb375f46f..5bf1fa8487 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -71,6 +71,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, : CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) { horizontalHeader()->setResizeMode (QHeaderView::Interactive); + horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); setSortingEnabled (true); setSelectionBehavior (QAbstractItemView::SelectRows); From 4928e3705f7695199efa18406306e25fa04a9c0e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 30 Mar 2015 12:52:08 +0200 Subject: [PATCH 20/35] highlight (bold) search string in results --- apps/opencs/model/tools/search.cpp | 41 +++++++++++++----------- apps/opencs/model/tools/search.hpp | 4 ++- apps/opencs/view/tools/reportsubview.cpp | 2 +- apps/opencs/view/tools/reporttable.cpp | 39 +++++++++++++++++++++- apps/opencs/view/tools/reporttable.hpp | 3 +- apps/opencs/view/tools/searchsubview.cpp | 2 +- 6 files changed, 68 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 9f1beb0642..e2bab38662 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -79,31 +79,36 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model QString CSMTools::Search::formatDescription (const QString& description, int pos, int length) const { - int padding = 10; ///< \todo make this configurable - - if (pos" + highlight + "" + after; + // improve layout for single line display - text.replace ("\n", ""); + text.replace ("\n", "<CR>"); text.replace ('\t', ' '); - return text; + return text; +} + +QString CSMTools::Search::flatten (const QString& text) const +{ + QString flat (text); + + flat.replace ("&", "&"); + flat.replace ("<", "<"); + + return flat; } CSMTools::Search::Search() : mType (Type_None) {} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 320323f037..0148beab3d 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -57,7 +57,9 @@ namespace CSMTools CSMDoc::Messages& messages) const; QString formatDescription (const QString& description, int pos, int length) const; - + + QString flatten (const QString& text) const; + public: Search(); diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index df1a5298cd..492874c01b 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -6,7 +6,7 @@ CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : CSVDoc::SubView (id) { - setWidget (mTable = new ReportTable (document, id, this)); + setWidget (mTable = new ReportTable (document, id, false, this)); connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 5bf1fa8487..73fee23626 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -6,11 +6,45 @@ #include #include #include +#include +#include +#include #include "../../model/tools/reportmodel.hpp" #include "../../view/world/idtypedelegate.hpp" +namespace CSVTools +{ + class RichTextDelegate : public QStyledItemDelegate + { + public: + + RichTextDelegate (QObject *parent = 0); + + virtual void paint(QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + }; +} + +CSVTools::RichTextDelegate::RichTextDelegate (QObject *parent) : QStyledItemDelegate (parent) +{} + +void CSVTools::RichTextDelegate::paint(QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QTextDocument document; + QVariant value = index.data (Qt::DisplayRole); + if (value.isValid() && !value.isNull()) + { + document.setHtml (value.toString()); + painter->translate (option.rect.topLeft()); + document.drawContents (painter); + painter->translate (-option.rect.topLeft()); + } +} + + void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) { QModelIndexList selectedRows = selectionModel()->selectedRows(); @@ -67,7 +101,7 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) } CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, - const CSMWorld::UniversalId& id, QWidget *parent) + const CSMWorld::UniversalId& id, bool richTextDescription, QWidget *parent) : CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) { horizontalHeader()->setResizeMode (QHeaderView::Interactive); @@ -85,6 +119,9 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, setItemDelegateForColumn (0, mIdTypeDelegate); + if (richTextDescription) + setItemDelegateForColumn (mModel->columnCount()-1, new RichTextDelegate (this)); + mShowAction = new QAction (tr ("Show"), this); connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection())); addAction (mShowAction); diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 4b686f2d48..dde6cc634d 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -36,8 +36,9 @@ namespace CSVTools public: + /// \param richTextDescription Use rich text in the description column. ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, - QWidget *parent = 0); + bool richTextDescription, QWidget *parent = 0); virtual std::vector getDraggedRecords() const; diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 4afed2c907..146b94ef44 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -17,7 +17,7 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: layout->addWidget (&mSearchBox); - layout->addWidget (mTable = new ReportTable (document, id), 2); + layout->addWidget (mTable = new ReportTable (document, id, true), 2); QWidget *widget = new QWidget; From cb6caf5e39da6b42fb46ab25edf58ebe1eb5c704 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 30 Mar 2015 22:30:33 +0200 Subject: [PATCH 21/35] added search-related user settings --- apps/opencs/model/settings/usersettings.cpp | 15 +++++++++++++++ apps/opencs/model/tools/search.cpp | 21 +++++++++++++-------- apps/opencs/model/tools/search.hpp | 4 ++++ apps/opencs/view/tools/searchsubview.cpp | 16 ++++++++++++++-- apps/opencs/view/tools/searchsubview.hpp | 2 ++ 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 7dac660c35..7a975c99c4 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -208,6 +208,21 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in table:

" + toolTip); } + declareSection ("search", "Search & Replace"); + { + Setting *before = createSetting (Type_SpinBox, "char-before", + "Characters before search string"); + before->setDefaultValue (10); + before->setRange (0, 1000); + before->setToolTip ("Maximum number of character to display in search result before the searched text"); + + Setting *after = createSetting (Type_SpinBox, "char-after", + "Characters after search string"); + after->setDefaultValue (10); + after->setRange (0, 1000); + after->setToolTip ("Maximum number of character to display in search result after the searched text"); + } + { /****************************************************************** * There are three types of values: diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index e2bab38662..28d92f06a1 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -85,11 +85,10 @@ QString CSMTools::Search::formatDescription (const QString& description, int pos text.remove ('\r'); // split - int padding = 10; ///< \todo make this configurable - QString highlight = flatten (text.mid (pos, length)); - QString before = flatten (padding<=pos ? text.mid (0, pos) : text.mid (pos-padding, padding)); - QString after = flatten (text.mid (pos+length, padding)); + QString before = flatten (mPaddingBefore<=pos ? + text.mid (0, pos) : text.mid (pos-mPaddingBefore, mPaddingBefore)); + QString after = flatten (text.mid (pos+length, mPaddingAfter)); // join text = before + "" + highlight + "" + after; @@ -111,24 +110,24 @@ QString CSMTools::Search::flatten (const QString& text) const return flat; } -CSMTools::Search::Search() : mType (Type_None) {} +CSMTools::Search::Search() : mType (Type_None), mPaddingBefore (10), mPaddingAfter (10) {} CSMTools::Search::Search (Type type, const std::string& value) -: mType (type), mText (value) +: mType (type), mText (value), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_Text && type!=Type_Id) throw std::logic_error ("Invalid search parameter (string)"); } CSMTools::Search::Search (Type type, const QRegExp& value) -: mType (type), mRegExp (value) +: mType (type), mRegExp (value), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_TextRegEx && type!=Type_IdRegEx) throw std::logic_error ("Invalid search parameter (RegExp)"); } CSMTools::Search::Search (Type type, int value) -: mType (type), mValue (value) +: mType (type), mValue (value), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_RecordState) throw std::logic_error ("invalid search parameter (int)"); @@ -230,3 +229,9 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, } } } + +void CSMTools::Search::setPadding (int before, int after) +{ + mPaddingBefore = before; + mPaddingAfter = after; +} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 0148beab3d..452b3cad29 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -45,6 +45,8 @@ namespace CSMTools std::set mColumns; int mIdColumn; int mTypeColumn; + int mPaddingBefore; + int mPaddingAfter; void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; @@ -78,6 +80,8 @@ namespace CSMTools // \attention *this needs to be configured for \a model. void searchRow (const CSMWorld::IdTableBase *model, int row, CSMDoc::Messages& messages) const; + + void setPadding (int before, int after); }; } diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 146b94ef44..36fd65a2b4 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -4,12 +4,13 @@ #include #include "../../model/doc/document.hpp" +#include "../../model/tools/search.hpp" #include "reporttable.hpp" #include "searchbox.hpp" CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id), mDocument (document) +: CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10) { QVBoxLayout *layout = new QVBoxLayout; @@ -45,6 +46,14 @@ void CSVTools::SearchSubView::setEditLock (bool locked) void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) { mTable->updateUserSetting (name, list); + + if (!list.empty()) + { + if (name=="search/char-before") + mPaddingBefore = list.at (0).toInt(); + else if (name=="search/char-after") + mPaddingAfter = list.at (0).toInt(); + } } void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *document) @@ -54,6 +63,9 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { + CSMTools::Search search2 (search); + search2.setPadding (mPaddingBefore, mPaddingAfter); + mTable->clear(); - mDocument.runSearch (getUniversalId(), search); + mDocument.runSearch (getUniversalId(), search2); } diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index d17f7a3407..b9b24f774c 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -24,6 +24,8 @@ namespace CSVTools ReportTable *mTable; SearchBox mSearchBox; CSMDoc::Document& mDocument; + int mPaddingBefore; + int mPaddingAfter; public: From 66c866aec945b0c74939d1c1a317407e9c0bff11 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 31 Mar 2015 13:02:12 +0200 Subject: [PATCH 22/35] fixed search result formatting --- apps/opencs/model/tools/search.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 28d92f06a1..db495be11a 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -81,15 +81,15 @@ QString CSMTools::Search::formatDescription (const QString& description, int pos { QString text (description); - // compensate for Windows nonsense - text.remove ('\r'); - // split QString highlight = flatten (text.mid (pos, length)); - QString before = flatten (mPaddingBefore<=pos ? + QString before = flatten (mPaddingBefore>=pos ? text.mid (0, pos) : text.mid (pos-mPaddingBefore, mPaddingBefore)); QString after = flatten (text.mid (pos+length, mPaddingAfter)); + // compensate for Windows nonsense + text.remove ('\r'); + // join text = before + "" + highlight + "" + after; From a9a8b5ad475bfbd80e0f5a390f849083d8507168 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 31 Mar 2015 14:25:27 +0200 Subject: [PATCH 23/35] improved performance of CSVRender::Cell::addObjects by bypassing Qt model --- apps/opencs/view/render/cell.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index ae2fad95ad..a030ea11f8 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -10,6 +10,7 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" +#include "../../model/world/refcollection.hpp" #include "../world/physicssystem.hpp" #include "elements.hpp" @@ -30,26 +31,19 @@ bool CSVRender::Cell::removeObject (const std::string& id) bool CSVRender::Cell::addObjects (int start, int end) { - CSMWorld::IdTable& references = dynamic_cast ( - *mData.getTableModel (CSMWorld::UniversalId::Type_References)); - - int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id); - int cellColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Cell); - int stateColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Modification); - bool modified = false; + const CSMWorld::RefCollection& collection = mData.getReferences(); + for (int i=start; i<=end; ++i) { - std::string cell = Misc::StringUtils::lowerCase (references.data ( - references.index (i, cellColumn)).toString().toUtf8().constData()); + std::string cell = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mCell); - int state = references.data (references.index (i, stateColumn)).toInt(); + CSMWorld::RecordBase::State state = collection.getRecord (i).mState; if (cell==mId && state!=CSMWorld::RecordBase::State_Deleted) { - std::string id = Misc::StringUtils::lowerCase (references.data ( - references.index (i, idColumn)).toString().toUtf8().constData()); + std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId); mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); modified = true; From 7c9104a29123a428138b7315ac2db3ef43f6d1f7 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Tue, 31 Mar 2015 22:02:08 -0400 Subject: [PATCH 24/35] fix -Wnewline-eof --- libs/openengine/misc/rng.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/openengine/misc/rng.cpp b/libs/openengine/misc/rng.cpp index 140aa337eb..3d50400df0 100644 --- a/libs/openengine/misc/rng.cpp +++ b/libs/openengine/misc/rng.cpp @@ -26,4 +26,4 @@ namespace Misc { } } -} \ No newline at end of file +} From d646836cddf54624fa14ce7ace4b1b050b3f2a23 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Wed, 1 Apr 2015 21:44:41 -0400 Subject: [PATCH 25/35] turn on -Wno-potentially-evaluated-expression on clang --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 342fb7e390..07fffd5776 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -353,6 +353,14 @@ endif() if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") + if (CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE) + execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE CLANG_VERSION) + string(REGEX REPLACE ".*version ([0-9\\.]*).*" "\\1" CLANG_VERSION ${CLANG_VERSION}) + if ("${CLANG_VERSION}" VERSION_GREATER 3.6 OR "${CLANG_VERSION}" VERSION_EQUAL 3.6) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-potentially-evaluated-expression") + endif ("${CLANG_VERSION}" VERSION_GREATER 3.6 OR "${CLANG_VERSION}" VERSION_EQUAL 3.6) + endif(CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) From 6b6bed520d82061c1b401e9aabf617db9d17d309 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 3 Apr 2015 13:45:13 +1300 Subject: [PATCH 26/35] removed redundant calls. --- apps/openmw/mwgui/quickkeysmenu.cpp | 1 - apps/openmw/mwgui/spellwindow.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 8f595df803..834c156f92 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -548,7 +548,6 @@ namespace MWGui WindowModal::open(); mMagicList->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); - mMagicList->update(); } void MagicSelectionDialog::onModelIndexSelected(SpellModel::ModelIndex index) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index cc032691e2..4fdeb91cfb 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -65,7 +65,6 @@ namespace MWGui mSpellIcons->updateWidgets(mEffectBox, false); mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); - mSpellView->update(); } void SpellWindow::onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped) @@ -170,7 +169,6 @@ namespace MWGui void SpellWindow::cycle(bool next) { mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); - mSpellView->getModel()->update(); SpellModel::ModelIndex selected = 0; for (SpellModel::ModelIndex i = 0; igetModel()->getItemCount()); ++i) From 52de622e9732d6dd3c36e22f0cd3562f52221f2d Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 3 Apr 2015 17:59:13 +1300 Subject: [PATCH 27/35] provide incremental update of SpellWindow (Fixes #2411) When SpellWindow is visible, every 0.5 seconds update the cost/changes for spells/enchanted items shown. Also, check to see if more substantial update of the window is required. --- apps/openmw/mwgui/spellview.cpp | 95 +++++++++++++++++++++++++------ apps/openmw/mwgui/spellview.hpp | 17 +++++- apps/openmw/mwgui/spellwindow.cpp | 15 +++++ apps/openmw/mwgui/spellwindow.hpp | 5 +- 4 files changed, 113 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 668b239bc2..eeadc1d818 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -10,6 +10,8 @@ namespace MWGui { + const char* SpellView::sSpellModelIndex = "SpellModelIndex"; + SpellView::SpellView() : mShowCostColumn(true) , mHighlightSelected(true) @@ -113,10 +115,10 @@ namespace MWGui group.push_back(costChance); Gui::SharedStateButton::createButtonGroup(group); - mLines.push_back(std::make_pair(t, costChance)); + mLines.push_back(boost::make_tuple(t, costChance, true)); } else - mLines.push_back(std::make_pair(t, (MyGUI::Widget*)NULL)); + mLines.push_back(boost::make_tuple(t, (MyGUI::Widget*)NULL, true)); t->setStateSelected(spell.mSelected); } @@ -124,30 +126,85 @@ namespace MWGui layoutWidgets(); } + void SpellView::incrementalUpdate() + { + if (!mModel.get()) + { + return; + } + + mModel->update(); + bool fullUpdateRequired = false; + SpellModel::ModelIndex maxSpellIndexFound = -1; + for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) + { + // only update the lines that are "updateable" + if (it->get<2>()) + { + Gui::SharedStateButton* nameButton = reinterpret_cast(it->get<0>()); + + // match model against line + // if don't match, then major change has happened, so do a full update + SpellModel::ModelIndex spellIndex = getSpellModelIndex(nameButton); + if (mModel->getItemCount() <= static_cast(spellIndex)) + { + fullUpdateRequired = true; + break; + } + + // more checking for major change. + const Spell& spell = mModel->getItem(spellIndex); + if (nameButton->getCaption() != spell.mName) + { + fullUpdateRequired = true; + break; + } + else + { + maxSpellIndexFound = spellIndex; + Gui::SharedStateButton* costButton = reinterpret_cast(it->get<1>()); + if ((costButton != NULL) && (costButton->getCaption() != spell.mCostColumn)) + { + costButton->setCaption(spell.mCostColumn); + } + } + } + } + + // special case, look for spells added to model that are beyond last updatable item + SpellModel::ModelIndex topSpellIndex = mModel->getItemCount() - 1; + if (fullUpdateRequired || + ((0 <= topSpellIndex) && (maxSpellIndexFound < topSpellIndex))) + { + update(); + } + } + + void SpellView::layoutWidgets() { int height = 0; - for (std::vector< std::pair >::iterator it = mLines.begin(); + for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - height += (it->first)->getHeight(); + height += (it->get<0>())->getHeight(); } bool scrollVisible = height > mScrollView->getHeight(); int width = mScrollView->getWidth() - (scrollVisible ? 18 : 0); height = 0; - for (std::vector< std::pair >::iterator it = mLines.begin(); + for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - int lineHeight = (it->first)->getHeight(); - (it->first)->setCoord(4, height, width-8, lineHeight); - if (it->second) + int lineHeight = (it->get<0>())->getHeight(); + (it->get<0>())->setCoord(4, height, width - 8, lineHeight); + if (it->get<1>()) { - (it->second)->setCoord(4, height, width-8, lineHeight); - MyGUI::TextBox* second = (it->second)->castType(false); + (it->get<1>())->setCoord(4, height, width - 8, lineHeight); + MyGUI::TextBox* second = (it->get<1>())->castType(false); if (second) - (it->first)->setSize(width-8-second->getTextSize().width, lineHeight); + (it->get<0>())->setSize(width - 8 - second->getTextSize().width, lineHeight); } height += lineHeight; @@ -167,7 +224,7 @@ namespace MWGui MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 18), MyGUI::Align::Left | MyGUI::Align::Top); separator->setNeedMouseFocus(false); - mLines.push_back(std::make_pair(separator, (MyGUI::Widget*)NULL)); + mLines.push_back(boost::make_tuple(separator, (MyGUI::Widget*)NULL, false)); } MyGUI::TextBox* groupWidget = mScrollView->createWidget("SandBrightText", @@ -186,10 +243,10 @@ namespace MWGui groupWidget2->setTextAlign(MyGUI::Align::Right); groupWidget2->setNeedMouseFocus(false); - mLines.push_back(std::make_pair(groupWidget, groupWidget2)); + mLines.push_back(boost::make_tuple(groupWidget, groupWidget2, false)); } else - mLines.push_back(std::make_pair(groupWidget, (MyGUI::Widget*)NULL)); + mLines.push_back(boost::make_tuple(groupWidget, (MyGUI::Widget*)NULL, false)); } @@ -222,16 +279,20 @@ namespace MWGui widget->setUserString("Spell", spell.mId); } - widget->setUserString("SpellModelIndex", MyGUI::utility::toString(index)); + widget->setUserString(sSpellModelIndex, MyGUI::utility::toString(index)); widget->eventMouseWheel += MyGUI::newDelegate(this, &SpellView::onMouseWheel); widget->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellView::onSpellSelected); } + SpellModel::ModelIndex SpellView::getSpellModelIndex(MyGUI::Widget* widget) + { + return MyGUI::utility::parseInt(widget->getUserString(sSpellModelIndex)); + } + void SpellView::onSpellSelected(MyGUI::Widget* _sender) { - SpellModel::ModelIndex i = MyGUI::utility::parseInt(_sender->getUserString("SpellModelIndex")); - eventSpellClicked(i); + eventSpellClicked(getSpellModelIndex(_sender)); } void SpellView::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 005d206f4d..2f6ff26248 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_GUI_SPELLVIEW_H #define OPENMW_GUI_SPELLVIEW_H +#include + #include #include "spellmodel.hpp" @@ -37,6 +39,9 @@ namespace MWGui void update(); + /// simplified update called each frame + void incrementalUpdate(); + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_ModelIndex; /// Fired when a spell was clicked EventHandle_ModelIndex eventSpellClicked; @@ -51,7 +56,13 @@ namespace MWGui std::auto_ptr mModel; - std::vector< std::pair > mLines; + /// tracks an item in the spell view + /// element<0> is the left column GUI object (usually holds the name) + /// element<1> is the right column (charge or cost info) + /// element<2> is if line needs to be checked during incremental update + typedef boost::tuple LineInfo; + + std::vector< LineInfo > mLines; bool mShowCostColumn; bool mHighlightSelected; @@ -62,6 +73,10 @@ namespace MWGui void onSpellSelected(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); + + SpellModel::ModelIndex getSpellModelIndex(MyGUI::Widget* _sender); + + static const char* sSpellModelIndex; }; } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 4fdeb91cfb..ca5ec20bdf 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -28,6 +28,7 @@ namespace MWGui : WindowPinnableBase("openmw_spell_window.layout") , NoDrop(drag, mMainWidget) , mSpellView(NULL) + , mUpdateTimer(0.0f) { mSpellIcons = new SpellIcons(); @@ -60,6 +61,20 @@ namespace MWGui updateSpells(); } + void SpellWindow::onFrame(float dt) + { + if (mMainWidget->getVisible()) + { + NoDrop::onFrame(dt); + mUpdateTimer += dt; + if (0.5f < mUpdateTimer) + { + mUpdateTimer = 0; + mSpellView->incrementalUpdate(); + } + } + } + void SpellWindow::updateSpells() { mSpellIcons->updateWidgets(mEffectBox, false); diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 8b5474f58c..dcce10f9da 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -19,7 +19,7 @@ namespace MWGui void updateSpells(); - void onFrame(float dt) { NoDrop::onFrame(dt); } + void onFrame(float dt); /// Cycle to next/previous spell void cycle(bool next); @@ -41,6 +41,9 @@ namespace MWGui SpellView* mSpellView; SpellIcons* mSpellIcons; + + private: + float mUpdateTimer; }; } From 3b408b64276ffdb1dcad81112d3c8fe17b0da710 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 4 Apr 2015 19:55:53 +0200 Subject: [PATCH 28/35] sorting out some Display enum mixup --- apps/opencs/model/world/columnbase.cpp | 5 ++--- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columnimp.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/model/world/resourcetable.cpp | 2 +- apps/opencs/view/world/scriptsubview.cpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index a736c01551..4f51fcad68 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -66,6 +66,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_JournalInfo, Display_Scene, Display_GlobalVariable, + Display_Script, Display_Mesh, Display_Icon, @@ -74,8 +75,6 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Texture, Display_Video, - Display_Id, - Display_None }; @@ -93,5 +92,5 @@ bool CSMWorld::ColumnBase::isText (Display display) bool CSMWorld::ColumnBase::isScript (Display display) { - return display==Display_Script || display==Display_ScriptLines; + return display==Display_ScriptFile || display==Display_ScriptLines; } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 38039c27c0..6f67898f66 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -101,6 +101,7 @@ namespace CSMWorld Display_Texture, Display_Video, Display_Colour, + Display_ScriptFile, Display_ScriptLines, // console context Display_SoundGeneratorType, Display_School, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 47b744b7f3..e67fdd59c8 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -818,7 +818,7 @@ namespace CSMWorld ScriptColumn (Type type) : Column (Columns::ColumnId_ScriptText, - type==Type_File ? ColumnBase::Display_Script : ColumnBase::Display_ScriptLines, + type==Type_File ? ColumnBase::Display_ScriptFile : ColumnBase::Display_ScriptLines, type==Type_File ? 0 : ColumnBase::Flag_Dialogue) {} diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 14a8890ad1..6963c13311 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -40,7 +40,7 @@ CSMWorld::RefIdCollection::RefIdCollection() { BaseColumns baseColumns; - mColumns.push_back (RefIdColumn (Columns::ColumnId_Id, ColumnBase::Display_String, + mColumns.push_back (RefIdColumn (Columns::ColumnId_Id, ColumnBase::Display_Id, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false)); baseColumns.mId = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Modification, ColumnBase::Display_RecordState, diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 36e2b3f3db..2cd44781ab 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -60,7 +60,7 @@ QVariant CSMWorld::ResourceTable::headerData (int section, Qt::Orientation orien return Columns::getName (Columns::ColumnId_Id).c_str(); if (role==ColumnBase::Role_Display) - return ColumnBase::Display_String; + return ColumnBase::Display_Id; break; diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 9b50a61f89..d0c3c25595 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -22,7 +22,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: for (int i=0; icolumnCount(); ++i) if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)== - CSMWorld::ColumnBase::Display_Script) + CSMWorld::ColumnBase::Display_ScriptFile) { mColumn = i; break; From fe69dc28637e0cc2e61f6bbcbaba5b5c82a1d912 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Apr 2015 14:56:29 +1200 Subject: [PATCH 29/35] Made LineInfo a struct, as requested by Scrawl. --- apps/openmw/mwgui/spellview.cpp | 40 ++++++++++++++++++++------------- apps/openmw/mwgui/spellview.hpp | 22 +++++++++++++----- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index eeadc1d818..a7c1d781bd 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -12,6 +12,14 @@ namespace MWGui const char* SpellView::sSpellModelIndex = "SpellModelIndex"; + SpellView::LineInfo::LineInfo(MyGUI::Widget* leftWidget, MyGUI::Widget* rightWidget, SpellModel::ModelIndex spellIndex) + : mLeftWidget(leftWidget) + , mRightWidget(rightWidget) + , mSpellIndex(spellIndex) + { + + } + SpellView::SpellView() : mShowCostColumn(true) , mHighlightSelected(true) @@ -115,10 +123,10 @@ namespace MWGui group.push_back(costChance); Gui::SharedStateButton::createButtonGroup(group); - mLines.push_back(boost::make_tuple(t, costChance, true)); + mLines.push_back(LineInfo(t, costChance, i)); } else - mLines.push_back(boost::make_tuple(t, (MyGUI::Widget*)NULL, true)); + mLines.push_back(LineInfo(t, (MyGUI::Widget*)NULL, i)); t->setStateSelected(spell.mSelected); } @@ -139,13 +147,13 @@ namespace MWGui for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { // only update the lines that are "updateable" - if (it->get<2>()) + SpellModel::ModelIndex spellIndex(it->mSpellIndex); + if (spellIndex != NoSpellIndex) { - Gui::SharedStateButton* nameButton = reinterpret_cast(it->get<0>()); + Gui::SharedStateButton* nameButton = reinterpret_cast(it->mLeftWidget); // match model against line // if don't match, then major change has happened, so do a full update - SpellModel::ModelIndex spellIndex = getSpellModelIndex(nameButton); if (mModel->getItemCount() <= static_cast(spellIndex)) { fullUpdateRequired = true; @@ -162,7 +170,7 @@ namespace MWGui else { maxSpellIndexFound = spellIndex; - Gui::SharedStateButton* costButton = reinterpret_cast(it->get<1>()); + Gui::SharedStateButton* costButton = reinterpret_cast(it->mRightWidget); if ((costButton != NULL) && (costButton->getCaption() != spell.mCostColumn)) { costButton->setCaption(spell.mCostColumn); @@ -187,7 +195,7 @@ namespace MWGui for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - height += (it->get<0>())->getHeight(); + height += (it->mLeftWidget)->getHeight(); } bool scrollVisible = height > mScrollView->getHeight(); @@ -197,14 +205,14 @@ namespace MWGui for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - int lineHeight = (it->get<0>())->getHeight(); - (it->get<0>())->setCoord(4, height, width - 8, lineHeight); - if (it->get<1>()) + int lineHeight = (it->mLeftWidget)->getHeight(); + (it->mLeftWidget)->setCoord(4, height, width - 8, lineHeight); + if (it->mRightWidget) { - (it->get<1>())->setCoord(4, height, width - 8, lineHeight); - MyGUI::TextBox* second = (it->get<1>())->castType(false); + (it->mRightWidget)->setCoord(4, height, width - 8, lineHeight); + MyGUI::TextBox* second = (it->mRightWidget)->castType(false); if (second) - (it->get<0>())->setSize(width - 8 - second->getTextSize().width, lineHeight); + (it->mLeftWidget)->setSize(width - 8 - second->getTextSize().width, lineHeight); } height += lineHeight; @@ -224,7 +232,7 @@ namespace MWGui MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 18), MyGUI::Align::Left | MyGUI::Align::Top); separator->setNeedMouseFocus(false); - mLines.push_back(boost::make_tuple(separator, (MyGUI::Widget*)NULL, false)); + mLines.push_back(LineInfo(separator, (MyGUI::Widget*)NULL, NoSpellIndex)); } MyGUI::TextBox* groupWidget = mScrollView->createWidget("SandBrightText", @@ -243,10 +251,10 @@ namespace MWGui groupWidget2->setTextAlign(MyGUI::Align::Right); groupWidget2->setNeedMouseFocus(false); - mLines.push_back(boost::make_tuple(groupWidget, groupWidget2, false)); + mLines.push_back(LineInfo(groupWidget, groupWidget2, NoSpellIndex)); } else - mLines.push_back(boost::make_tuple(groupWidget, (MyGUI::Widget*)NULL, false)); + mLines.push_back(LineInfo(groupWidget, (MyGUI::Widget*)NULL, NoSpellIndex)); } diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 2f6ff26248..7af1bda7a7 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -56,11 +56,23 @@ namespace MWGui std::auto_ptr mModel; - /// tracks an item in the spell view - /// element<0> is the left column GUI object (usually holds the name) - /// element<1> is the right column (charge or cost info) - /// element<2> is if line needs to be checked during incremental update - typedef boost::tuple LineInfo; + /// tracks a row in the spell view + struct LineInfo + { + /// the widget on the left side of the row + MyGUI::Widget* mLeftWidget; + + /// the widget on the left side of the row (if there is one) + MyGUI::Widget* mRightWidget; + + /// index to item in mModel that row is showing information for + SpellModel::ModelIndex mSpellIndex; + + LineInfo(MyGUI::Widget* leftWidget, MyGUI::Widget* rightWidget, SpellModel::ModelIndex spellIndex); + }; + + /// magic number indicating LineInfo does not correspond to an item in mModel + enum { NoSpellIndex = -1 }; std::vector< LineInfo > mLines; From 0a5de33a1a6e7bd2ddd0848677e7f9827a2fe60b Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 6 Apr 2015 15:13:09 +1200 Subject: [PATCH 30/35] fireEquipmentChangedEvent() updates the InventoryWindow. (Fixes #2424) --- apps/openmw/mwworld/inventorystore.cpp | 19 ++++++++++++++----- apps/openmw/mwworld/inventorystore.hpp | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 4503e66f58..2de3abc750 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -10,6 +10,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwgui/inventorywindow.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" @@ -175,7 +178,7 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite flagAsModified(); - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); } @@ -188,7 +191,7 @@ void MWWorld::InventoryStore::unequipAll(const MWWorld::Ptr& actor) mUpdatesEnabled = true; - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); } @@ -318,7 +321,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) if (changed) { mSlots.swap (slots_); - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); flagAsModified(); } @@ -549,7 +552,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c } } - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); return retval; @@ -576,12 +579,18 @@ void MWWorld::InventoryStore::setListener(InventoryStoreListener *listener, cons updateMagicEffects(actor); } -void MWWorld::InventoryStore::fireEquipmentChangedEvent() +void MWWorld::InventoryStore::fireEquipmentChangedEvent(const Ptr& actor) { if (!mUpdatesEnabled) return; if (mListener) mListener->equipmentChanged(); + + // if player, update inventory window + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); + } } void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisitor &visitor) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 9a154373a1..6b906207e1 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -111,7 +111,7 @@ namespace MWWorld void updateMagicEffects(const Ptr& actor); void updateRechargingItems(); - void fireEquipmentChangedEvent(); + void fireEquipmentChangedEvent(const Ptr& actor); virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); From 3f4f008c5132689974b4085238311224eba34beb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 10 Apr 2015 13:27:34 +0200 Subject: [PATCH 31/35] another fix to display type handling --- apps/opencs/model/world/columnbase.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 4f51fcad68..17e4def2fc 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -75,6 +75,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Texture, Display_Video, + Display_Id, + Display_None }; From 4951fc477ca0ee0bee330f280ba613483d80a176 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Apr 2015 18:50:22 +0200 Subject: [PATCH 32/35] added replace function --- apps/opencs/model/tools/reportmodel.cpp | 17 +++++- apps/opencs/model/tools/reportmodel.hpp | 4 +- apps/opencs/model/tools/search.cpp | 68 +++++++++++++++++++----- apps/opencs/model/tools/search.hpp | 12 +++-- apps/opencs/view/tools/reporttable.cpp | 59 +++++++++++++++++++- apps/opencs/view/tools/reporttable.hpp | 10 ++++ apps/opencs/view/tools/searchbox.cpp | 46 +++++++++++++--- apps/opencs/view/tools/searchbox.hpp | 6 +++ apps/opencs/view/tools/searchsubview.cpp | 37 +++++++++++-- apps/opencs/view/tools/searchsubview.hpp | 5 ++ 10 files changed, 234 insertions(+), 30 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 627199c22f..5648ace549 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -80,7 +80,7 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const char type, ignore; int fieldIndex; - if ((stream >> type >> ignore >> fieldIndex) && type=='r') + if ((stream >> type >> ignore >> fieldIndex) && (type=='r' || type=='R')) { field = CSMWorld::Columns::getName ( static_cast (fieldIndex)); @@ -135,6 +135,21 @@ void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::str endInsertRows(); } +void CSMTools::ReportModel::flagAsReplaced (int index) +{ + Line& line = mRows.at (index); + std::string hint = line.mHint; + + if (hint.empty() || hint[0]!='R') + throw std::logic_error ("trying to flag message as replaced that is not replaceable"); + + hint[0] = 'r'; + + line.mHint = hint; + + emit dataChanged (this->index (index, 0), this->index (index, columnCount())); +} + const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const { return mRows.at (row).mId; diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 7e733fab65..4d2d0542f5 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -49,10 +49,12 @@ namespace CSMTools virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); - + void add (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint = ""); + void flagAsReplaced (int index); + const CSMWorld::UniversalId& getUniversalId (int row) const; std::string getHint (int row) const; diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index db495be11a..cb88507547 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -4,14 +4,16 @@ #include #include -#include "../../model/doc/messages.hpp" +#include "../doc/messages.hpp" +#include "../doc/document.hpp" -#include "../../model/world/idtablebase.hpp" -#include "../../model/world/columnbase.hpp" -#include "../../model/world/universalid.hpp" +#include "../world/idtablebase.hpp" +#include "../world/columnbase.hpp" +#include "../world/universalid.hpp" +#include "../world/commands.hpp" void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const { // using QString here for easier handling of case folding. @@ -25,7 +27,8 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, { std::ostringstream hint; hint - << "r: " + << (writable ? 'R' : 'r') + <<": " << model->getColumnId (index.column()) << " " << pos << " " << search.length(); @@ -37,7 +40,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, } void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const { QString text = model->data (index).toString(); @@ -49,7 +52,12 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, int length = mRegExp.matchedLength(); std::ostringstream hint; - hint << "r: " << model->getColumnId (index.column()) << " " << pos << " " << length; + hint + << (writable ? 'R' : 'r') + <<": " + << model->getColumnId (index.column()) + << " " << pos + << " " << length; messages.add (id, formatDescription (text, pos, length).toUtf8().data(), hint.str()); @@ -58,8 +66,11 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, } void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const { + if (writable) + throw std::logic_error ("Record state can not be modified by search and replace"); + int data = model->data (index).toInt(); if (data==mValue) @@ -203,24 +214,26 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, CSMWorld::UniversalId id ( type, model->data (model->index (row, mIdColumn)).toString().toUtf8().data()); - + + bool writable = model->flags (index) & Qt::ItemIsEditable; + switch (mType) { case Type_Text: case Type_Id: - searchTextCell (model, index, id, messages); + searchTextCell (model, index, id, writable, messages); break; case Type_TextRegEx: case Type_IdRegEx: - searchRegExCell (model, index, id, messages); + searchRegExCell (model, index, id, writable, messages); break; case Type_RecordState: - searchRecordStateCell (model, index, id, messages); + searchRecordStateCell (model, index, id, writable, messages); break; case Type_None: @@ -235,3 +248,32 @@ void CSMTools::Search::setPadding (int before, int after) mPaddingBefore = before; mPaddingAfter = after; } + +void CSMTools::Search::replace (CSMDoc::Document& document, CSMWorld::IdTableBase *model, + const CSMWorld::UniversalId& id, const std::string& messageHint, + const std::string& replaceText) const +{ + std::istringstream stream (messageHint.c_str()); + + char hint, ignore; + int columnId, pos, length; + + if (stream >> hint >> ignore >> columnId >> pos >> length) + { + int column = + model->findColumnIndex (static_cast (columnId)); + + QModelIndex index = model->getModelIndex (id.getId(), column); + + std::string text = model->data (index).toString().toUtf8().constData(); + + std::string before = text.substr (0, pos); + std::string after = text.substr (pos+length); + + std::string newText = before + replaceText + after; + + document.getUndoStack().push ( + new CSMWorld::ModifyCommand (*model, index, QString::fromUtf8 (newText.c_str()))); + } +} + diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 452b3cad29..c9dfc4c446 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -12,6 +12,7 @@ class QModelIndex; namespace CSMDoc { class Messages; + class Document; } namespace CSMWorld @@ -49,13 +50,13 @@ namespace CSMTools int mPaddingAfter; void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const; void searchRegExCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const; void searchRecordStateCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const; QString formatDescription (const QString& description, int pos, int length) const; @@ -82,6 +83,11 @@ namespace CSMTools CSMDoc::Messages& messages) const; void setPadding (int before, int after); + + // Configuring *this for the model is not necessary when calling this function. + void replace (CSMDoc::Document& document, CSMWorld::IdTableBase *model, + const CSMWorld::UniversalId& id, const std::string& messageHint, + const std::string& replaceText) const; }; } diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 73fee23626..1b07d3c0f6 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -56,8 +56,25 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) { menu.addAction (mShowAction); menu.addAction (mRemoveAction); - } + bool found = false; + for (QModelIndexList::const_iterator iter (selectedRows.begin()); + iter!=selectedRows.end(); ++iter) + { + QString hint = mModel->data (mModel->index (iter->row(), 2)).toString(); + + if (!hint.isEmpty() && hint[0]=='R') + { + found = true; + break; + } + } + + if (found) + menu.addAction (mReplaceAction); + + } + menu.exec (event->globalPos()); } @@ -129,6 +146,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, mRemoveAction = new QAction (tr ("Remove from list"), this); connect (mRemoveAction, SIGNAL (triggered()), this, SLOT (removeSelection())); addAction (mRemoveAction); + + mReplaceAction = new QAction (tr ("Replace"), this); + connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest())); + addAction (mReplaceAction); } std::vector CSVTools::ReportTable::getDraggedRecords() const @@ -151,6 +172,42 @@ void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStrin mIdTypeDelegate->updateUserSetting (name, list); } +std::vector CSVTools::ReportTable::getReplaceIndices (bool selection) const +{ + std::vector indices; + + if (selection) + { + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); + ++iter) + { + QString hint = mModel->data (mModel->index (iter->row(), 2)).toString(); + + if (!hint.isEmpty() && hint[0]=='R') + indices.push_back (iter->row()); + } + } + else + { + for (int i=0; irowCount(); ++i) + { + QString hint = mModel->data (mModel->index (i, 2)).toString(); + + if (!hint.isEmpty() && hint[0]=='R') + indices.push_back (i); + } + } + + return indices; +} + +void CSVTools::ReportTable::flagAsReplaced (int index) +{ + mModel->flagAsReplaced (index); +} + void CSVTools::ReportTable::showSelection() { QModelIndexList selectedRows = selectionModel()->selectedRows(); diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index dde6cc634d..c4d5b414ea 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -25,6 +25,7 @@ namespace CSVTools CSVWorld::CommandDelegate *mIdTypeDelegate; QAction *mShowAction; QAction *mRemoveAction; + QAction *mReplaceAction; private: @@ -46,6 +47,13 @@ namespace CSVTools void clear(); + // Return indices of rows that are suitable for replacement. + // + // \param selection Only list selected rows. + std::vector getReplaceIndices (bool selection) const; + + void flagAsReplaced (int index); + private slots: void showSelection(); @@ -55,6 +63,8 @@ namespace CSVTools signals: void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); + + void replaceRequest(); }; } diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 178dd1f041..1e92acb75e 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -38,6 +38,9 @@ void CSVTools::SearchBox::updateSearchButton() CSVTools::SearchBox::SearchBox (QWidget *parent) : QWidget (parent), mSearch ("Search"), mSearchEnabled (false) { + mLayout = new QGridLayout (this); + + // search panel std::vector states = CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); states.resize (states.size()-1); // ignore erased state @@ -46,8 +49,6 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) ++iter) mRecordState.addItem (QString::fromUtf8 (iter->c_str())); - mLayout = new QGridLayout (this); - mMode.addItem ("Text"); mMode.addItem ("Text (RegEx)"); mMode.addItem ("ID"); @@ -61,13 +62,8 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) mInput.insertWidget (0, &mText); mInput.insertWidget (1, &mRecordState); - mLayout->addWidget (&mInput, 0, 1); - - mLayout->setColumnMinimumWidth (2, 50); - mLayout->setColumnStretch (1, 1); + mLayout->addWidget (&mInput, 0, 1); - mLayout->setContentsMargins (0, 0, 0, 0); - connect (&mMode, SIGNAL (activated (int)), this, SLOT (modeSelected (int))); connect (&mText, SIGNAL (textChanged (const QString&)), @@ -76,7 +72,20 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) connect (&mSearch, SIGNAL (clicked (bool)), this, SLOT (startSearch (bool))); connect (&mText, SIGNAL (returnPressed()), this, SLOT (startSearch())); + + // replace panel + mReplaceInput.insertWidget (0, &mReplaceText); + mReplaceInput.insertWidget (1, &mReplacePlaceholder); + + mLayout->addWidget (&mReplaceInput, 1, 1); + + // layout adjustments + mLayout->setColumnMinimumWidth (2, 50); + mLayout->setColumnStretch (1, 1); + + mLayout->setContentsMargins (0, 0, 0, 0); + // update modeSelected (0); updateSearchButton(); @@ -116,6 +125,25 @@ CSMTools::Search CSVTools::SearchBox::getSearch() const throw std::logic_error ("invalid search mode index"); } +std::string CSVTools::SearchBox::getReplaceText() const +{ + CSMTools::Search::Type type = static_cast (mMode.currentIndex()); + + switch (type) + { + case CSMTools::Search::Type_Text: + case CSMTools::Search::Type_TextRegEx: + case CSMTools::Search::Type_Id: + case CSMTools::Search::Type_IdRegEx: + + return mReplaceText.text().toUtf8().data(); + + default: + + throw std::logic_error ("Invalid search mode for replace"); + } +} + void CSVTools::SearchBox::modeSelected (int index) { switch (index) @@ -126,10 +154,12 @@ void CSVTools::SearchBox::modeSelected (int index) case CSMTools::Search::Type_IdRegEx: mInput.setCurrentIndex (0); + mReplaceInput.setCurrentIndex (0); break; case CSMTools::Search::Type_RecordState: mInput.setCurrentIndex (1); + mReplaceInput.setCurrentIndex (1); break; } diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp index 35c656d160..594788e6c1 100644 --- a/apps/opencs/view/tools/searchbox.hpp +++ b/apps/opencs/view/tools/searchbox.hpp @@ -6,6 +6,7 @@ #include #include #include +#include class QGridLayout; @@ -27,6 +28,9 @@ namespace CSVTools QGridLayout *mLayout; QComboBox mMode; bool mSearchEnabled; + QStackedWidget mReplaceInput; + QLineEdit mReplaceText; + QLabel mReplacePlaceholder; private: @@ -40,6 +44,8 @@ namespace CSVTools CSMTools::Search getSearch() const; + std::string getReplaceText() const; + private slots: void modeSelected (int index); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 36fd65a2b4..64827b737e 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -5,6 +5,8 @@ #include "../../model/doc/document.hpp" #include "../../model/tools/search.hpp" +#include "../../model/tools/reportmodel.hpp" +#include "../../model/world/idtablebase.hpp" #include "reporttable.hpp" #include "searchbox.hpp" @@ -31,6 +33,8 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); + connect (mTable, SIGNAL (replaceRequest()), this, SLOT (replaceRequest())); + connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (stateChanged (int, CSMDoc::Document *))); @@ -63,9 +67,36 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { - CSMTools::Search search2 (search); - search2.setPadding (mPaddingBefore, mPaddingAfter); + mSearch = search; + mSearch.setPadding (mPaddingBefore, mPaddingAfter); mTable->clear(); - mDocument.runSearch (getUniversalId(), search2); + mDocument.runSearch (getUniversalId(), mSearch); +} + +void CSVTools::SearchSubView::replaceRequest() +{ + std::vector indices = mTable->getReplaceIndices (true); + + std::string replace = mSearchBox.getReplaceText(); + + const CSMTools::ReportModel& model = + dynamic_cast (*mTable->model()); + + // We are running through the indices in reverse order to avoid messing up multiple results + // in a single string. + for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) + { + CSMWorld::UniversalId id = model.getUniversalId (*iter); + + CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType()); + + CSMWorld::IdTableBase *table = &dynamic_cast ( + *mDocument.getData().getTableModel (type)); + + std::string hint = model.getHint (*iter); + + mSearch.replace (mDocument, table, id, hint, replace); + mTable->flagAsReplaced (*iter); + } } diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index b9b24f774c..125d0b9276 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -1,6 +1,8 @@ #ifndef CSV_TOOLS_SEARCHSUBVIEW_H #define CSV_TOOLS_SEARCHSUBVIEW_H +#include "../../model/tools/search.hpp" + #include "../doc/subview.hpp" #include "searchbox.hpp" @@ -26,6 +28,7 @@ namespace CSVTools CSMDoc::Document& mDocument; int mPaddingBefore; int mPaddingAfter; + CSMTools::Search mSearch; public: @@ -40,6 +43,8 @@ namespace CSVTools void stateChanged (int state, CSMDoc::Document *document); void startSearch (const CSMTools::Search& search); + + void replaceRequest(); }; } From 36ce2d61f4aa9afccdceeb9e327ab5393080f37c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Apr 2015 19:02:03 +0200 Subject: [PATCH 33/35] consider lock mode when replacing --- apps/opencs/view/tools/searchsubview.cpp | 8 ++++++-- apps/opencs/view/tools/searchsubview.hpp | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 64827b737e..0bdb9d6585 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -12,7 +12,8 @@ #include "searchbox.hpp" CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10) +: CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10), + mLocked (false) { QVBoxLayout *layout = new QVBoxLayout; @@ -44,7 +45,7 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: void CSVTools::SearchSubView::setEditLock (bool locked) { - // ignored. We don't change document state anyway. + mLocked = false; } void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) @@ -76,6 +77,9 @@ void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) void CSVTools::SearchSubView::replaceRequest() { + if (mLocked) + return; + std::vector indices = mTable->getReplaceIndices (true); std::string replace = mSearchBox.getReplaceText(); diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index 125d0b9276..59fbfe66e0 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -29,6 +29,7 @@ namespace CSVTools int mPaddingBefore; int mPaddingAfter; CSMTools::Search mSearch; + bool mLocked; public: From b939fd440ee2ac3a4c1d3d91c8733bfb72694fef Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Apr 2015 20:11:14 +0200 Subject: [PATCH 34/35] added replace all button --- apps/opencs/view/tools/searchbox.cpp | 16 +++++- apps/opencs/view/tools/searchbox.hpp | 7 +++ apps/opencs/view/tools/searchsubview.cpp | 65 ++++++++++++++---------- apps/opencs/view/tools/searchsubview.hpp | 6 +++ 4 files changed, 67 insertions(+), 27 deletions(-) diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 1e92acb75e..ca55207875 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -36,7 +36,7 @@ void CSVTools::SearchBox::updateSearchButton() } CSVTools::SearchBox::SearchBox (QWidget *parent) -: QWidget (parent), mSearch ("Search"), mSearchEnabled (false) +: QWidget (parent), mSearch ("Search"), mSearchEnabled (false), mReplace ("Replace All") { mLayout = new QGridLayout (this); @@ -78,12 +78,16 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) mReplaceInput.insertWidget (1, &mReplacePlaceholder); mLayout->addWidget (&mReplaceInput, 1, 1); + + mLayout->addWidget (&mReplace, 1, 3); // layout adjustments mLayout->setColumnMinimumWidth (2, 50); mLayout->setColumnStretch (1, 1); mLayout->setContentsMargins (0, 0, 0, 0); + + connect (&mReplace, (SIGNAL (clicked (bool))), this, SLOT (replaceAll (bool))); // update modeSelected (0); @@ -144,6 +148,11 @@ std::string CSVTools::SearchBox::getReplaceText() const } } +void CSVTools::SearchBox::setEditLock (bool locked) +{ + mReplace.setEnabled (!locked); +} + void CSVTools::SearchBox::modeSelected (int index) { switch (index) @@ -176,3 +185,8 @@ void CSVTools::SearchBox::startSearch (bool checked) if (mSearch.isEnabled()) emit startSearch (getSearch()); } + +void CSVTools::SearchBox::replaceAll (bool checked) +{ + emit replaceAll(); +} diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp index 594788e6c1..433c096936 100644 --- a/apps/opencs/view/tools/searchbox.hpp +++ b/apps/opencs/view/tools/searchbox.hpp @@ -31,6 +31,7 @@ namespace CSVTools QStackedWidget mReplaceInput; QLineEdit mReplaceText; QLabel mReplacePlaceholder; + QPushButton mReplace; private: @@ -46,6 +47,8 @@ namespace CSVTools std::string getReplaceText() const; + void setEditLock (bool locked); + private slots: void modeSelected (int index); @@ -54,9 +57,13 @@ namespace CSVTools void startSearch (bool checked = true); + void replaceAll (bool checked); + signals: void startSearch (const CSMTools::Search& search); + + void replaceAll(); }; } diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 0bdb9d6585..5743ad7614 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -11,6 +11,36 @@ #include "reporttable.hpp" #include "searchbox.hpp" +void CSVTools::SearchSubView::replace (bool selection) +{ + if (mLocked) + return; + + std::vector indices = mTable->getReplaceIndices (selection); + + std::string replace = mSearchBox.getReplaceText(); + + const CSMTools::ReportModel& model = + dynamic_cast (*mTable->model()); + + // We are running through the indices in reverse order to avoid messing up multiple results + // in a single string. + for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) + { + CSMWorld::UniversalId id = model.getUniversalId (*iter); + + CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType()); + + CSMWorld::IdTableBase *table = &dynamic_cast ( + *mDocument.getData().getTableModel (type)); + + std::string hint = model.getHint (*iter); + + mSearch.replace (mDocument, table, id, hint, replace); + mTable->flagAsReplaced (*iter); + } +} + CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10), mLocked (false) @@ -41,11 +71,14 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (&mSearchBox, SIGNAL (startSearch (const CSMTools::Search&)), this, SLOT (startSearch (const CSMTools::Search&))); + + connect (&mSearchBox, SIGNAL (replaceAll()), this, SLOT (replaceAllRequest())); } void CSVTools::SearchSubView::setEditLock (bool locked) { - mLocked = false; + mLocked = locked; + mSearchBox.setEditLock (locked); } void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) @@ -77,30 +110,10 @@ void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) void CSVTools::SearchSubView::replaceRequest() { - if (mLocked) - return; - - std::vector indices = mTable->getReplaceIndices (true); - - std::string replace = mSearchBox.getReplaceText(); - - const CSMTools::ReportModel& model = - dynamic_cast (*mTable->model()); - - // We are running through the indices in reverse order to avoid messing up multiple results - // in a single string. - for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) - { - CSMWorld::UniversalId id = model.getUniversalId (*iter); - - CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType()); + replace (true); +} - CSMWorld::IdTableBase *table = &dynamic_cast ( - *mDocument.getData().getTableModel (type)); - - std::string hint = model.getHint (*iter); - - mSearch.replace (mDocument, table, id, hint, replace); - mTable->flagAsReplaced (*iter); - } +void CSVTools::SearchSubView::replaceAllRequest() +{ + replace (false); } diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index 59fbfe66e0..eeefa9afbf 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -31,6 +31,10 @@ namespace CSVTools CSMTools::Search mSearch; bool mLocked; + private: + + void replace (bool selection); + public: SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); @@ -46,6 +50,8 @@ namespace CSVTools void startSearch (const CSMTools::Search& search); void replaceRequest(); + + void replaceAllRequest(); }; } From 4607c4b5816e151bca2af6237ed51a682f148c8e Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 18 Apr 2015 15:33:49 +1200 Subject: [PATCH 35/35] Add Modified DateTime to plug-in tooltip. (Fixes #2479) --- components/contentselector/model/esmfile.cpp | 7 ++++--- components/contentselector/model/esmfile.hpp | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/contentselector/model/esmfile.cpp b/components/contentselector/model/esmfile.cpp index 1ac1c75008..46a7c96008 100644 --- a/components/contentselector/model/esmfile.cpp +++ b/components/contentselector/model/esmfile.cpp @@ -6,9 +6,10 @@ int ContentSelectorModel::EsmFile::sPropertyCount = 7; QString ContentSelectorModel::EsmFile::sToolTip = QString("Author: %1
\ Version: %2
\ - Path:
%3
\ -
Description:
%4
\ -
Dependencies: %5
"); + Modified: %3
\ + Path:
%4
\ +
Description:
%5
\ +
Dependencies: %6
"); ContentSelectorModel::EsmFile::EsmFile(QString fileName, ModelItem *parent) diff --git a/components/contentselector/model/esmfile.hpp b/components/contentselector/model/esmfile.hpp index d0cebab3c6..614eee2987 100644 --- a/components/contentselector/model/esmfile.hpp +++ b/components/contentselector/model/esmfile.hpp @@ -59,6 +59,7 @@ namespace ContentSelectorModel inline QString description() const { return mDescription; } inline QString toolTip() const { return sToolTip.arg(mAuthor) .arg(mFormat) + .arg(mModified.toString(Qt::ISODate)) .arg(mPath) .arg(mDescription) .arg(mGameFiles.join(", "));