diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 621b9bf86..b2b534031 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -60,11 +60,12 @@ opencs_hdrs_noqt (view/doc opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool - scenetoolmode infocreator scriptedit + scenetoolmode infocreator scriptedit dialoguesubview previewsubview ) opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget + previewwidget ) opencs_units_noqt (view/render @@ -72,8 +73,7 @@ opencs_units_noqt (view/render ) opencs_units_noqt (view/world - dialoguesubview subviews - enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate + subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate scripthighlighter idvalidator dialoguecreator ) @@ -147,6 +147,9 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) +set(BOOST_COMPONENTS system filesystem program_options thread wave) +find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) + find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) include(${QT_USE_FILE}) @@ -187,6 +190,8 @@ if(APPLE) endif(APPLE) target_link_libraries(opencs + ${OGRE_LIBRARIES} + ${SHINY_LIBRARIES} ${Boost_LIBRARIES} ${QT_LIBRARIES} components diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 2b2f41754..942780c32 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -9,8 +9,13 @@ #include #include +#include +#include + #include +#include + #include "model/doc/document.hpp" #include "model/world/data.hpp" @@ -18,14 +23,17 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) : mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mIpcServerName ("org.openmw.OpenCS") { - Files::PathContainer dataDirs = readConfig(); + std::pair > config = readConfig(); - setupDataFiles (dataDirs); + setupDataFiles (config.first); CSMSettings::UserSettings::instance().loadSettings ("opencs.cfg"); ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); + Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, + mFsStrict); + mNewGame.setLocalData (mLocal); mFileDialog.setLocalData (mLocal); @@ -58,7 +66,7 @@ void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) } } -Files::PathContainer CS::Editor::readConfig() +std::pair > CS::Editor::readConfig() { boost::program_options::variables_map variables; boost::program_options::options_description desc("Syntax: opencs \nAllowed options"); @@ -68,13 +76,17 @@ Files::PathContainer CS::Editor::readConfig() ("data-local", boost::program_options::value()->default_value("")) ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) ("encoding", boost::program_options::value()->default_value("win1252")) - ("resources", boost::program_options::value()->default_value("resources")); + ("resources", boost::program_options::value()->default_value("resources")) + ("fallback-archive", boost::program_options::value >()-> + default_value(std::vector(), "fallback-archive")->multitoken()); boost::program_options::notify(variables); mCfgMgr.readConfiguration(variables, desc); - mDocumentManager.setResourceDir (variables["resources"].as()); + mDocumentManager.setResourceDir (mResources = variables["resources"].as()); + + mFsStrict = variables["fs-strict"].as(); Files::PathContainer dataDirs, dataLocal; if (!variables["data"].empty()) { @@ -105,7 +117,7 @@ Files::PathContainer CS::Editor::readConfig() dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end()); - return dataDirs; + return std::make_pair (dataDirs, variables["fallback-archive"].as >()); } void CS::Editor::createGame() @@ -216,6 +228,15 @@ int CS::Editor::run() if (mLocal.empty()) return 1; + mStartup.show(); + + QApplication::setQuitOnLastWindowClosed (true); + + return QApplication::exec(); +} + +std::auto_ptr CS::Editor::setupGraphics() +{ // TODO: setting Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem")); @@ -233,9 +254,36 @@ int CS::Editor::run() Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms); hiddenWindow->setActive(false); - mStartup.show(); + sh::OgrePlatform* platform = + new sh::OgrePlatform ("General", (mResources / "materials").string()); - QApplication::setQuitOnLastWindowClosed (true); + if (!boost::filesystem::exists (mCfgMgr.getCachePath())) + boost::filesystem::create_directories (mCfgMgr.getCachePath()); - return QApplication::exec(); + platform->setCacheFolder (mCfgMgr.getCachePath().string()); + + std::auto_ptr factory (new sh::Factory (platform)); + + factory->setCurrentLanguage (sh::Language_GLSL); /// \todo make this configurable + factory->setWriteSourceCache (true); + factory->setReadSourceCache (true); + factory->setReadMicrocodeCache (true); + factory->setWriteMicrocodeCache (true); + + factory->loadAllFiles(); + + sh::Factory::getInstance().setGlobalSetting ("fog", "true"); + + sh::Factory::getInstance().setGlobalSetting ("shadows", "false"); + sh::Factory::getInstance().setGlobalSetting ("shadows_pssm", "false"); + + sh::Factory::getInstance ().setGlobalSetting ("render_refraction", "false"); + + sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); + + sh::Factory::getInstance ().setGlobalSetting ("num_lights", "8"); + + /// \todo add more configurable shiny settings + + return factory; } diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 0f1c7a682..164398fb7 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -1,11 +1,15 @@ #ifndef CS_EDITOR_H #define CS_EDITOR_H +#include + #include #include #include #include +#include + #ifndef Q_MOC_RUN #include #endif @@ -41,12 +45,13 @@ namespace CS CSVDoc::NewGameDialogue mNewGame; CSVSettings::UserSettingsDialog mSettings; CSVDoc::FileDialog mFileDialog; - boost::filesystem::path mLocal; + boost::filesystem::path mResources; + bool mFsStrict; void setupDataFiles (const Files::PathContainer& dataDirs); - Files::PathContainer readConfig(); + std::pair > readConfig(); ///< \return data paths // not implemented @@ -63,6 +68,9 @@ namespace CS int run(); ///< \return error status + std::auto_ptr setupGraphics(); + ///< The returned factory must persist at least as long as *this. + private slots: void createGame(); diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 212ed0836..eded36394 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include #ifdef Q_OS_MAC @@ -42,6 +44,8 @@ int main(int argc, char *argv[]) OgreInit::OgreInit ogreInit; + std::auto_ptr shinyFactory; + Application application (argc, argv); #ifdef Q_OS_MAC @@ -73,5 +77,7 @@ int main(int argc, char *argv[]) // return 0; } + shinyFactory = editor.setupGraphics(); + return editor.run(); } diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 34bad20cc..f6363fe2e 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -17,4 +17,9 @@ bool CSMWorld::ColumnBase::isUserEditable() const std::string CSMWorld::ColumnBase::getTitle() const { return Columns::getName (static_cast (mColumnId)); +} + +int CSMWorld::ColumnBase::getId() const +{ + return mColumnId; } \ No newline at end of file diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index e04333608..fe310d0aa 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -28,6 +28,7 @@ namespace CSMWorld { Display_None, //Do not use Display_String, + Display_LongString, //CONCRETE TYPES STARTS HERE Display_Skill, @@ -105,6 +106,8 @@ namespace CSMWorld ///< Can this column be edited directly by the user? virtual std::string getTitle() const; + + virtual int getId() const; }; template diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index def225018..ccbeaf694 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -202,7 +202,7 @@ namespace CSMWorld struct DescriptionColumn : public Column { DescriptionColumn() - : Column (Columns::ColumnId_Description, ColumnBase::Display_String) + : Column (Columns::ColumnId_Description, ColumnBase::Display_LongString) {} virtual QVariant get (const Record& record) const @@ -834,7 +834,7 @@ namespace CSMWorld virtual bool isUserEditable() const { - return false; + return true; } }; @@ -1114,7 +1114,7 @@ namespace CSMWorld virtual bool isUserEditable() const { - return false; + return true; } }; @@ -1380,7 +1380,7 @@ namespace CSMWorld template struct QuestDescriptionColumn : public Column { - QuestDescriptionColumn() : Column (Columns::ColumnId_QuestDescription, ColumnBase::Display_String) {} + QuestDescriptionColumn() : Column (Columns::ColumnId_QuestDescription, ColumnBase::Display_LongString) {} virtual QVariant get (const Record& record) const { @@ -1560,7 +1560,7 @@ namespace CSMWorld template struct ResponseColumn : public Column { - ResponseColumn() : Column (Columns::ColumnId_Response, ColumnBase::Display_String) {} + ResponseColumn() : Column (Columns::ColumnId_Response, ColumnBase::Display_LongString) {} virtual QVariant get (const Record& record) const { diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d68b79ff0..d60dcae11 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -250,9 +250,9 @@ CSMWorld::Data::Data() : mRefs (mCells) addModel (new IdTable (&mTopicInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_TopicInfos, UniversalId::Type_TopicInfo); addModel (new IdTable (&mJournalInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_JournalInfos, UniversalId::Type_JournalInfo); addModel (new IdTable (&mCells, IdTable::Reordering_None, IdTable::Viewing_Id), UniversalId::Type_Cells, UniversalId::Type_Cell); - addModel (new IdTable (&mReferenceables), UniversalId::Type_Referenceables, - UniversalId::Type_Referenceable); - addModel (new IdTable (&mRefs, IdTable::Reordering_None, IdTable::Viewing_Cell), UniversalId::Type_References, UniversalId::Type_Reference, false); + addModel (new IdTable (&mReferenceables, IdTable::Reordering_None, IdTable::Viewing_None, true), + UniversalId::Type_Referenceables, UniversalId::Type_Referenceable); + addModel (new IdTable (&mRefs, IdTable::Reordering_None, IdTable::Viewing_Cell, true), UniversalId::Type_References, UniversalId::Type_Reference, false); addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter, false); } diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 453a7da6a..50998c36f 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -5,8 +5,8 @@ #include "columnbase.hpp" CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering, - Viewing viewing) -: mIdCollection (idCollection), mReordering (reordering), mViewing (viewing) + Viewing viewing, bool preview) +: mIdCollection (idCollection), mReordering (reordering), mViewing (viewing), mPreview (preview) {} CSMWorld::IdTable::~IdTable() @@ -196,6 +196,11 @@ CSMWorld::IdTable::Viewing CSMWorld::IdTable::getViewing() const return mViewing; } +bool CSMWorld::IdTable::hasPreview() const +{ + return mPreview; +} + std::pair CSMWorld::IdTable::view (int row) const { std::string id; @@ -230,4 +235,9 @@ std::pair CSMWorld::IdTable::view (int row) id = "sys::default"; return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint); +} + +int CSMWorld::IdTable::getColumnId(int column) const +{ + return mIdCollection->getColumn(column).getId(); } \ No newline at end of file diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 5a271de44..8b5462825 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -39,6 +39,7 @@ namespace CSMWorld CollectionBase *mIdCollection; Reordering mReordering; Viewing mViewing; + bool mPreview; // not implemented IdTable (const IdTable&); @@ -47,7 +48,7 @@ namespace CSMWorld public: IdTable (CollectionBase *idCollection, Reordering reordering = Reordering_None, - Viewing viewing = Viewing_None); + Viewing viewing = Viewing_None, bool preview = false); ///< The ownership of \a idCollection is not transferred. virtual ~IdTable(); @@ -100,9 +101,13 @@ namespace CSMWorld Viewing getViewing() const; + bool hasPreview() const; + std::pair view (int row) const; ///< Return the UniversalId and the hint for viewing \a row. If viewing is not /// supported by this table, return (UniversalId::Type_None, ""). + + int getColumnId(int column) const; }; } diff --git a/apps/opencs/model/world/tablemimedata.cpp b/apps/opencs/model/world/tablemimedata.cpp index b56c9c8c2..9dcecf3bc 100644 --- a/apps/opencs/model/world/tablemimedata.cpp +++ b/apps/opencs/model/world/tablemimedata.cpp @@ -443,4 +443,9 @@ CSMWorld::ColumnBase::Display CSMWorld::TableMimeData::convertEnums (CSMWorld::U default: return CSMWorld::ColumnBase::Display_None; } +} + +const CSMDoc::Document* CSMWorld::TableMimeData::getDocumentPtr() const +{ + return &mDocument; } \ No newline at end of file diff --git a/apps/opencs/model/world/tablemimedata.hpp b/apps/opencs/model/world/tablemimedata.hpp index 7687f3555..44ac0f5f6 100644 --- a/apps/opencs/model/world/tablemimedata.hpp +++ b/apps/opencs/model/world/tablemimedata.hpp @@ -48,6 +48,8 @@ namespace CSMWorld UniversalId returnMatching(UniversalId::Type type) const; + const CSMDoc::Document* getDocumentPtr() const; + UniversalId returnMatching(CSMWorld::ColumnBase::Display type) const; static CSMWorld::UniversalId::Type convertEnums(CSMWorld::ColumnBase::Display type); diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 1d1b3c960..a62acc02b 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -92,6 +92,8 @@ namespace { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" }, { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 }, + { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", 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 0c17da03b..34167cd85 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -95,7 +95,8 @@ namespace CSMWorld Type_TopicInfo, Type_JournalInfos, Type_JournalInfo, - Type_Scene + Type_Scene, + Type_Preview }; enum { NumberOfTypes = Type_Scene+1 }; diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index 6160f2673..dcd85945f 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -18,4 +18,10 @@ void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QSt void CSVDoc::SubView::setStatusBar (bool show) {} -void CSVDoc::SubView::useHint (const std::string& hint) {} \ No newline at end of file +void CSVDoc::SubView::useHint (const std::string& hint) {} + +void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) +{ + mUniversalId = id; + setWindowTitle (mUniversalId.toString().c_str()); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 59781f869..85274a18d 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -27,6 +27,8 @@ namespace CSVDoc // not implemented SubView (const SubView&); SubView& operator= (SubView&); + protected: + void setUniversalId(const CSMWorld::UniversalId& id); public: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index de3f476af..bc34c6118 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -316,8 +316,16 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin /// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis) - SubView *view = mSubViewFactory.makeSubView (id, *mDocument); - + const std::vector referenceables(CSMWorld::UniversalId::listReferenceableTypes()); + SubView *view = NULL; + if(std::find(referenceables.begin(), referenceables.end(), id.getType()) != referenceables.end()) + { + view = mSubViewFactory.makeSubView (CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Referenceable, id.getId()), *mDocument); + } else + { + view = mSubViewFactory.makeSubView (id, *mDocument); + } + assert(view); if (!hint.empty()) view->useHint (hint); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp new file mode 100644 index 000000000..43d45f4cb --- /dev/null +++ b/apps/opencs/view/render/previewwidget.cpp @@ -0,0 +1,72 @@ + +#include "previewwidget.hpp" + +#include + +#include "../../model/world/data.hpp" + +void CSVRender::PreviewWidget::setup (const std::string& id) +{ + setNavigation (&mOrbit); + + int column = mData.getReferenceables().findColumnIndex (CSMWorld::Columns::ColumnId_Model); + + int row = mData.getReferenceables().getIndex (id); + + QVariant value = mData.getReferenceables().getData (row, column); + + if (!value.isValid()) + return; + + std::string model = value.toString().toUtf8().constData(); + + if (model.empty()) + return; + + mNode = getSceneManager()->getRootSceneNode()->createChildSceneNode(); + mNode->setPosition (Ogre::Vector3 (0, 0, 0)); + + mObject = NifOgre::Loader::createObjects (mNode, "Meshes\\" + model); +} + +void CSVRender::PreviewWidget::adjust (const std::string& id) +{ + if (mNode) + { + int row = mData.getReferences().getIndex (id); + + float scale = mData.getReferences().getData (row, mData.getReferences(). + findColumnIndex (CSMWorld::Columns::ColumnId_Scale)).toFloat(); + float rotX = mData.getReferences().getData (row, mData.getReferences(). + findColumnIndex (CSMWorld::Columns::ColumnId_PositionXRot)).toFloat(); + float rotY = mData.getReferences().getData (row, mData.getReferences(). + findColumnIndex (CSMWorld::Columns::ColumnId_PositionYRot)).toFloat(); + float rotZ = mData.getReferences().getData (row, mData.getReferences(). + findColumnIndex (CSMWorld::Columns::ColumnId_PositionZRot)).toFloat(); + + mNode->setScale (scale, scale, scale); + + Ogre::Quaternion xr (Ogre::Radian(-rotX), Ogre::Vector3::UNIT_X); + + Ogre::Quaternion yr (Ogre::Radian(-rotY), Ogre::Vector3::UNIT_Y); + + Ogre::Quaternion zr (Ogre::Radian(-rotZ), Ogre::Vector3::UNIT_Z); + + mNode->setOrientation (xr*yr*zr); + } +} + +CSVRender::PreviewWidget::PreviewWidget (const CSMWorld::Data& data, + const std::string& referenceableId, QWidget *parent) +: SceneWidget (parent), mData (data), mNode (0) +{ + setup (referenceableId); +} + +CSVRender::PreviewWidget::PreviewWidget (const CSMWorld::Data& data, + const std::string& referenceableId, const std::string& referenceId, QWidget *parent) +: SceneWidget (parent), mData (data) +{ + setup (referenceableId); + adjust (referenceId); +} diff --git a/apps/opencs/view/render/previewwidget.hpp b/apps/opencs/view/render/previewwidget.hpp new file mode 100644 index 000000000..b3abd5587 --- /dev/null +++ b/apps/opencs/view/render/previewwidget.hpp @@ -0,0 +1,46 @@ +#ifndef OPENCS_VIEW_PREVIEWWIDGET_H +#define OPENCS_VIEW_PREVIEWWIDGET_H + +#include + +#include "scenewidget.hpp" + +#include "navigationorbit.hpp" + +namespace CSMWorld +{ + class Data; +} + +namespace CSVRender +{ + class PreviewWidget : public SceneWidget + { + Q_OBJECT + + const CSMWorld::Data& mData; + CSVRender::NavigationOrbit mOrbit; + NifOgre::ObjectScenePtr mObject; + Ogre::SceneNode *mNode; + + void setup (const std::string& id); + ///< \param id ID of the referenceable to be viewed + + void adjust (const std::string& id); + ///< \param id ID of the reference to be viewed + + public: + + PreviewWidget (const CSMWorld::Data& data, const std::string& referenceableId, + QWidget *parent = 0); + + PreviewWidget (const CSMWorld::Data& data, const std::string& referenceableId, + const std::string& referenceId, QWidget *parent = 0); + + signals: + + void closeRequest(); + }; +} + +#endif diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 31d5d0318..5eec702d3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -45,15 +45,10 @@ namespace CSVRender mCamera = mSceneMgr->createCamera("foo"); - Ogre::Entity* ent = mSceneMgr->createEntity("cube", Ogre::SceneManager::PT_CUBE); - ent->setMaterialName("BaseWhite"); - - mSceneMgr->getRootSceneNode()->attachObject(ent); - - mCamera->setPosition(300,300,300); + mCamera->setPosition(300,0,000); mCamera->lookAt(0,0,0); mCamera->setNearClipDistance(0.1); - mCamera->setFarClipDistance(3000); + mCamera->setFarClipDistance(30000); QTimer *timer = new QTimer (this); @@ -118,6 +113,11 @@ namespace CSVRender } } + Ogre::SceneManager *SceneWidget::getSceneManager() + { + return mSceneMgr; + } + void SceneWidget::paintEvent(QPaintEvent* e) { if (!mWindow) diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index ad68897ac..05b06b287 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -34,6 +34,8 @@ namespace CSVRender void setNavigation (Navigation *navigation); ///< \attention The ownership of \a navigation is not transferred to *this. + Ogre::SceneManager *getSceneManager(); + private: void paintEvent(QPaintEvent* e); void resizeEvent(QResizeEvent* e); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index dcd152bb3..9959c5a67 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -1,11 +1,20 @@ #include "worldspacewidget.hpp" +#include +#include +#include + #include "../world/scenetoolmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (QWidget *parent) : SceneWidget (parent) -{} +{ + Ogre::Entity* ent = getSceneManager()->createEntity("cube", Ogre::SceneManager::PT_CUBE); + ent->setMaterialName("BaseWhite"); + + getSceneManager()->getRootSceneNode()->attachObject(ent); +} void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) { diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index cedb20de9..ae7c5923b 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -1,98 +1,663 @@ #include "dialoguesubview.hpp" +#include +#include + #include #include +#include #include #include #include #include +#include #include +#include +#include +#include +#include +#include +#include +#include #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/columns.hpp" +#include "../../model/world/record.hpp" +#include "../../model/world/tablemimedata.hpp" +#include "../../model/doc/document.hpp" +#include "../../model/world/commands.hpp" -CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, - bool createAndDelete) -: SubView (id) +#include "recordstatusdelegate.hpp" +#include "util.hpp" +#include "tablebottombox.hpp" +/* +==============================NotEditableSubDelegate========================================== +*/ +CSVWorld::NotEditableSubDelegate::NotEditableSubDelegate(const CSMWorld::IdTable* table, QObject * parent) : +QAbstractItemDelegate(parent), +mTable(table) +{} + +void CSVWorld::NotEditableSubDelegate::setEditorData (QLabel* editor, const QModelIndex& index) const { - QWidget *widget = new QWidget (this); - - setWidget (widget); - - QGridLayout *layout = new QGridLayout; - - widget->setLayout (layout); - - QAbstractItemModel *model = document.getData().getTableModel (id); - - int columns = model->columnCount(); - - mWidgetMapper = new QDataWidgetMapper (this); - mWidgetMapper->setModel (model); - - for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); - - if (flags & CSMWorld::ColumnBase::Flag_Dialogue) + v = index.data(Qt::DisplayRole); + if (!v.isValid()) { - layout->addWidget (new QLabel (model->headerData (i, Qt::Horizontal).toString()), i, 0); - - CSMWorld::ColumnBase::Display display = static_cast - (model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - - QWidget *widget = 0; - - if (model->flags (model->index (0, i)) & Qt::ItemIsEditable) - { - switch (display) - { - case CSMWorld::ColumnBase::Display_String: - - layout->addWidget (widget = new QLineEdit, i, 1); - break; - - case CSMWorld::ColumnBase::Display_Integer: - - /// \todo configure widget properly (range) - layout->addWidget (widget = new QSpinBox, i, 1); - break; - - case CSMWorld::ColumnBase::Display_Float: - - /// \todo configure widget properly (range, format?) - layout->addWidget (widget = new QDoubleSpinBox, i, 1); - break; - - default: break; // silence warnings for other times for now - } - } - else - { - switch (display) - { - case CSMWorld::ColumnBase::Display_String: - case CSMWorld::ColumnBase::Display_Integer: - case CSMWorld::ColumnBase::Display_Float: - - layout->addWidget (widget = new QLabel, i, 1); - break; - - default: break; // silence warnings for other times for now - } - } - - if (widget) - mWidgetMapper->addMapping (widget, i); + return; } } - mWidgetMapper->setCurrentModelIndex ( - dynamic_cast (*model).getModelIndex (id.getId(), 0)); + if (QVariant::String == v.type()) + { + editor->setText(v.toString()); + } else //else we are facing enums + { + int data = v.toInt(); + std::vector enumNames (CSMWorld::Columns::getEnums (static_cast (mTable->getColumnId (index.column())))); + editor->setText(QString::fromUtf8(enumNames.at(data).c_str())); + } +} + +void CSVWorld::NotEditableSubDelegate::setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const +{ + //not editable widgets will not save model data +} + +void CSVWorld::NotEditableSubDelegate::paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + //does nothing +} + +QSize CSVWorld::NotEditableSubDelegate::sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + return QSize(); +} + +QWidget* CSVWorld::NotEditableSubDelegate::createEditor (QWidget *parent, + const QStyleOptionViewItem& option, + const QModelIndex& index, + CSMWorld::ColumnBase::Display display) const +{ + return new QLabel(parent); +} + +/* +==============================DialogueDelegateDispatcherProxy========================================== +*/ +CSVWorld::DialogueDelegateDispatcherProxy::refWrapper::refWrapper(const QModelIndex& index) : +mIndex(index) +{} + +CSVWorld::DialogueDelegateDispatcherProxy::DialogueDelegateDispatcherProxy(QWidget* editor, CSMWorld::ColumnBase::Display display) : +mEditor(editor), +mDisplay(display), +mIndexWrapper(NULL) +{ +} + +void CSVWorld::DialogueDelegateDispatcherProxy::editorDataCommited() +{ + if (mIndexWrapper.get()) + { + emit editorDataCommited(mEditor, mIndexWrapper->mIndex, mDisplay); + } +} + +void CSVWorld::DialogueDelegateDispatcherProxy::setIndex(const QModelIndex& index) +{ + mIndexWrapper.reset(new refWrapper(index)); +} + +QWidget* CSVWorld::DialogueDelegateDispatcherProxy::getEditor() const +{ + return mEditor; +} + +void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std::vector& data, const CSMDoc::Document* document) +{ + QLineEdit* lineEdit = qobject_cast(mEditor); + { + if (!lineEdit or !mIndexWrapper.get()) + { + return; + } + } + for (unsigned i = 0; i < data.size(); ++i) + { + if (mDisplay == CSMWorld::TableMimeData::convertEnums(data[i].getType())) + { + emit tableMimeDataDropped(mEditor, mIndexWrapper->mIndex, data[i], document); + emit editorDataCommited(mEditor, mIndexWrapper->mIndex, mDisplay); + break; + } + } +} +/* +==============================DialogueDelegateDispatcher========================================== +*/ + +CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack) : +mParent(parent), +mTable(table), +mUndoStack(undoStack), +mNotEditableDelegate(table, parent) +{ +} + +CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CSMWorld::ColumnBase::Display display) +{ + CommandDelegate *delegate = NULL; + std::map::const_iterator delegateIt(mDelegates.find(display)); + if (delegateIt == mDelegates.end()) + { + delegate = CommandDelegateFactoryCollection::get().makeDelegate ( + display, mUndoStack, mParent); + mDelegates.insert(std::make_pair(display, delegate)); + } else + { + delegate = delegateIt->second; + } + return delegate; +} + +void CSVWorld::DialogueDelegateDispatcher::editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display) +{ + setModelData(editor, mTable, index, display); +} + +void CSVWorld::DialogueDelegateDispatcher::setEditorData (QWidget* editor, const QModelIndex& index) const +{ + CSMWorld::ColumnBase::Display display = static_cast + (mTable->headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + + QLabel* label = qobject_cast(editor); + if(label) + { + mNotEditableDelegate.setEditorData(label, index); + return; + } + + std::map::const_iterator delegateIt(mDelegates.find(display)); + if (delegateIt != mDelegates.end()) + { + delegateIt->second->setEditorData(editor, index, true); + } + + for (unsigned i = 0; i < mProxys.size(); ++i) + { + if (mProxys[i]->getEditor() == editor) + { + mProxys[i]->setIndex(index); + } + } +} + +void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const +{ + std::map::const_iterator delegateIt(mDelegates.find(display)); + if (delegateIt != mDelegates.end()) + { + delegateIt->second->setModelData(editor, model, index); + } +} + +void CSVWorld::DialogueDelegateDispatcher::paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + //Does nothing +} + +QSize CSVWorld::DialogueDelegateDispatcher::sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + return QSize(); //silencing warning, otherwise does nothing +} + +QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::Display display, const QModelIndex& index) +{ + QVariant variant = index.data(); + if (!variant.isValid()) + { + variant = index.data(Qt::DisplayRole); + if (!variant.isValid()) + { + return NULL; + } + } + + QWidget* editor = NULL; + if (! (mTable->flags (index) & Qt::ItemIsEditable)) + { + return mNotEditableDelegate.createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); + } + + std::map::iterator delegateIt(mDelegates.find(display)); + if (delegateIt != mDelegates.end()) + { + editor = delegateIt->second->createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); + DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display); + + bool skip = false; + if (qobject_cast(editor)) + { + connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); + connect(editor, SIGNAL(tableMimeDataDropped(const std::vector&, const CSMDoc::Document*)), + proxy, SLOT(tableMimeDataDropped(const std::vector&, const CSMDoc::Document*))); + connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), + this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); + skip = true; + } + if(!skip && qobject_cast(editor)) + { + connect(editor, SIGNAL(stateChanged(int)), proxy, SLOT(editorDataCommited())); + skip = true; + } + if(!skip && qobject_cast(editor)) + { + connect(editor, SIGNAL(textChanged()), proxy, SLOT(editorDataCommited())); + skip = true; + } + if(!skip && qobject_cast(editor)) + { + connect(editor, SIGNAL(currentIndexChanged (int)), proxy, SLOT(editorDataCommited())); + skip = true; + } + if(!skip && qobject_cast(editor)) + { + connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); + skip = true; + } + + connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); + mProxys.push_back(proxy); //deleted in the destructor + } + return editor; +} + +CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher() +{ + for (unsigned i = 0; i < mProxys.size(); ++i) + { + delete mProxys[i]; //unique_ptr could be handy + } +} + +/* +=============================================================EditWidget===================================================== +*/ + +CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete) : +mDispatcher(this, table, undoStack), +QScrollArea(parent), +mWidgetMapper(NULL), +mMainWidget(NULL), +mUndoStack(undoStack), +mTable(table) +{ + remake (row); + connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); +} + +void CSVWorld::EditWidget::remake(int row) +{ + if (mMainWidget) + { + delete mMainWidget; + } + mMainWidget = new QWidget (this); + + //not sure if widget mapper can handle deleting the widgets that were mapped + if (mWidgetMapper) + { + delete mWidgetMapper; + } + mWidgetMapper = new QDataWidgetMapper (this); + mWidgetMapper->setModel(mTable); + mWidgetMapper->setItemDelegate(&mDispatcher); + + QFrame* line = new QFrame(mMainWidget); + line->setObjectName(QString::fromUtf8("line")); + line->setGeometry(QRect(320, 150, 118, 3)); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + + QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget); + QGridLayout *unlockedLayout = new QGridLayout(); + QGridLayout *lockedLayout = new QGridLayout(); + mainLayout->addLayout(lockedLayout, 0); + mainLayout->addWidget(line, 1); + mainLayout->addLayout(unlockedLayout, 2); + mainLayout->addStretch(1); + + int unlocked = 0; + int locked = 0; + const int columns = mTable->columnCount(); + for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); + + if (flags & CSMWorld::ColumnBase::Flag_Dialogue) + { + CSMWorld::ColumnBase::Display display = static_cast + (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + + mDispatcher.makeDelegate(display); + QWidget *editor = mDispatcher.makeEditor(display, (mTable->index (row, i))); + + if (editor) + { + mWidgetMapper->addMapping (editor, i); + QLabel* label = new QLabel(mTable->headerData (i, Qt::Horizontal).toString(), mMainWidget); + label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + editor->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + if (! (mTable->flags (mTable->index (row, i)) & Qt::ItemIsEditable)) + { + lockedLayout->addWidget (label, locked, 0); + lockedLayout->addWidget (editor, locked, 1); + ++locked; + } else + { + unlockedLayout->addWidget (label, unlocked, 0); + unlockedLayout->addWidget (editor, unlocked, 1); + ++unlocked; + } + } + } + } + + mWidgetMapper->setCurrentModelIndex(mTable->index(row, 0)); + + this->setMinimumWidth(325); //TODO find better way to set the width or make it customizable + this->setWidget(mMainWidget); + this->setWidgetResizable(true); +} + +/* +==============================DialogueSubView========================================== +*/ + +CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, + const CreatorFactoryBase& creatorFactory, bool sorting) : + + SubView (id), + mEditWidget(0), + mMainLayout(NULL), + mUndoStack(document.getUndoStack()), + mTable(dynamic_cast(document.getData().getTableModel(id))), + mRow (-1), + mLocked(false), + mDocument(document) + +{ + connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&))); + mRow = mTable->getModelIndex (id.getId(), 0).row(); + QWidget *mainWidget = new QWidget(this); + + QHBoxLayout *buttonsLayout = new QHBoxLayout; + QToolButton* prevButton = new QToolButton(mainWidget); + prevButton->setIcon(QIcon(":/go-previous.png")); + QToolButton* nextButton = new QToolButton(mainWidget); + nextButton->setIcon(QIcon(":/go-next.png")); + buttonsLayout->addWidget(prevButton, 0); + buttonsLayout->addWidget(nextButton, 1); + buttonsLayout->addStretch(2); + + QToolButton* cloneButton = new QToolButton(mainWidget); + cloneButton->setIcon(QIcon(":/edit-clone.png")); + QToolButton* addButton = new QToolButton(mainWidget); + addButton->setIcon(QIcon(":/add.png")); + QToolButton* deleteButton = new QToolButton(mainWidget); + deleteButton->setIcon(QIcon(":/edit-delete.png")); + QToolButton* revertButton = new QToolButton(mainWidget); + revertButton->setIcon(QIcon(":/edit-undo.png")); + + if (mTable->hasPreview()) + { + QToolButton* previewButton = new QToolButton(mainWidget); + previewButton->setIcon(QIcon(":/edit-preview.png")); + buttonsLayout->addWidget(previewButton); + connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview())); + } + + if (mTable->getViewing()!=CSMWorld::IdTable::Viewing_None) + { + QToolButton* viewButton = new QToolButton(mainWidget); + viewButton->setIcon(QIcon(":/cell.png")); + buttonsLayout->addWidget(viewButton); + connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord())); + } + + buttonsLayout->addWidget(cloneButton); + buttonsLayout->addWidget(addButton); + buttonsLayout->addWidget(deleteButton); + buttonsLayout->addWidget(revertButton); + + connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId())); + connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId())); + connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest())); + connect(revertButton, SIGNAL(clicked()), this, SLOT(revertRecord())); + connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteRecord())); + + mMainLayout = new QVBoxLayout(mainWidget); + + mEditWidget = new EditWidget(mainWidget, mRow, mTable, mUndoStack, false); + connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), + this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); + + mMainLayout->addWidget(mEditWidget); + mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + + mMainLayout->addWidget (mBottom = + new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this)); + + mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&))); + connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest())); + + if(!mBottom->canCreateAndDelete()) + { + cloneButton->setDisabled(true); + addButton->setDisabled(true); + deleteButton->setDisabled(true); + } + + dataChanged(mTable->index(mRow, 0)); + mMainLayout->addLayout(buttonsLayout); + setWidget(mainWidget); +} + +void CSVWorld::DialogueSubView::prevId() +{ + int newRow = mRow - 1; + if (newRow < 0) + { + return; + } + while (newRow >= 0) + { + QModelIndex newIndex(mTable->index(newRow, 0)); + + if (!newIndex.isValid()) + { + return; + } + + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (newRow, 1)).toInt()); + if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)) + { + mEditWidget->remake(newRow); + setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), + mTable->data (mTable->index (newRow, 0)).toString().toStdString())); + mRow = newRow; + mEditWidget->setDisabled(mLocked); + return; + } + --newRow; + } +} + +void CSVWorld::DialogueSubView::nextId() +{ + int newRow = mRow + 1; + + if (newRow >= mTable->rowCount()) + { + return; + } + + while (newRow < mTable->rowCount()) + { + QModelIndex newIndex(mTable->index(newRow, 0)); + + if (!newIndex.isValid()) + { + return; + } + + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (newRow, 1)).toInt()); + if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)) + { + mEditWidget->remake(newRow); + setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), + mTable->data (mTable->index (newRow, 0)).toString().toStdString())); + mRow = newRow; + mEditWidget->setDisabled(mLocked); + return; + } + ++newRow; + } } void CSVWorld::DialogueSubView::setEditLock (bool locked) { + mLocked = locked; + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (mRow, 1)).toInt()); + if (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased) + { + mEditWidget->setDisabled(true); + } else + { + mEditWidget->setDisabled(mLocked); + } +} +void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) +{ + if (index.row() == mRow) + { + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (mRow, 1)).toInt()); + if (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased) + { + mEditWidget->setDisabled(true); + } else + { + mEditWidget->setDisabled(mLocked); + } + } +} + +void CSVWorld::DialogueSubView::tableMimeDataDropped(QWidget* editor, + const QModelIndex& index, + const CSMWorld::UniversalId& id, + const CSMDoc::Document* document) +{ + if (document == &mDocument) + { + qobject_cast(editor)->setText(id.getId().c_str()); + } +} + +void CSVWorld::DialogueSubView::revertRecord() +{ + int rows = mTable->rowCount(); + if (!mLocked && mTable->columnCount() > 0 && mRow < mTable->rowCount() ) + { + CSMWorld::RecordBase::State state = + static_cast (mTable->data (mTable->index (mRow, 1)).toInt()); + + if (state!=CSMWorld::RecordBase::State_BaseOnly) + { + mUndoStack.push(new CSMWorld::RevertCommand(*mTable, mTable->data(mTable->index (mRow, 0)).toString().toStdString())); + } + if (rows != mTable->rowCount()) + { + if (mTable->rowCount() == 0) + { + mEditWidget->setDisabled(true); //closing the editor is other option + return; + } + if (mRow >= mTable->rowCount()) + { + prevId(); + } else { + dataChanged(mTable->index(mRow, 0)); + } + } + } +} + +void CSVWorld::DialogueSubView::deleteRecord() +{ + int rows = mTable->rowCount(); + + //easier than disabling the button + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (mRow, 1)).toInt()); + bool deledetedOrErased = (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased); + + if (!mLocked && + mTable->columnCount() > 0 && + !deledetedOrErased && + mRow < rows && + mBottom->canCreateAndDelete()) + { + mUndoStack.push(new CSMWorld::DeleteCommand(*mTable, mTable->data(mTable->index (mRow, 0)).toString().toStdString())); + if (rows != mTable->rowCount()) + { + if (mTable->rowCount() == 0) + { + mEditWidget->setDisabled(true); //closing the editor is other option + return; + } + if (mRow >= mTable->rowCount()) + { + prevId(); + } else { + dataChanged(mTable->index(mRow, 0)); + } + } + } +} + +void CSVWorld::DialogueSubView::requestFocus (const std::string& id) +{ + mRow = mTable->getModelIndex (id, 0).row(); + mEditWidget->remake(mRow); +} + +void CSVWorld::DialogueSubView::cloneRequest () +{ + mBottom->cloneRequest(mTable->data(mTable->index (mRow, 0)).toString().toStdString(), + static_cast(mTable->data(mTable->index(mRow, 2)).toInt())); +} + +void CSVWorld::DialogueSubView::showPreview () +{ + if (mTable->hasPreview() && mRow < mTable->rowCount()) + { + emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mTable->data(mTable->index (mRow, 0)).toString().toStdString()), ""); + } +} + +void CSVWorld::DialogueSubView::viewRecord() +{ + if (mRow < mTable->rowCount()) + { + std::pair params = mTable->view (mRow); + + if (params.first.getType()!=CSMWorld::UniversalId::Type_None) + emit focusId (params.first, params.second); + } } \ No newline at end of file diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 64715f5b7..5642f46a0 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -1,9 +1,25 @@ #ifndef CSV_WORLD_DIALOGUESUBVIEW_H #define CSV_WORLD_DIALOGUESUBVIEW_H +#include +#include + +#include +#include + #include "../doc/subview.hpp" +#include "../../model/world/columnbase.hpp" class QDataWidgetMapper; +class QSize; +class QEvent; +class QLabel; +class QVBoxLayout; + +namespace CSMWorld +{ + class IdTable; +} namespace CSMDoc { @@ -12,15 +28,181 @@ namespace CSMDoc namespace CSVWorld { - class DialogueSubView : public CSVDoc::SubView + class CommandDelegate; + class CreatorFactoryBase; + class TableBottomBox; + + class NotEditableSubDelegate : public QAbstractItemDelegate { + const CSMWorld::IdTable* mTable; + public: + NotEditableSubDelegate(const CSMWorld::IdTable* table, QObject * parent = 0); + + virtual void setEditorData (QLabel* editor, const QModelIndex& index) const; + + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; + + virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + ///< does nothing + + virtual QSize sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const; + ///< does nothing + + virtual QWidget *createEditor (QWidget *parent, + const QStyleOptionViewItem& option, + const QModelIndex& index, + CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const; + }; + + //this can't be nested into the DialogueDelegateDispatcher, because it needs to emit signals + class DialogueDelegateDispatcherProxy : public QObject + { + Q_OBJECT + class refWrapper + { + public: + refWrapper(const QModelIndex& index); + + const QModelIndex& mIndex; + }; + + QWidget* mEditor; + + CSMWorld::ColumnBase::Display mDisplay; + + std::auto_ptr mIndexWrapper; + + public: + DialogueDelegateDispatcherProxy(QWidget* editor, CSMWorld::ColumnBase::Display display); + QWidget* getEditor() const; + + public slots: + void editorDataCommited(); + void setIndex(const QModelIndex& index); + void tableMimeDataDropped(const std::vector& data, const CSMDoc::Document* document); + + signals: + void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display); + + void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, + const CSMWorld::UniversalId& id, + const CSMDoc::Document* document); + + }; + + class DialogueDelegateDispatcher : public QAbstractItemDelegate + { + Q_OBJECT + std::map mDelegates; + + QObject* mParent; + + CSMWorld::IdTable* mTable; + + QUndoStack& mUndoStack; + + NotEditableSubDelegate mNotEditableDelegate; + + std::vector mProxys; //once we move to the C++11 we should use unique_ptr + + public: + DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack); + + ~DialogueDelegateDispatcher(); + + CSVWorld::CommandDelegate* makeDelegate(CSMWorld::ColumnBase::Display display); + + QWidget* makeEditor(CSMWorld::ColumnBase::Display display, const QModelIndex& index); + ///< will return null if delegate is not present, parent of the widget is same as for dispatcher itself + + virtual void setEditorData (QWidget* editor, const QModelIndex& index) const; + + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; + + virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + ///< does nothing + + virtual QSize sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const; + ///< does nothing + + private slots: + void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display); + + signals: + void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, + const CSMWorld::UniversalId& id, + const CSMDoc::Document* document); + + + }; + + class EditWidget : public QScrollArea + { + Q_OBJECT QDataWidgetMapper *mWidgetMapper; + DialogueDelegateDispatcher mDispatcher; + QWidget* mMainWidget; + CSMWorld::IdTable* mTable; + QUndoStack& mUndoStack; public: - DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete); + EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete = false); + + void remake(int row); + + signals: + void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, + const CSMWorld::UniversalId& id, + const CSMDoc::Document* document); + }; + + class DialogueSubView : public CSVDoc::SubView + { + Q_OBJECT + + EditWidget* mEditWidget; + QVBoxLayout* mMainLayout; + CSMWorld::IdTable* mTable; + QUndoStack& mUndoStack; + int mRow; + bool mLocked; + const CSMDoc::Document& mDocument; + TableBottomBox* mBottom; + + public: + + DialogueSubView (const CSMWorld::UniversalId& id, + CSMDoc::Document& document, + const CreatorFactoryBase& creatorFactory, + bool sorting = false); virtual void setEditLock (bool locked); + + private slots: + + void nextId(); + + void prevId(); + + void showPreview(); + + void viewRecord(); + + void revertRecord(); + + void deleteRecord(); + + void cloneRequest(); + + void dataChanged(const QModelIndex & index); + ///\brief we need to care for deleting currently edited record + + void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, + const CSMWorld::UniversalId& id, + const CSMDoc::Document* document); + + void requestFocus (const std::string& id); }; } diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index fc9b7ee3b..377f479bf 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -41,10 +41,18 @@ CSVWorld::EnumDelegate::EnumDelegate (const std::vector } -QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, - const QModelIndex& index) const +QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem& option, + const QModelIndex& index) const { - if (!index.data().isValid()) + return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); + //overloading virtual functions is HARD +} + +QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index, CSMWorld::ColumnBase::Display display) const +{ + if (!index.data(Qt::EditRole).isValid() && !index.data(Qt::DisplayRole).isValid()) return 0; QComboBox *comboBox = new QComboBox (parent); @@ -56,11 +64,22 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptio return comboBox; } -void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& index) const +void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const { if (QComboBox *comboBox = dynamic_cast (editor)) { - int value = index.data (Qt::EditRole).toInt(); + QVariant data = index.data (Qt::EditRole); + + if (tryDisplay && !data.isValid()) + { + data = index.data (Qt::DisplayRole); + if (!data.isValid()) + { + return; + } + } + + int value = data.toInt(); std::size_t size = mValues.size(); diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp index 606f9278a..cd749a451 100644 --- a/apps/opencs/view/world/enumdelegate.hpp +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -4,6 +4,7 @@ #include #include +#include #include @@ -31,10 +32,16 @@ namespace CSVWorld EnumDelegate (const std::vector >& values, QUndoStack& undoStack, QObject *parent); - virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option, - const QModelIndex& index) const; + virtual QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; - virtual void setEditorData (QWidget *editor, const QModelIndex& index) const; + virtual QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem& option, + const QModelIndex& index, + CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const; + + virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay = false) const; virtual void paint (QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp new file mode 100644 index 000000000..587af561f --- /dev/null +++ b/apps/opencs/view/world/previewsubview.cpp @@ -0,0 +1,52 @@ + +#include "previewsubview.hpp" + +#include + +#include "../render/scenewidget.hpp" + +#include "scenetoolbar.hpp" + +#include "../render/previewwidget.hpp" + +CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) +: SubView (id) +{ + QHBoxLayout *layout = new QHBoxLayout; + + layout->setContentsMargins (QMargins (0, 0, 0, 0)); + + if (document.getData().getReferenceables().searchId (id.getId())==-1) + { + std::string referenceableId = + document.getData().getReferences().getRecord (id.getId()).get().mRefID; + + setWindowTitle (("Preview: Reference to " + referenceableId).c_str()); + + mScene = + new CSVRender::PreviewWidget (document.getData(), referenceableId, id.getId(), this); + } + else + mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), this); + + SceneToolbar *toolbar = new SceneToolbar (48, this); + + layout->addWidget (toolbar, 0); + + layout->addWidget (mScene, 1); + + QWidget *widget = new QWidget; + + widget->setLayout (layout); + + setWidget (widget); + + connect (mScene, SIGNAL (closeRequest()), this, SLOT (closeRequest())); +} + +void CSVWorld::PreviewSubView::setEditLock (bool locked) {} + +void CSVWorld::PreviewSubView::closeRequest() +{ + deleteLater(); +} \ No newline at end of file diff --git a/apps/opencs/view/world/previewsubview.hpp b/apps/opencs/view/world/previewsubview.hpp new file mode 100644 index 000000000..e7a2a261e --- /dev/null +++ b/apps/opencs/view/world/previewsubview.hpp @@ -0,0 +1,36 @@ +#ifndef CSV_WORLD_PREVIEWSUBVIEW_H +#define CSV_WORLD_PREVIEWSUBVIEW_H + +#include "../doc/subview.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSVRender +{ + class PreviewWidget; +} + +namespace CSVWorld +{ + class PreviewSubView : public CSVDoc::SubView + { + Q_OBJECT + + CSVRender::PreviewWidget *mScene; + + public: + + PreviewSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + + virtual void setEditLock (bool locked); + + private slots: + + void closeRequest(); + }; +} + +#endif diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 3601ae094..66e026604 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -34,7 +34,7 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D SceneToolbar *toolbar = new SceneToolbar (48, this); - if (id.getId()[0]=='#') + if (id.getId()=="sys::default") mScene = new CSVRender::PagedWorldspaceWidget (this); else mScene = new CSVRender::UnpagedWorldspaceWidget (id.getId(), document, this); diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 74ce03cce..75f391699 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -16,6 +16,7 @@ #include "scenesubview.hpp" #include "dialoguecreator.hpp" #include "infocreator.hpp" +#include "previewsubview.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -78,4 +79,62 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CreatorFactory >); manager.add (CSMWorld::UniversalId::Type_Scene, new CSVDoc::SubViewFactory); + + //edit subviews + manager.add (CSMWorld::UniversalId::Type_Region, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Spell, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Referenceable, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Birthsign, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Global, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Gmst, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Race, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Class, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Reference, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Cell, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Filter, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Sound, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Faction, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Skill, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_JournalInfo, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_TopicInfo, + new CSVDoc::SubViewFactoryWithCreator >(false)); + + manager.add (CSMWorld::UniversalId::Type_Topic, + new CSVDoc::SubViewFactoryWithCreator (false)); + + manager.add (CSMWorld::UniversalId::Type_Journal, + new CSVDoc::SubViewFactoryWithCreator (false)); + + //preview + manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory); } \ No newline at end of file diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 4bb9955e6..cd9138c35 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -39,18 +39,6 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) if (mCreateAction) menu.addAction(mCloneAction); - - if (mModel->getViewing()!=CSMWorld::IdTable::Viewing_None) - { - int row = selectedRows.begin()->row(); - - row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row(); - - CSMWorld::UniversalId id = mModel->view (row).first; - - if (!mDocument.getData().getCells().getRecord (id.getId()).isDeleted()) - menu.addAction (mViewAction); - } } if (mCreateAction) @@ -95,6 +83,28 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) } } + if (selectedRows.size()==1) + { + if (mModel->getViewing()!=CSMWorld::IdTable::Viewing_None) + { + int row = selectedRows.begin()->row(); + + row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row(); + + CSMWorld::UniversalId id = mModel->view (row).first; + + int index = mDocument.getData().getCells().searchId (id.getId()); + // index==-1: the ID references a worldspace instead of a cell (ignore for now and go + // ahead) + + if (index==-1 || !mDocument.getData().getCells().getRecord (index).isDeleted()) + menu.addAction (mViewAction); + } + + if (mModel->hasPreview()) + menu.addAction (mPreviewAction); + } + menu.exec (event->globalPos()); } @@ -249,6 +259,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mViewAction, SIGNAL (triggered()), this, SLOT (viewRecord())); addAction (mViewAction); + mPreviewAction = new QAction (tr ("Preview"), this); + connect (mPreviewAction, SIGNAL (triggered()), this, SLOT (previewRecord())); + addAction (mPreviewAction); + connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (tableSizeUpdate())); @@ -406,7 +420,7 @@ void CSVWorld::Table::viewRecord() if (selectedRows.size()==1) { - int row =selectedRows.begin()->row(); + int row = selectedRows.begin()->row(); row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row(); @@ -417,6 +431,18 @@ void CSVWorld::Table::viewRecord() } } +void CSVWorld::Table::previewRecord() +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + if (selectedRows.size()==1) + { + std::string id = getUniversalId (selectedRows.begin()->row()).getId(); + + emit editRequest (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Preview, id) , ""); + } +} + void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue) { int columns = mModel->columnCount(); @@ -508,27 +534,14 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event) drag->setMimeData (mime); drag->setPixmap (QString::fromStdString (mime->getIcon())); - - Qt::DropActions action = Qt::IgnoreAction; - switch (QApplication::keyboardModifiers()) - { - case Qt::ControlModifier: - action = Qt::CopyAction; - break; - - case Qt::ShiftModifier: - action = Qt::MoveAction; - break; - } - - drag->exec(action); + drag->exec(Qt::CopyAction); } } void CSVWorld::Table::dragEnterEvent(QDragEnterEvent *event) { - event->acceptProposedAction(); + event->acceptProposedAction(); } void CSVWorld::Table::dropEvent(QDropEvent *event) @@ -560,7 +573,7 @@ void CSVWorld::Table::dropEvent(QDropEvent *event) void CSVWorld::Table::dragMoveEvent(QDragMoveEvent *event) { - event->accept(); + event->accept(); } std::vector CSVWorld::Table::getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index e8d5648d1..4231a4a43 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -44,6 +44,7 @@ namespace CSVWorld QAction *mMoveUpAction; QAction *mMoveDownAction; QAction *mViewAction; + QAction *mPreviewAction; CSMWorld::IdTableProxyModel *mProxyModel; CSMWorld::IdTable *mModel; bool mEditLock; @@ -111,6 +112,8 @@ namespace CSVWorld void viewRecord(); + void previewRecord(); + public slots: void tableSizeUpdate(); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 97af3b99c..227c5c9c5 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -4,8 +4,18 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "../../model/world/commands.hpp" +#include "../../model/world/tablemimedata.hpp" CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) : mModel (model) @@ -117,10 +127,56 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode } QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, - const QModelIndex& index) const + const QModelIndex& index, CSMWorld::ColumnBase::Display display) const { - if (!index.data().isValid()) - return 0; + QVariant variant = index.data(); + if (!variant.isValid()) + { + variant = index.data(Qt::DisplayRole); + if (!variant.isValid()) + { + return 0; + } + } + + if (display != CSMWorld::ColumnBase::Display_None) + { + if (variant.type() == QVariant::Color) + { + return new QLineEdit(parent); + } + if (display == CSMWorld::ColumnBase::Display_Integer) + { + return new QSpinBox(parent); + } + if (display == CSMWorld::ColumnBase::Display_Var) + { + return new QLineEdit(parent); + } + if (display == CSMWorld::ColumnBase::Display_Float) + { + return new QDoubleSpinBox(parent); + } + if (display == CSMWorld::ColumnBase::Display_LongString) + { + return new QTextEdit(parent); + } + if (display == CSMWorld::ColumnBase::Display_String || + display == CSMWorld::ColumnBase::Display_Skill || + display == CSMWorld::ColumnBase::Display_Script || + display == CSMWorld::ColumnBase::Display_Race || + display == CSMWorld::ColumnBase::Display_Class || + display == CSMWorld::ColumnBase::Display_Faction || + display == CSMWorld::ColumnBase::Display_Miscellaneous || + display == CSMWorld::ColumnBase::Display_Sound) + { + return new DropLineEdit(parent); + } + if (display == CSMWorld::ColumnBase::Display_Boolean) + { + return new QCheckBox(parent); + } + } return QStyledItemDelegate::createEditor (parent, option, index); } @@ -140,4 +196,67 @@ bool CSVWorld::CommandDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue) { return false; +} + +void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const +{ + QVariant v = index.data(Qt::EditRole); + if (tryDisplay) + { + if (!v.isValid()) + { + v = index.data(Qt::DisplayRole); + if (!v.isValid()) + { + return; + } + } + QPlainTextEdit* plainTextEdit = qobject_cast(editor); + if(plainTextEdit) //for some reason it is easier to brake the loop here + { + if(plainTextEdit->toPlainText() == v.toString()) + { + return; + } + } + } + + QByteArray n = editor->metaObject()->userProperty().name(); + + if (n == "dateTime") { + if (editor->inherits("QTimeEdit")) + n = "time"; + else if (editor->inherits("QDateEdit")) + n = "date"; + } + + if (!n.isEmpty()) { + if (!v.isValid()) + v = QVariant(editor->property(n).userType(), (const void *)0); + editor->setProperty(n, v); + } + +} + +CSVWorld::DropLineEdit::DropLineEdit(QWidget* parent) : +QLineEdit(parent) +{ + setAcceptDrops(true); +} + +void CSVWorld::DropLineEdit::dragEnterEvent(QDragEnterEvent *event) +{ + event->acceptProposedAction(); +} + +void CSVWorld::DropLineEdit::dragMoveEvent(QDragMoveEvent *event) +{ + event->accept(); +} + +void CSVWorld::DropLineEdit::dropEvent(QDropEvent *event) +{ + const CSMWorld::TableMimeData* data(dynamic_cast(event->mimeData())); + emit tableMimeDataDropped(data->getData(), data->getDocumentPtr()); + //WIP } \ No newline at end of file diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 87f118cd7..7664f3eae 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -5,11 +5,19 @@ #include #include +#include #include "../../model/world/columnbase.hpp" +#include "../../model/doc/document.hpp" class QUndoStack; +namespace CSMWorld +{ + class TableMimeData; + class UniversalId; +} + namespace CSVWorld { ///< \brief Getting the data out of an editor widget @@ -79,6 +87,24 @@ namespace CSVWorld }; + class DropLineEdit : public QLineEdit + { + Q_OBJECT + + public: + DropLineEdit(QWidget *parent); + + private: + void dragEnterEvent(QDragEnterEvent *event); + + void dragMoveEvent(QDragMoveEvent *event); + + void dropEvent(QDropEvent *event); + + signals: + void tableMimeDataDropped(const std::vector& data, const CSMDoc::Document* document); + }; + ///< \brief Use commands instead of manipulating the model directly class CommandDelegate : public QStyledItemDelegate { @@ -101,8 +127,10 @@ namespace CSVWorld virtual void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; - virtual QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem& option, - const QModelIndex& index) const; + virtual QWidget *createEditor (QWidget *parent, + const QStyleOptionViewItem& option, + const QModelIndex& index, + CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const; void setEditLock (bool locked); @@ -111,6 +139,9 @@ namespace CSVWorld virtual bool updateEditorSetting (const QString &settingName, const QString &settingValue); ///< \return Does column require update? + virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay = false) const; + + private slots: virtual void slotUpdateEditorSetting (const QString &settingName, const QString &settingValue) {} diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7d0626913..47e0d016f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -12,7 +12,7 @@ #include -#include +#include #include #include #include @@ -192,50 +192,6 @@ OMW::Engine::~Engine() SDL_Quit(); } -// Load BSA files - -void OMW::Engine::loadBSA() -{ - // We use separate resource groups to handle location priority. - const Files::PathContainer& dataDirs = mFileCollections.getPaths(); - - int i=0; - for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) - { - // Last data dir has the highest priority - std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i, 8, '0'); - Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); - - std::string dataDirectory = iter->string(); - std::cout << "Data dir " << dataDirectory << std::endl; - Bsa::addDir(dataDirectory, mFSStrict, groupName); - ++i; - } - - i=0; - for (std::vector::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive) - { - if (mFileCollections.doesExist(*archive)) - { - // Last BSA has the highest priority - std::string groupName = "DataBSA" + Ogre::StringConverter::toString(mArchives.size()-i, 8, '0'); - - Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); - - const std::string archivePath = mFileCollections.getPath(*archive).string(); - std::cout << "Adding BSA archive " << archivePath << std::endl; - Bsa::addBSA(archivePath, groupName); - ++i; - } - else - { - std::stringstream message; - message << "Archive '" << *archive << "' not found"; - throw std::runtime_error(message.str()); - } - } -} - // add resources directory // \note This function works recursively. @@ -385,8 +341,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mOgre->createWindow("OpenMW", windowSettings); - loadBSA(); - + Bsa::registerResources (mFileCollections, mArchives, true, mFSStrict); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 5c15ddf6f..e0f51d0dc 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -101,9 +101,6 @@ namespace OMW /// add a .zip resource void addZipResource (const boost::filesystem::path& path); - /// Load BSA files - void loadBSA(); - void executeLocalScripts(); virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index db4ecad0b..f8a2969f9 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -15,7 +15,7 @@ add_component_dir (nifoverrides ) add_component_dir (bsa - bsa_archive bsa_file + bsa_archive bsa_file resources ) add_component_dir (nif diff --git a/components/bsa/resources.cpp b/components/bsa/resources.cpp new file mode 100644 index 000000000..d06b3b485 --- /dev/null +++ b/components/bsa/resources.cpp @@ -0,0 +1,53 @@ + +#include "resources.hpp" + +#include + +#include +#include + +#include "bsa_archive.hpp" + +void Bsa::registerResources (const Files::Collections& collections, + const std::vector& archives, bool useLooseFiles, bool fsStrict) +{ + const Files::PathContainer& dataDirs = collections.getPaths(); + + int i=0; + + if (useLooseFiles) + for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) + { + // Last data dir has the highest priority + std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i, 8, '0'); + Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); + + std::string dataDirectory = iter->string(); + std::cout << "Data dir " << dataDirectory << std::endl; + Bsa::addDir(dataDirectory, fsStrict, groupName); + ++i; + } + + i=0; + for (std::vector::const_iterator archive = archives.begin(); archive != archives.end(); ++archive) + { + if (collections.doesExist(*archive)) + { + // Last BSA has the highest priority + std::string groupName = "DataBSA" + Ogre::StringConverter::toString(archives.size()-i, 8, '0'); + + Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); + + const std::string archivePath = collections.getPath(*archive).string(); + std::cout << "Adding BSA archive " << archivePath << std::endl; + Bsa::addBSA(archivePath, groupName); + ++i; + } + else + { + std::stringstream message; + message << "Archive '" << *archive << "' not found"; + throw std::runtime_error(message.str()); + } + } +} \ No newline at end of file diff --git a/components/bsa/resources.hpp b/components/bsa/resources.hpp new file mode 100644 index 000000000..8c3fb7bef --- /dev/null +++ b/components/bsa/resources.hpp @@ -0,0 +1,16 @@ +#ifndef BSA_BSA_RESOURCES_H +#define BSA_BSA_RESOURCES_H + +#include +#include + +#include "../files/collections.hpp" + +namespace Bsa +{ + void registerResources (const Files::Collections& collections, + const std::vector& archives, bool useLooseFiles, bool fsStrict); + ///< Register resources directories and archives as OGRE resources groups +} + +#endif diff --git a/files/opencs/add.png b/files/opencs/add.png new file mode 100644 index 000000000..3f1347e24 Binary files /dev/null and b/files/opencs/add.png differ diff --git a/files/opencs/edit-clone.png b/files/opencs/edit-clone.png new file mode 100644 index 000000000..3398e8d18 Binary files /dev/null and b/files/opencs/edit-clone.png differ diff --git a/files/opencs/edit-delete.png b/files/opencs/edit-delete.png new file mode 100644 index 000000000..ea03150a1 Binary files /dev/null and b/files/opencs/edit-delete.png differ diff --git a/files/opencs/edit-preview.png b/files/opencs/edit-preview.png new file mode 100644 index 000000000..a605e7080 Binary files /dev/null and b/files/opencs/edit-preview.png differ diff --git a/files/opencs/edit-undo.png b/files/opencs/edit-undo.png new file mode 100644 index 000000000..8b0fef9a8 Binary files /dev/null and b/files/opencs/edit-undo.png differ diff --git a/files/opencs/go-next.png b/files/opencs/go-next.png new file mode 100644 index 000000000..6ef8de76e Binary files /dev/null and b/files/opencs/go-next.png differ diff --git a/files/opencs/go-previous.png b/files/opencs/go-previous.png new file mode 100644 index 000000000..659cd90d7 Binary files /dev/null and b/files/opencs/go-previous.png differ diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index 2b1e65ff0..2031e54cc 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -57,6 +57,13 @@ static.png weapon.png multitype.png + go-next.png + go-previous.png + edit-delete.png + edit-undo.png + edit-preview.png + edit-clone.png + add.png raster/startup/big/create-addon.png raster/startup/big/new-game.png raster/startup/big/edit-content.png