1 /* 2 Copyright (C) 2010-2014 Kristian Duske 3 4 This file is part of TrenchBroom. 5 6 TrenchBroom is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 TrenchBroom is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "ViewUtils.h" 21 22 #include "Exceptions.h" 23 #include "Logger.h" 24 #include "Assets/EntityModelManager.h" 25 #include "Assets/EntityDefinitionFileSpec.h" 26 #include "Assets/ModelDefinition.h" 27 #include "Model/Game.h" 28 #include "Model/GameFactory.h" 29 #include "View/ChoosePathTypeDialog.h" 30 #include "View/MapDocument.h" 31 32 namespace TrenchBroom { 33 namespace View { safeGetModel(Assets::EntityModelManager & manager,const Assets::ModelSpecification & spec,Logger & logger)34 Assets::EntityModel* safeGetModel(Assets::EntityModelManager& manager, const Assets::ModelSpecification& spec, Logger& logger) { 35 try { 36 return manager.model(spec.path); 37 } catch (const GameException& e) { 38 logger.error(String(e.what())); 39 return NULL; 40 } 41 } 42 combineFlags(const size_t numFlags,const int newFlagValue,int & setFlags,int & mixedFlags)43 void combineFlags(const size_t numFlags, const int newFlagValue, int& setFlags, int& mixedFlags) { 44 for (size_t i = 0; i < numFlags; ++i) { 45 const bool alreadySet = (newFlagValue & (1 << i)) != 0; 46 const bool willBeSet = (setFlags & (1 << i)) != 0; 47 if (alreadySet == willBeSet) 48 continue; 49 50 setFlags &= ~(1 << i); 51 mixedFlags |= (1 << i); 52 } 53 } 54 loadDroppedFiles(MapDocumentWPtr document,wxWindow * parent,const wxArrayString & wxPaths)55 size_t loadDroppedFiles(MapDocumentWPtr document, wxWindow* parent, const wxArrayString& wxPaths) { 56 size_t count = 0; 57 count += loadTextureCollections(document, parent, wxPaths); 58 if (loadEntityDefinitionFile(document, parent, wxPaths) < wxPaths.size()) 59 ++count; 60 return count > 0; 61 } 62 loadTextureCollection(MapDocumentWPtr document,wxWindow * parent,const wxString & wxPath)63 bool loadTextureCollection(MapDocumentWPtr document, wxWindow* parent, const wxString& wxPath) { 64 wxArrayString wxPaths; 65 wxPaths.Add(wxPath); 66 return loadTextureCollections(document, parent, wxPaths) == 1; 67 } 68 containsLoadableTextureCollections(MapDocumentWPtr i_document,const wxArrayString & wxPaths)69 bool containsLoadableTextureCollections(MapDocumentWPtr i_document, const wxArrayString& wxPaths) { 70 MapDocumentSPtr document = lock(i_document); 71 Model::GamePtr game = document->game(); 72 const Model::GameFactory& gameFactory = Model::GameFactory::instance(); 73 const IO::Path gamePath = gameFactory.gamePath(game->gameName()); 74 const IO::Path docPath = document->path(); 75 76 for (size_t i = 0; i < wxPaths.size(); ++i) { 77 const wxString& wxPath = wxPaths[i]; 78 const IO::Path absPath(wxPath.ToStdString()); 79 if (!game->isTextureCollection(absPath)) 80 return true; 81 } 82 83 return false; 84 } 85 loadTextureCollections(MapDocumentWPtr i_document,wxWindow * parent,const wxArrayString & wxPaths)86 size_t loadTextureCollections(MapDocumentWPtr i_document, wxWindow* parent, const wxArrayString& wxPaths) { 87 if (wxPaths.empty()) 88 return 0; 89 90 size_t count = 0; 91 92 MapDocumentSPtr document = lock(i_document); 93 Model::GamePtr game = document->game(); 94 const Model::GameFactory& gameFactory = Model::GameFactory::instance(); 95 const IO::Path gamePath = gameFactory.gamePath(game->gameName()); 96 const IO::Path docPath = document->path(); 97 98 Transaction transaction(document); 99 try { 100 for (size_t i = 0; i < wxPaths.size(); ++i) { 101 const wxString& wxPath = wxPaths[i]; 102 const IO::Path absPath(wxPath.ToStdString()); 103 if (game->isTextureCollection(absPath)) { 104 ChoosePathTypeDialog pathDialog(wxGetTopLevelParent(parent), absPath, docPath, gamePath); 105 if (pathDialog.ShowModal() == wxID_OK) { 106 const IO::Path collectionPath = pathDialog.path(); 107 document->addTextureCollection(collectionPath.asString()); 108 ++count; 109 } 110 } 111 } 112 } catch (...) { 113 transaction.rollback(); 114 throw; 115 } 116 117 return count; 118 } 119 loadEntityDefinitionFile(MapDocumentWPtr document,wxWindow * parent,const wxString & wxPath)120 bool loadEntityDefinitionFile(MapDocumentWPtr document, wxWindow* parent, const wxString& wxPath) { 121 wxArrayString wxPaths; 122 wxPaths.Add(wxPath); 123 return loadEntityDefinitionFile(document, parent, wxPaths) == 0; 124 } 125 containsLoadableEntityDefinitionFile(MapDocumentWPtr i_document,const wxArrayString & wxPaths)126 bool containsLoadableEntityDefinitionFile(MapDocumentWPtr i_document, const wxArrayString& wxPaths) { 127 MapDocumentSPtr document = lock(i_document); 128 Model::GamePtr game = document->game(); 129 const Model::GameFactory& gameFactory = Model::GameFactory::instance(); 130 const IO::Path gamePath = gameFactory.gamePath(game->gameName()); 131 const IO::Path docPath = document->path(); 132 133 for (size_t i = 0; i < wxPaths.size(); ++i) { 134 const wxString& wxPath = wxPaths[i]; 135 const IO::Path absPath(wxPath.ToStdString()); 136 if (game->isEntityDefinitionFile(absPath)) 137 return true; 138 } 139 140 return false; 141 } 142 loadEntityDefinitionFile(MapDocumentWPtr i_document,wxWindow * parent,const wxArrayString & wxPaths)143 size_t loadEntityDefinitionFile(MapDocumentWPtr i_document, wxWindow* parent, const wxArrayString& wxPaths) { 144 if (wxPaths.empty()) 145 return 0; 146 147 MapDocumentSPtr document = lock(i_document); 148 Model::GamePtr game = document->game(); 149 const Model::GameFactory& gameFactory = Model::GameFactory::instance(); 150 const IO::Path gamePath = gameFactory.gamePath(game->gameName()); 151 const IO::Path docPath = document->path(); 152 153 try { 154 for (size_t i = 0; i < wxPaths.size(); ++i) { 155 const wxString& wxPath = wxPaths[i]; 156 const IO::Path absPath(wxPath.ToStdString()); 157 if (game->isEntityDefinitionFile(absPath)) { 158 ChoosePathTypeDialog pathDialog(wxGetTopLevelParent(parent), absPath, docPath, gamePath); 159 if (pathDialog.ShowModal() == wxID_OK) { 160 const Assets::EntityDefinitionFileSpec spec = Assets::EntityDefinitionFileSpec::external(pathDialog.path()); 161 document->setEntityDefinitionFile(spec); 162 return i; 163 } 164 } 165 } 166 } catch (...) { 167 throw; 168 } 169 170 return wxPaths.size(); 171 } 172 queryGroupName(wxWindow * parent)173 String queryGroupName(wxWindow* parent) { 174 while (true) { 175 wxTextEntryDialog dialog(parent, "Enter a name", "Group Name", "Unnamed"); 176 dialog.CentreOnParent(); 177 if (dialog.ShowModal() != wxID_OK) 178 return ""; 179 180 const String name = dialog.GetValue().ToStdString(); 181 if (StringUtils::isBlank(name)) { 182 if (wxMessageBox("Group names cannot be blank.", "Error", wxOK | wxCANCEL | wxCENTRE, parent) != wxOK) 183 return ""; 184 } else if (StringUtils::containsCaseInsensitive(name, "\"")) { 185 if (wxMessageBox("Group names cannot contain double quotes.", "Error", wxOK | wxCANCEL | wxCENTRE, parent) != wxOK) 186 return ""; 187 } else { 188 return name; 189 } 190 } 191 } 192 } 193 } 194