733509737dcf257e0f55e87310ca1a87912d1bcb
[alexxy/gromacs.git] / src / gromacs / onlinehelp / helpmanager.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  * \brief
37  * Implements gmx::HelpManager.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_onlinehelp
41  */
42 #include "helpmanager.h"
43
44 #include <string>
45 #include <vector>
46
47 #include "gromacs/onlinehelp/helptopicinterface.h"
48 #include "gromacs/utility/exceptions.h"
49 #include "gromacs/utility/stringutil.h"
50
51 namespace gmx
52 {
53
54 /********************************************************************
55  * HelpManager::Impl
56  */
57
58 /*! \internal \brief
59  * Private implementation class for HelpManager.
60  *
61  * \ingroup module_onlinehelp
62  */
63 class HelpManager::Impl
64 {
65     public:
66         //! Container type for keeping the stack of active topics.
67         typedef std::vector<const HelpTopicInterface *> TopicStack;
68
69         //! Initializes a new manager with the given context.
70         explicit Impl(const HelpWriterContext &context)
71             : rootContext_(context)
72         {
73         }
74
75         //! Whether the active topic is the root topic.
76         bool isAtRootTopic() const { return topicStack_.size() == 1; }
77         //! Returns the active topic.
78         const HelpTopicInterface &currentTopic() const
79         {
80             return *topicStack_.back();
81         }
82         //! Formats the active topic as a string, including its parent topics.
83         std::string currentTopicAsString() const;
84
85         //! Context with which the manager was initialized.
86         const HelpWriterContext &rootContext_;
87         /*! \brief
88          * Stack of active topics.
89          *
90          * The first item is always the root topic, and each item is a subtopic
91          * of the preceding item.  The last item is the currently active topic.
92          */
93         TopicStack               topicStack_;
94 };
95
96 std::string HelpManager::Impl::currentTopicAsString() const
97 {
98     std::string                result;
99     TopicStack::const_iterator topic;
100     for (topic = topicStack_.begin() + 1; topic != topicStack_.end(); ++topic)
101     {
102         if (!result.empty())
103         {
104             result.append(" ");
105         }
106         result.append((*topic)->name());
107     }
108     return result;
109 }
110
111 /********************************************************************
112  * HelpManager
113  */
114
115 HelpManager::HelpManager(const HelpTopicInterface &rootTopic,
116                          const HelpWriterContext  &context)
117     : impl_(new Impl(context))
118 {
119     impl_->topicStack_.push_back(&rootTopic);
120 }
121
122 HelpManager::~HelpManager()
123 {
124 }
125
126 void HelpManager::enterTopic(const char *name)
127 {
128     const HelpTopicInterface &topic = impl_->currentTopic();
129     if (!topic.hasSubTopics())
130     {
131         GMX_THROW(InvalidInputError(
132                           formatString("Help topic '%s' has no subtopics",
133                                        impl_->currentTopicAsString().c_str())));
134     }
135     const HelpTopicInterface *newTopic = topic.findSubTopic(name);
136     if (newTopic == NULL)
137     {
138         if (impl_->isAtRootTopic())
139         {
140             GMX_THROW(InvalidInputError(
141                               formatString("No help available for '%s'", name)));
142         }
143         else
144         {
145             GMX_THROW(InvalidInputError(
146                               formatString("Help topic '%s' has no subtopic '%s'",
147                                            impl_->currentTopicAsString().c_str(), name)));
148         }
149     }
150     impl_->topicStack_.push_back(newTopic);
151 }
152
153 void HelpManager::enterTopic(const std::string &name)
154 {
155     enterTopic(name.c_str());
156 }
157
158 void HelpManager::writeCurrentTopic() const
159 {
160     const HelpTopicInterface &topic = impl_->currentTopic();
161     topic.writeHelp(impl_->rootContext_);
162 }
163
164 } // namespace gmx