Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutorial3/src/libraries/util/output/OutputManager.cc @ 10904

Last change on this file since 10904 was 8858, checked in by landauf, 13 years ago

merged output branch back to trunk.

Changes:

  • you have to include util/Output.h instead of util/Debug.h
  • COUT(x) is now called orxout(level)
  • output levels are now defined by an enum instead of numbers. see util/Output.h for the definition
  • it's possible to use output contexts with orxout(level, context). see util/Output.h for some common contexts. you can define more contexts
  • you must use 'endl' at the end of an output message, '\n' does not flush the message

Output levels:

  • instead of COUT(0) use orxout()
  • instead of COUT(1) use orxout(user_error) or orxout(internal_error)
  • instead of COUT(2) use orxout(user_warning) or orxout(internal_warning)
  • instead of COUT(3) use orxout(user_status/user_info) or orxout(internal_status/internal_info)
  • instead of COUT(4) use orxout(verbose)
  • instead of COUT(5) use orxout(verbose_more)
  • instead of COUT(6) use orxout(verbose_ultra)

Guidelines:

  • user_* levels are for the user, visible in the console and the log-file
  • internal_* levels are for developers, visible in the log-file
  • verbose_* levels are for debugging, only visible if the context of the output is activated

Usage in C++:

  • orxout() << "message" << endl;
  • orxout(level) << "message" << endl;
  • orxout(level, context) << "message" << endl;

Usage in Lua:

  • orxout("message")
  • orxout(orxonox.level.levelname, "message")
  • orxout(orxonox.level.levelname, "context", "message")

Usage in Tcl (and in the in-game-console):

  • orxout levelname message
  • orxout_context levelname context message
  • shortcuts: log message, error message, warning message, status message, info message, debug message
  • Property svn:eol-style set to native
File size: 10.8 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 the OutputManager singleton.
32*/
33
34#include "OutputManager.h"
35
36#include "MemoryWriter.h"
37#include "ConsoleWriter.h"
38#include "LogWriter.h"
39#include "util/Output.h"
40#include "util/StringUtils.h"
41
42namespace orxonox
43{
44    /**
45        @brief Constructor, initializes all values.
46    */
47    OutputManager::OutputManager()
48    {
49        this->combinedLevelMask_ = level::none;
50        this->combinedAdditionalContextsLevelMask_ = level::none;
51        this->combinedAdditionalContextsMask_ = context::none;
52
53        this->subcontextCounter_ = 0;
54    }
55
56    /**
57        @brief Destructor.
58    */
59    OutputManager::~OutputManager()
60    {
61    }
62
63    /**
64        @brief Returns the only existing instance of the OutputManager singleton.
65    */
66    /*static*/ OutputManager& OutputManager::getInstance()
67    {
68        static OutputManager instance;
69        return instance;
70    }
71
72    /**
73        @brief Returns the only existing instance of the OutputManager singleton
74        and ensures that the most important output listeners exist.
75
76        You should use this function if you send output to OutputManager and want
77        to be sure that the most important output listeners exist. Don't use it
78        elsewhere inside the output system to avoid circular calls.
79    */
80    /*static*/ OutputManager& OutputManager::getInstanceAndCreateListeners()
81    {
82        static OutputManager& instance = OutputManager::getInstance();
83
84        static MemoryWriter& memoryWriterInstance = MemoryWriter::getInstance(); (void)memoryWriterInstance;
85        static ConsoleWriter& consoleWriterInstance = ConsoleWriter::getInstance(); (void)consoleWriterInstance;
86        static LogWriter& logWriterInstance = LogWriter::getInstance(); (void)logWriterInstance;
87
88        return instance;
89    }
90
91    /**
92        @brief Sends an output message to all output listeners.
93        @param level The level of the message
94        @param context The context of the message
95        @param message The output message (may contain '\\n')
96
97        This function splits the message into lines (if it contains '\\n') and
98        sends it to the output listeners. They may ignore the message if it
99        doesn't match their level- and context-masks.
100    */
101    void OutputManager::pushMessage(OutputLevel level, const OutputContextContainer& context, const std::string& message)
102    {
103        std::vector<std::string> lines;
104        vectorize(message, '\n', &lines);
105
106        for (size_t i = 0; i < this->listeners_.size(); ++i)
107            this->listeners_[i]->unfilteredOutput(level, context, lines);
108    }
109
110    /**
111        @brief Adds an output listener to the list of listeners.
112    */
113    void OutputManager::registerListener(OutputListener* listener)
114    {
115        this->listeners_.push_back(listener);
116        this->updateMasks();
117    }
118
119    /**
120        @brief Removes an output listener from the list of listeners.
121    */
122    void OutputManager::unregisterListener(OutputListener* listener)
123    {
124        for (std::vector<OutputListener*>::iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
125        {
126            if (*it == listener)
127            {
128                this->listeners_.erase(it);
129                break;
130            }
131        }
132        this->updateMasks();
133    }
134
135    /**
136        @brief Updates all three combined level- and context-masks.
137    */
138    void OutputManager::updateMasks()
139    {
140        this->updateCombinedLevelMask();
141        this->updateCombinedAdditionalContextsLevelMask();
142        this->updateCombinedAdditionalContextsMask();
143    }
144
145    /**
146        @brief Updates the combined level mask. The masks of all listeners are ORed to form the combined mask.
147    */
148    void OutputManager::updateCombinedLevelMask()
149    {
150        int mask = 0;
151        for (size_t i = 0; i < this->listeners_.size(); ++i)
152            mask |= this->listeners_[i]->getLevelMask();
153        this->combinedLevelMask_ = static_cast<OutputLevel>(mask);
154    }
155
156    /**
157        @brief Updates the combined additional contexts level mask. The masks of all listeners are ORed to form the combined mask.
158    */
159    void OutputManager::updateCombinedAdditionalContextsLevelMask()
160    {
161        int mask = 0;
162        for (size_t i = 0; i < this->listeners_.size(); ++i)
163            mask |= this->listeners_[i]->getAdditionalContextsLevelMask();
164        this->combinedAdditionalContextsLevelMask_ = static_cast<OutputLevel>(mask);
165    }
166
167    /**
168        @brief Updates the combined additional contexts mask. The masks of all listeners are ORed to form the combined mask.
169    */
170    void OutputManager::updateCombinedAdditionalContextsMask()
171    {
172        this->combinedAdditionalContextsMask_ = 0;
173        for (size_t i = 0; i < this->listeners_.size(); ++i)
174            this->combinedAdditionalContextsMask_ |= this->listeners_[i]->getAdditionalContextsMask();
175    }
176
177    /**
178        @brief Registers a context (or sub-context) and returns the container which identifies the context.
179        @param name The name of the context
180        @param subname The name of the sub-context (or "" if it is not a sub-context)
181
182        If the context doesn't exist, it gets created. Otherwise the existing instance is returned.
183    */
184    const OutputContextContainer& OutputManager::registerContext(const std::string& name, const std::string& subname)
185    {
186        // the full name of a context is a combination of name and subname with "::" in between
187        std::string full_name = name;
188        if (subname != "")
189            full_name += "::" + subname;
190
191        // check if the context already exists (and return it if it does)
192        std::map<std::string, OutputContextContainer>::iterator it_container = this->contextContainers_.find(full_name);
193        if (it_container != this->contextContainers_.end())
194            return it_container->second;
195
196        // create a new context container
197        OutputContextContainer container;
198        container.name = full_name;
199
200        // check if the mask of the main-context already exists
201        std::map<std::string, OutputContextMask>::iterator it_mask = this->contextMasks_.find(name);
202        if (it_mask != this->contextMasks_.end())
203        {
204            // the mask exists, assign it to the container
205            container.mask = it_mask->second;
206        }
207        else
208        {
209            // the mask doesn't exist, create it. It's a binary mask. The n-th main-context is defined by the n-th bit in the mask.
210            container.mask = static_cast<OutputContextMask>(0x1) << this->contextMasks_.size();
211            this->contextMasks_[name] = container.mask;
212
213            if (container.mask == 0)
214                orxout(internal_warning) << "More than " << sizeof(OutputContextMask) * 8 << " output contexts defined. Context '" << name << "' might not get filtered correctly" << endl;
215        }
216
217        // if the context is a sub-context, assign a unique ID.
218        if (subname == "")
219            container.sub_id = context::no_subcontext;
220        else
221            container.sub_id = ++this->subcontextCounter_; // start with 1
222
223        // add the new context to the map and return it
224        return (this->contextContainers_[full_name] = container);
225    }
226
227    /**
228        @brief Static function, shortcut to OutputManager::registerContext().
229        The function is declared in OutputDefinitions.h.
230    */
231    const OutputContextContainer& registerContext(const std::string& name, const std::string& subname)
232    {
233        return OutputManager::getInstance().registerContext(name, subname);
234    }
235
236    /**
237        @brief Returns a human readable string for each output level.
238    */
239    const std::string& OutputManager::getLevelName(OutputLevel level) const
240    {
241        switch (level)
242        {
243            // using static cache variables for speed
244            case level::none:               { static std::string name = "None"; return name; }
245            case level::message:            { static std::string name = "Message"; return name; }
246            case level::debug_output:       { static std::string name = "Debug"; return name; }
247            case level::user_error:         { static std::string name = "Error"; return name; }
248            case level::user_warning:       { static std::string name = "Warning"; return name; }
249            case level::user_status:        { static std::string name = "Status"; return name; }
250            case level::user_info:          { static std::string name = "Info"; return name; }
251            case level::internal_error:     { static std::string name = "Error (internal)"; return name; }
252            case level::internal_warning:   { static std::string name = "Warning (internal)"; return name; }
253            case level::internal_status:    { static std::string name = "Status (internal)"; return name; }
254            case level::internal_info:      { static std::string name = "Info (internal)"; return name; }
255            case level::verbose:            { static std::string name = "Verbose"; return name; }
256            case level::verbose_more:       { static std::string name = "Verbose (more)"; return name; }
257            case level::verbose_ultra:      { static std::string name = "Verbose (ultra)"; return name; }
258            default:                        { static std::string name = ""; return name; }
259        }
260    }
261
262    /**
263        @brief Returns a string containing the name of the level and the context (if any) which
264        can be prepended to an output message if it is written to the console or the log file.
265    */
266    std::string OutputManager::getDefaultPrefix(OutputLevel level, const OutputContextContainer& context) const
267    {
268        // "undefined" context is ignored because it's used implicitly if no explicit context is defined
269        static OutputContextMask undefined_mask = context::undefined().mask;
270
271        std::string prefix = this->getLevelName(level) + ": ";
272        if (context.mask != undefined_mask)
273            prefix += "[" + context.name + "] ";
274
275        return prefix;
276    }
277}
Note: See TracBrowser for help on using the repository browser.