Update my e-mail address on author lines.
[alexxy/gromacs.git] / src / gromacs / onlinehelp / helptopic.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Implements classes and functions from helptopic.h.
34  *
35  * \author Teemu Murtola <teemu.murtola@gmail.com>
36  * \ingroup module_onlinehelp
37  */
38 #include "helptopic.h"
39
40 #include <map>
41 #include <utility>
42
43 #include "gromacs/onlinehelp/helpformat.h"
44 #include "gromacs/onlinehelp/helpwritercontext.h"
45 #include "gromacs/utility/exceptions.h"
46 #include "gromacs/utility/file.h"
47 #include "gromacs/utility/gmxassert.h"
48 #include "gromacs/utility/stringutil.h"
49
50 namespace gmx
51 {
52
53 /*! \cond libapi */
54 void writeBasicHelpTopic(const HelpWriterContext  &context,
55                          const HelpTopicInterface &topic,
56                          const std::string        &text)
57 {
58     const char *title = topic.title();
59     if (title != NULL && title[0] != '\0')
60     {
61         context.writeTitle(title);
62     }
63     context.writeTextBlock(text);
64 }
65 //! \endcond
66
67 /********************************************************************
68  * AbstractSimpleHelpTopic
69  */
70
71 bool AbstractSimpleHelpTopic::hasSubTopics() const
72 {
73     return false;
74 }
75
76 const HelpTopicInterface *
77 AbstractSimpleHelpTopic::findSubTopic(const char *name) const
78 {
79     return NULL;
80 }
81
82 void AbstractSimpleHelpTopic::writeHelp(const HelpWriterContext &context) const
83 {
84     writeBasicHelpTopic(context, *this, helpText());
85 }
86
87 /********************************************************************
88  * AbstractCompositeHelpTopic::Impl
89  */
90
91 /*! \internal \brief
92  * Private implementation class for AbstractCompositeHelpTopic.
93  *
94  * \ingroup module_onlinehelp
95  */
96 class AbstractCompositeHelpTopic::Impl
97 {
98     public:
99         //! Container for mapping subtopic names to help topic objects.
100         typedef std::map<std::string, HelpTopicPointer> SubTopicMap;
101
102         /*! \brief
103          * Maps subtopic names to help topic objects.
104          *
105          * Owns the contained subtopics.
106          */
107         SubTopicMap             subtopics_;
108 };
109
110 /********************************************************************
111  * AbstractCompositeHelpTopic
112  */
113
114 AbstractCompositeHelpTopic::AbstractCompositeHelpTopic()
115     : impl_(new Impl)
116 {
117 }
118
119 AbstractCompositeHelpTopic::~AbstractCompositeHelpTopic()
120 {
121 }
122
123 bool AbstractCompositeHelpTopic::hasSubTopics() const
124 {
125     return !impl_->subtopics_.empty();
126 }
127
128 const HelpTopicInterface *
129 AbstractCompositeHelpTopic::findSubTopic(const char *name) const
130 {
131     Impl::SubTopicMap::const_iterator topic = impl_->subtopics_.find(name);
132     if (topic == impl_->subtopics_.end())
133     {
134         return NULL;
135     }
136     return topic->second.get();
137 }
138
139 void AbstractCompositeHelpTopic::writeHelp(const HelpWriterContext &context) const
140 {
141     writeBasicHelpTopic(context, *this, helpText());
142     writeSubTopicList(context, "\nAvailable subtopics:");
143 }
144
145 bool
146 AbstractCompositeHelpTopic::writeSubTopicList(const HelpWriterContext &context,
147                                               const std::string       &title) const
148 {
149     if (context.outputFormat() != eHelpOutputFormat_Console)
150     {
151         // TODO: Implement once the situation with Redmine issue #969 is more
152         // clear.
153         GMX_THROW(NotImplementedError(
154                           "Subtopic listing is not implemented for this output format"));
155     }
156     int maxNameLength = 0;
157     Impl::SubTopicMap::const_iterator topic;
158     for (topic = impl_->subtopics_.begin(); topic != impl_->subtopics_.end(); ++topic)
159     {
160         const char *title = topic->second->title();
161         if (title == NULL || title[0] == '\0')
162         {
163             continue;
164         }
165         int nameLength = static_cast<int>(topic->first.length());
166         if (nameLength > maxNameLength)
167         {
168             maxNameLength = nameLength;
169         }
170     }
171     if (maxNameLength == 0)
172     {
173         return false;
174     }
175     File              &file = context.outputFile();
176     TextTableFormatter formatter;
177     formatter.addColumn(NULL, maxNameLength + 1, false);
178     formatter.addColumn(NULL, 72 - maxNameLength, true);
179     formatter.setFirstColumnIndent(4);
180     file.writeLine(title);
181     for (topic = impl_->subtopics_.begin(); topic != impl_->subtopics_.end(); ++topic)
182     {
183         const char *name  = topic->first.c_str();
184         const char *title = topic->second->title();
185         if (title != NULL && title[0] != '\0')
186         {
187             formatter.clear();
188             formatter.addColumnLine(0, name);
189             formatter.addColumnLine(1, title);
190             file.writeString(formatter.formatRow());
191         }
192     }
193     return true;
194 }
195
196 void AbstractCompositeHelpTopic::addSubTopic(HelpTopicPointer topic)
197 {
198     GMX_ASSERT(impl_->subtopics_.find(topic->name()) == impl_->subtopics_.end(),
199                "Attempted to register a duplicate help topic name");
200     impl_->subtopics_.insert(std::make_pair(std::string(topic->name()),
201                                             move(topic)));
202 }
203
204 } // namespace gmx