2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2012,2013, 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.
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.
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.
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.
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.
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.
37 * Implements functions in helpformat.h.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_onlinehelp
42 #include "helpformat.h"
48 #include "gromacs/onlinehelp/helpwritercontext.h"
49 #include "gromacs/utility/gmxassert.h"
50 #include "gromacs/utility/stringutil.h"
55 /********************************************************************
56 * TextTableFormatter::Impl
60 * Private implementation class for TextTableFormatter.
62 * \ingroup module_onlinehelp
64 class TextTableFormatter::Impl
69 ColumnData(const char *title, int width, bool bWrap)
70 : title_(title != NULL ? title : ""),
71 width_(width), bWrap_(bWrap), firstLine_(0)
73 GMX_ASSERT(width >= 0, "Negative width not possible");
74 GMX_ASSERT(title_.length() <= static_cast<size_t>(width),
75 "Title too long for column width");
78 //! Returns the title of the column.
79 const std::string &title() const { return title_; }
80 //! Returns the width of the column.
81 int width() const { return width_; }
83 * Returns the first line offset for the current row.
85 * Note that the return value may be outside the printed lines if
88 int firstLine() const { return firstLine_; }
90 * Returns the index of the last line with text for the current row.
92 * If there is no text, returns -1.
100 return firstLine_ + static_cast<int>(lines_.size()) - 1;
103 * Returns the text for a line.
105 * \param[in] line Zero-based line index.
106 * \returns Text for line \p line, or empty string if \p line has
107 * no text for this column.
109 std::string textForLine(int line) const
111 // The second conditional matches if there are no lines
112 if (line < firstLine() || line > lastLine())
114 return std::string();
116 return lines_[line - firstLine()];
119 //! Statit data: title of the column.
121 //! Static data: width of the column.
123 //! Static data: whether to automatically wrap input text.
125 //! First line offset for the current row.
127 //! Text lines for the current row.
128 std::vector<std::string> lines_;
131 //! Container type for column data.
132 typedef std::vector<ColumnData> ColumnList;
134 //! Initializes data for an empty formatter.
138 * Convenience method for checked access to data for a column.
140 * \param[in] index Zero-based column index.
141 * \returns \c columns_[index]
143 ColumnData &columnData(int index)
145 GMX_ASSERT(index >= 0 && index < static_cast<int>(columns_.size()),
146 "Invalid column index");
147 return columns_[index];
149 //! \copydoc columnData()
150 const ColumnData &columnData(int index) const
152 return const_cast<Impl *>(this)->columnData(index);
155 //! Container for column data.
157 //! Indentation before the first column.
158 int firstColumnIndent_;
159 //! If true, no output has yet been produced.
161 //! If true, a header will be printed before the first row.
165 TextTableFormatter::Impl::Impl()
166 : firstColumnIndent_(0), bFirstRow_(true), bPrintHeader_(false)
170 /********************************************************************
174 TextTableFormatter::TextTableFormatter()
179 TextTableFormatter::~TextTableFormatter()
183 void TextTableFormatter::addColumn(const char *title, int width, bool bWrap)
185 if (title != NULL && title[0] != '\0')
187 impl_->bPrintHeader_ = true;
189 impl_->columns_.push_back(Impl::ColumnData(title, width, bWrap));
192 void TextTableFormatter::setFirstColumnIndent(int indent)
194 GMX_RELEASE_ASSERT(indent >= 0, "Negative indentation not allowed");
195 impl_->firstColumnIndent_ = indent;
198 bool TextTableFormatter::didOutput() const
200 return !impl_->bFirstRow_;
203 void TextTableFormatter::clear()
205 Impl::ColumnList::iterator i;
206 for (i = impl_->columns_.begin(); i != impl_->columns_.end(); ++i)
213 void TextTableFormatter::addColumnLine(int index, const std::string &text)
215 Impl::ColumnData &column = impl_->columnData(index);
216 TextLineWrapper wrapper;
219 wrapper.settings().setLineLength(column.width());
221 std::vector<std::string> lines(wrapper.wrapToVector(text));
222 column.lines_.insert(column.lines_.end(), lines.begin(), lines.end());
225 void TextTableFormatter::addColumnHelpTextBlock(
226 int index, const HelpWriterContext &context, const std::string &text)
228 Impl::ColumnData &column = impl_->columnData(index);
229 TextLineWrapperSettings settings;
232 settings.setLineLength(column.width());
234 std::vector<std::string> lines(
235 context.substituteMarkupAndWrapToVector(settings, text));
236 column.lines_.insert(column.lines_.end(), lines.begin(), lines.end());
239 void TextTableFormatter::setColumnFirstLineOffset(int index, int firstLine)
241 GMX_ASSERT(firstLine >= 0, "Invalid first line");
242 Impl::ColumnData &column = impl_->columnData(index);
243 column.firstLine_ = firstLine;
246 int TextTableFormatter::lastColumnLine(int index) const
248 return impl_->columnData(index).lastLine();
251 std::string TextTableFormatter::formatRow()
254 Impl::ColumnList::const_iterator column;
255 // Print a header if this is the first line.
256 if (impl_->bPrintHeader_ && impl_->bFirstRow_)
258 size_t totalWidth = 0;
259 result.append(impl_->firstColumnIndent_, ' ');
260 for (column = impl_->columns_.begin();
261 column != impl_->columns_.end();
264 std::string title(column->title());
265 if (column != impl_->columns_.end() - 1)
267 title.resize(column->width() + 1, ' ');
268 totalWidth += title.length();
272 totalWidth += std::min(column->width(),
273 static_cast<int>(title.length() + 13));
275 result.append(title);
278 result.append(impl_->firstColumnIndent_, ' ');
279 result.append(totalWidth, '-');
283 // Compute the last applicable line.
285 for (column = impl_->columns_.begin();
286 column != impl_->columns_.end();
289 lastLine = std::max(lastLine, column->lastLine());
292 // Format the actual row data.
293 for (int line = 0; line <= lastLine; ++line)
295 std::string lineResult;
296 size_t currentWidth = 0;
297 for (column = impl_->columns_.begin();
298 column != impl_->columns_.end();
301 std::string value(column->textForLine(line));
302 if (column != impl_->columns_.begin())
307 lineResult.append(" ");
308 if (lineResult.length() < currentWidth)
310 lineResult.resize(currentWidth, ' ');
314 // TODO: Rewrap the text if wrapping is on and the previous columns
316 lineResult.append(value);
317 currentWidth += column->width();
319 result.append(impl_->firstColumnIndent_, ' ');
320 result.append(lineResult);
324 impl_->bFirstRow_ = false;