Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/config/SettingsConfigFile.cc @ 11504

Last change on this file since 11504 was 11071, checked in by landauf, 9 years ago

merged branch cpp11_v3 back to trunk

  • Property svn:eol-style set to native
File size: 11.3 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file
31    @brief Implementation of SettingsConfigFile.
32*/
33
34#include "SettingsConfigFile.h"
35
36#include "util/StringUtils.h"
37#include "core/command/ConsoleCommandIncludes.h"
38#include "ConfigFileManager.h"
39#include "ConfigValueContainer.h"
40
41namespace orxonox
42{
43    ////////////////////////
44    // SettingsConfigFile //
45    ////////////////////////
46
47    static const std::string __CC_load_name = "reloadSettings";
48    static const std::string __CC_setFilename_name = "setSettingsFile";
49    static const std::string __CC_config_name = "config";
50    static const std::string __CC_tconfig_name = "tconfig";
51    static const std::string __CC_getConfig_name = "getConfig";
52
53    SetConsoleCommand(__CC_load_name,            &ConfigFile::load);
54    SetConsoleCommand(__CC_setFilename_name,     &SettingsConfigFile::setFilename);
55    SetConsoleCommand(__CC_config_name,          &SettingsConfigFile::config).argumentCompleter(0, autocompletion::settingssections()).argumentCompleter(1, autocompletion::settingsentries()).argumentCompleter(2, autocompletion::settingsvalue());
56    SetConsoleCommand(__CC_tconfig_name,         &SettingsConfigFile::tconfig).argumentCompleter(0, autocompletion::settingssections()).argumentCompleter(1, autocompletion::settingsentries()).argumentCompleter(2, autocompletion::settingsvalue());
57    SetConsoleCommand(__CC_getConfig_name,       &SettingsConfigFile::getConfig).argumentCompleter(0, autocompletion::settingssections()).argumentCompleter(1, autocompletion::settingsentries());
58
59    SettingsConfigFile* SettingsConfigFile::singletonPtr_s = nullptr;
60
61    /**
62        @brief Constructor: Activates the console commands.
63    */
64    SettingsConfigFile::SettingsConfigFile(const std::string& filename)
65        : ConfigFile(filename)
66    {
67        ModifyConsoleCommand(__CC_load_name).setObject(this);
68        ModifyConsoleCommand(__CC_setFilename_name).setObject(this);
69        ModifyConsoleCommand(__CC_config_name).setObject(this);
70        ModifyConsoleCommand(__CC_tconfig_name).setObject(this);
71        ModifyConsoleCommand(__CC_getConfig_name).setObject(this);
72    }
73
74    /**
75        @brief Destructor: Deactivates the console commands.
76    */
77    SettingsConfigFile::~SettingsConfigFile()
78    {
79        ModifyConsoleCommand(__CC_load_name).setObject(nullptr);
80        ModifyConsoleCommand(__CC_setFilename_name).setObject(nullptr);
81        ModifyConsoleCommand(__CC_config_name).setObject(nullptr);
82        ModifyConsoleCommand(__CC_tconfig_name).setObject(nullptr);
83        ModifyConsoleCommand(__CC_getConfig_name).setObject(nullptr);
84    }
85
86    /**
87        @brief Loads the config file and updates the @ref ConfigValueContainer "config value containers".
88    */
89    void SettingsConfigFile::load()
90    {
91        ConfigFile::load();
92        this->updateConfigValues();
93    }
94
95    /**
96        @brief Changes the file-name.
97    */
98    void SettingsConfigFile::setFilename(const std::string& filename)
99    {
100        ConfigFileManager::getInstance().setFilename(ConfigFileType::Settings, filename);
101    }
102
103    /**
104        @brief Registers a new @ref ConfigValueContainer "config value container".
105    */
106    void SettingsConfigFile::addConfigValueContainer(ConfigValueContainer* container)
107    {
108        if (container == nullptr)
109            return;
110        std::pair<std::string, ConfigValueContainer*> second(getLowercase(container->getName()), container);
111        this->containers_.insert(std::make_pair(getLowercase(container->getSectionName()), second));
112        this->sectionNames_.insert(container->getSectionName());
113    }
114
115    /**
116        @brief Unregisters a @ref ConfigValueContainer "config value container".
117    */
118    void SettingsConfigFile::removeConfigValueContainer(ConfigValueContainer* container)
119    {
120        if (container == nullptr)
121            return;
122        const std::string& sectionLC = getLowercase(container->getSectionName());
123        ContainerMap::iterator upper = this->containers_.upper_bound(sectionLC);
124        for (ContainerMap::iterator it = this->containers_.lower_bound(sectionLC); it != upper; ++it)
125        {
126            if (it->second.second == container)
127            {
128                // Remove entry from section name set this was the last container for that section
129                if (upper == this->containers_.lower_bound(sectionLC))
130                    this->sectionNames_.erase(container->getSectionName());
131                this->containers_.erase(it);
132                break;
133            }
134        }
135    }
136
137    /**
138        @brief Updates all @ref ConfigValueContainer "config value containers".
139    */
140    void SettingsConfigFile::updateConfigValues()
141    {
142        // todo: can this be done more efficiently? looks like some identifiers will be updated multiple times.
143
144        for (const auto& mapEntry : this->containers_)
145        {
146            mapEntry.second.second->update();
147            mapEntry.second.second->getIdentifier()->updateConfigValues();
148        }
149    }
150
151    /**
152        @brief Removes entries and sections from the file that don't exist anymore (i.e. if there's no corresponding @ref ConfigValueContainer "config value container").
153        @param bCleanComments If true, comments are also removed from the file
154    */
155    void SettingsConfigFile::clean(bool bCleanComments)
156    {
157        for (std::list<ConfigFileSection*>::iterator itSection = this->sections_.begin(); itSection != this->sections_.end(); )
158        {
159            const std::string& sectionLC = getLowercase((*itSection)->getName());
160            ContainerMap::const_iterator lower = this->containers_.lower_bound(sectionLC);
161            ContainerMap::const_iterator upper = this->containers_.upper_bound(sectionLC);
162            if (lower != upper)
163            {
164                // The section exists, delete comment
165                if (bCleanComments)
166                    (*itSection)->setComment("");
167                for (std::list<ConfigFileEntry*>::iterator itEntry = (*itSection)->entries_.begin(); itEntry != (*itSection)->entries_.end(); )
168                {
169                    const std::string& entryLC = getLowercase((*itEntry)->getName());
170                    bool bFound = false;
171                    for (ContainerMap::const_iterator itContainer = lower; itContainer != upper; ++itContainer)
172                    {
173                        if (itContainer->second.first == entryLC)
174                        {
175                            // The config-value exists, delete comment
176                            if (bCleanComments)
177                                (*itEntry)->setComment("");
178                            ++itEntry;
179                            bFound = true;
180                            break;
181                        }
182                    }
183                    if (!bFound)
184                    {
185                        // The config-value doesn't exist
186                        delete (*itEntry);
187                        (*itSection)->entries_.erase(itEntry++);
188                    }
189                }
190                ++itSection;
191            }
192            else
193            {
194                // The section doesn't exist
195                delete (*itSection);
196                this->sections_.erase(itSection++);
197            }
198        }
199
200        // Save the file
201        this->save();
202    }
203
204    /**
205        @brief Console-command: Changes the value of an entry and stores it the file.
206
207        @param section  The section of the config value
208        @param entry    The name of the config value
209        @param value    The new value
210    */
211    void SettingsConfigFile::config(const std::string& section, const std::string& entry, const std::string& value)
212    {
213        if (!this->configImpl(section, entry, value, &ConfigValueContainer::set))
214            orxout(user_error, context::config) << "Config value \"" << entry << "\" in section \"" << section << "\" doesn't exist." << endl;
215    }
216
217    /**
218        @brief Console-command: Changes the value of an entry, but doesn't store it in the file (it's only a temporary change).
219
220        @param section  The section of the config value
221        @param entry    The name of the config value
222        @param value    The new value
223    */
224    void SettingsConfigFile::tconfig(const std::string& section, const std::string& entry, const std::string& value)
225    {
226        if (!this->configImpl(section, entry, value, &ConfigValueContainer::tset))
227            orxout(user_error, context::config) << "Config value \"" << entry << "\" in section \"" << section << "\" doesn't exist." << endl;
228    }
229
230    /**
231        @brief Changes the value of an entry, depending on @a function, either by using "set" or "tset"
232
233        @param section  The section of the config value
234        @param entry    The name of the config value
235        @param value    The new value
236        @param function The function ("set" or "tset") that will be used to change the value.
237    */
238    bool SettingsConfigFile::configImpl(const std::string& section, const std::string& entry, const std::string& value, bool (ConfigValueContainer::*function)(const MultiType&))
239    {
240        const std::string& sectionLC = getLowercase(section);
241        const std::string& entryLC = getLowercase(entry);
242        ContainerMap::iterator upper = this->containers_.upper_bound(sectionLC);
243        for (ContainerMap::iterator it = this->containers_.lower_bound(sectionLC); it != upper; ++it)
244        {
245            // Note: Config value vectors cannot be supported
246            if (it->second.first == entryLC && !it->second.second->isVector())
247            {
248                return (it->second.second->*function)(value);
249            }
250        }
251        return false;
252    }
253
254    /**
255        @brief Console-command: Returns the value of a given entry.
256
257        @param section  The section of the config value
258        @param entry    The name of the config value
259    */
260    std::string SettingsConfigFile::getConfig(const std::string& section, const std::string& entry)
261    {
262        const std::string& sectionLC = getLowercase(section);
263        const std::string& entryLC = getLowercase(entry);
264        ContainerMap::iterator upper = this->containers_.upper_bound(sectionLC);
265        for (ContainerMap::iterator it = this->containers_.lower_bound(sectionLC); it != upper; ++it)
266        {
267            // Note: Config value vectors cannot be supported
268            if (it->second.first == entryLC && ! it->second.second->isVector())
269            {
270                std::string value;
271                it->second.second->getValue<std::string, void>(&value, nullptr);
272                return value;
273            }
274        }
275        return "";
276    }
277}
Note: See TracBrowser for help on using the repository browser.