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 #ifndef TrenchBroom_RecentDocuments 21 #define TrenchBroom_RecentDocuments 22 23 #include "CollectionUtils.h" 24 #include "Notifier.h" 25 #include "IO/Path.h" 26 27 #include <vector> 28 29 #include <wx/config.h> 30 #include <wx/confbase.h> 31 #include <wx/event.h> 32 #include <wx/menu.h> 33 34 namespace TrenchBroom { 35 namespace View { 36 template <class EventHandler> 37 class RecentDocuments { 38 private: 39 typedef void (EventHandler::*Function)(wxCommandEvent&); 40 typedef std::vector<wxMenu*> MenuList; 41 MenuList m_menus; 42 EventHandler* m_handler; 43 Function m_function; 44 int m_baseId; 45 size_t m_maxSize; 46 IO::Path::List m_recentDocuments; 47 public: 48 Notifier0 didChangeNotifier; 49 public: RecentDocuments(const int baseId,const size_t maxSize)50 RecentDocuments(const int baseId, const size_t maxSize) : 51 m_handler(NULL), 52 m_function(NULL), 53 m_baseId(baseId), 54 m_maxSize(maxSize) { 55 assert(m_maxSize > 0); 56 loadFromConfig(); 57 } 58 recentDocuments()59 const IO::Path::List& recentDocuments() const { 60 return m_recentDocuments; 61 } 62 addMenu(wxMenu * menu)63 void addMenu(wxMenu* menu) { 64 assert(menu != NULL); 65 clearMenu(menu); 66 createMenuItems(menu); 67 m_menus.push_back(menu); 68 } 69 removeMenu(wxMenu * menu)70 void removeMenu(wxMenu* menu) { 71 assert(menu != NULL); 72 clearMenu(menu); 73 VectorUtils::erase(m_menus, menu); 74 } 75 setHandler(EventHandler * handler,Function function)76 void setHandler(EventHandler* handler, Function function) { 77 if (m_handler != NULL && m_function != NULL) 78 clearBindings(); 79 80 m_handler = handler; 81 m_function = function; 82 83 if (m_handler != NULL && m_function != NULL) 84 createBindings(); 85 } 86 updatePath(const IO::Path & path)87 void updatePath(const IO::Path& path) { 88 insertPath(path); 89 updateMenus(); 90 updateBindings(); 91 saveToConfig(); 92 didChangeNotifier(); 93 } 94 removePath(const IO::Path & path)95 void removePath(const IO::Path& path) { 96 const size_t oldSize = m_recentDocuments.size(); 97 98 const IO::Path canonPath = path.makeCanonical(); 99 VectorUtils::erase(m_recentDocuments, canonPath); 100 101 if (oldSize > m_recentDocuments.size()) { 102 updateMenus(); 103 updateBindings(); 104 saveToConfig(); 105 didChangeNotifier(); 106 } 107 } 108 private: loadFromConfig()109 void loadFromConfig() { 110 m_recentDocuments.clear(); 111 wxConfigBase* conf = wxConfig::Get(); 112 for (size_t i = 0; i < m_maxSize; ++i) { 113 const wxString confName = wxString("RecentDocuments/") << i; 114 wxString value; 115 if (conf->Read(confName, &value)) 116 m_recentDocuments.push_back(IO::Path(value.ToStdString())); 117 else 118 break; 119 } 120 } 121 saveToConfig()122 void saveToConfig() { 123 wxConfigBase* conf = wxConfig::Get(); 124 conf->DeleteGroup("RecentDocuments"); 125 for (size_t i = 0; i < m_recentDocuments.size(); ++i) { 126 const wxString confName = wxString("RecentDocuments/") << i; 127 const wxString value = m_recentDocuments[i].asString(); 128 conf->Write(confName, value); 129 } 130 } 131 updateBindings()132 void updateBindings() { 133 if (m_handler != NULL && m_function != NULL) { 134 clearBindings(); 135 createBindings(); 136 } 137 } 138 createBindings()139 void createBindings() { 140 for (size_t i = 0; i < m_recentDocuments.size(); ++i) { 141 wxVariant* data = new wxVariant(wxString(m_recentDocuments[i].asString())); 142 const int windowId = m_baseId + static_cast<int>(i); 143 m_handler->Bind(wxEVT_MENU, m_function, m_handler, windowId, windowId, data); 144 } 145 } 146 clearBindings()147 void clearBindings() { 148 for (int i = 0; i < static_cast<int>(m_maxSize); ++i) 149 m_handler->Unbind(wxEVT_MENU, m_function, m_handler, m_baseId + i); 150 } 151 insertPath(const IO::Path & path)152 void insertPath(const IO::Path& path) { 153 const IO::Path canonPath = path.makeCanonical(); 154 IO::Path::List::iterator it = std::find(m_recentDocuments.begin(), m_recentDocuments.end(), canonPath); 155 if (it != m_recentDocuments.end()) 156 m_recentDocuments.erase(it); 157 m_recentDocuments.insert(m_recentDocuments.begin(), canonPath); 158 if (m_recentDocuments.size() > m_maxSize) 159 m_recentDocuments.pop_back(); 160 } 161 updateMenus()162 void updateMenus() { 163 MenuList::iterator it, end; 164 for (it = m_menus.begin(), end = m_menus.end(); it != end; ++it) { 165 wxMenu* menu = *it; 166 clearMenu(menu); 167 createMenuItems(menu); 168 } 169 } 170 clearMenu(wxMenu * menu)171 void clearMenu(wxMenu* menu) { 172 while (menu->GetMenuItemCount() > 0) { 173 wxMenuItem* item = menu->FindItemByPosition(0); 174 menu->Delete(item); 175 } 176 } 177 createMenuItems(wxMenu * menu)178 void createMenuItems(wxMenu* menu) { 179 for (size_t i = 0; i < m_recentDocuments.size(); ++i) { 180 const IO::Path& path = m_recentDocuments[i]; 181 const int windowId = m_baseId + static_cast<int>(i); 182 menu->Append(windowId, path.lastComponent().asString()); 183 } 184 } 185 }; 186 } 187 } 188 189 #endif /* defined(TrenchBroom_RecentDocuments) */ 190