Additional features to TextTableFormatter.
authorTeemu Murtola <teemu.murtola@gmail.com>
Mon, 14 May 2012 05:13:40 +0000 (08:13 +0300)
committerTeemu Murtola <teemu.murtola@gmail.com>
Tue, 29 May 2012 13:56:52 +0000 (16:56 +0300)
Add possibility to print out a table without a header (if there are no
column titles) and possibility to indent the whole table.
Use the new features for formatting the list of commands in
CommandLineModuleManager.

IssueID #666

Change-Id: I2d5aaceaf1c5545ff3be215d27ec30df38fbacde

src/gromacs/commandline/cmdlinemodulemanager.cpp
src/gromacs/onlinehelp/helpformat.cpp
src/gromacs/onlinehelp/helpformat.h
src/gromacs/onlinehelp/tests/helpformat.cpp
src/gromacs/onlinehelp/tests/refdata/TextTableFormatterTest_HandlesEmptyColumnTitles.xml [new file with mode: 0644]
src/gromacs/onlinehelp/tests/refdata/TextTableFormatterTest_HandlesIndentation.xml [new file with mode: 0644]

index 7a65cc72b9412a576a3fbdafb6441155f34c1088..41b7e1640416a6694778a7c3bc5c2041706bb1a3 100644 (file)
@@ -44,6 +44,7 @@
 #include <utility>
 
 #include "gromacs/commandline/cmdlinemodule.h"
+#include "gromacs/onlinehelp/helpformat.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/programinfo.h"
 
@@ -170,12 +171,19 @@ void CommandLineModuleManager::Impl::printModuleList() const
             maxNameLength = nameLength;
         }
     }
+    TextTableFormatter formatter;
+    formatter.addColumn(NULL, maxNameLength + 1, false);
+    formatter.addColumn(NULL, 72 - maxNameLength, true);
+    formatter.setFirstColumnIndent(4);
     fprintf(stderr, "The following commands are available:\n");
     for (module = modules_.begin(); module != modules_.end(); ++module)
     {
         const char *name = module->first.c_str();
         const char *description = module->second->shortDescription();
-        fprintf(stderr, "    %*s  %s\n", -maxNameLength, name, description);
+        formatter.clear();
+        formatter.addColumnLine(0, name);
+        formatter.addColumnLine(1, description);
+        fprintf(stderr, "%s", formatter.formatRow().c_str());
     }
 }
 
index 0779dc96614a1cfba7e115260e114034244911a6..0d269143b0d0bddb79d1b579318adc31f34a282c 100644 (file)
@@ -178,12 +178,16 @@ class TextTableFormatter::Impl
 
         //! Container for column data.
         ColumnList              columns_;
+        //! Indentation before the first column.
+        int                     firstColumnIndent_;
         //! If true, no output has yet been produced.
         bool                    bFirstRow_;
+        //! If true, a header will be printed before the first row.
+        bool                    bPrintHeader_;
 };
 
 TextTableFormatter::Impl::Impl()
-    : bFirstRow_(true)
+    : firstColumnIndent_(0), bFirstRow_(true), bPrintHeader_(false)
 {
 }
 
@@ -202,9 +206,19 @@ TextTableFormatter::~TextTableFormatter()
 
 void TextTableFormatter::addColumn(const char *title, int width, bool bWrap)
 {
+    if (title != NULL && title[0] != '\0')
+    {
+        impl_->bPrintHeader_ = true;
+    }
     impl_->columns_.push_back(Impl::ColumnData(title, width, bWrap));
 }
 
+void TextTableFormatter::setFirstColumnIndent(int indent)
+{
+    GMX_RELEASE_ASSERT(indent >= 0, "Negative indentation not allowed");
+    impl_->firstColumnIndent_ = indent;
+}
+
 bool TextTableFormatter::didOutput() const
 {
     return !impl_->bFirstRow_;
@@ -249,9 +263,10 @@ std::string TextTableFormatter::formatRow()
     std::string result;
     Impl::ColumnList::const_iterator column;
     // Print a header if this is the first line.
-    if (impl_->bFirstRow_)
+    if (impl_->bPrintHeader_ && impl_->bFirstRow_)
     {
         size_t totalWidth = 0;
+        result.append(impl_->firstColumnIndent_, ' ');
         for (column  = impl_->columns_.begin();
              column != impl_->columns_.end();
              ++column)
@@ -270,6 +285,7 @@ std::string TextTableFormatter::formatRow()
             result.append(title);
         }
         result.append("\n");
+        result.append(impl_->firstColumnIndent_, ' ');
         result.append(totalWidth, '-');
         result.append("\n");
     }
@@ -310,6 +326,7 @@ std::string TextTableFormatter::formatRow()
             lineResult.append(value);
             currentWidth += column->width();
         }
+        result.append(impl_->firstColumnIndent_, ' ');
         result.append(lineResult);
         result.append("\n");
     }
index 35a9d61e1e49e68c7457d302cb5afcf9384a4930..bddfa59c4f93050cccd713de378c93aa455f907f 100644 (file)
@@ -86,7 +86,7 @@ void writeHelpTextForConsole(File *file, const std::string &text);
  * responsibility to check that overflows are avoided or are acceptable).
  *
  * Column definitions are first set with addColumn().
- * To format a fow, first call clear().  Then call addColumnLine() to add text
+ * To format a row, first call clear().  Then call addColumnLine() to add text
  * to each column (can be called multiple times on a single column to add
  * multiple lines), and possibly setColumnFirstLineOffset() to adjust the line
  * from which the column output should start.  Finally, call formatRow() to
@@ -142,6 +142,14 @@ class TextTableFormatter
          * The length of \p title must not exceed \p width.
          */
         void addColumn(const char *title, int width, bool bWrap);
+        /*! \brief
+         * Sets amount on indentation before the first column.
+         *
+         * \param[in]  indent  Number of spaces to use for indenting.
+         *
+         * Does not throw.
+         */
+        void setFirstColumnIndent(int indent);
 
         /*! \brief
          * Whether formatRow() has been successfully called.
@@ -202,7 +210,7 @@ class TextTableFormatter
          * addColumnLine() and setColumnFirstLineOffset().
          *
          * If this is the first line to be formatted, a header is also added to
-         * the beginning of the returned string.
+         * the beginning of the returned string if any column has a title.
          *
          * The return value always terminates with a newline.
          *
index 7cb6f4a2174c700bd6fc1c9c502353e62029c8f7..dbe0ac5331bcfb3c5c1c79a1868a13d056566c07 100644 (file)
@@ -54,12 +54,12 @@ const char g_wrapText2[] = "A quick brown fox jumps\nover the lazy dog";
 class TextTableFormatterTest : public gmx::test::StringTestBase
 {
     public:
-        TextTableFormatterTest();
+        void setupStandardColumns();
 
         gmx::TextTableFormatter formatter_;
 };
 
-TextTableFormatterTest::TextTableFormatterTest()
+void TextTableFormatterTest::setupStandardColumns()
 {
     formatter_.addColumn("Col1", 4, false);
     formatter_.addColumn("Col2", 4, false);
@@ -69,6 +69,34 @@ TextTableFormatterTest::TextTableFormatterTest()
 
 TEST_F(TextTableFormatterTest, HandlesBasicCase)
 {
+    setupStandardColumns();
+    formatter_.clear();
+    formatter_.addColumnLine(0, "foo");
+    formatter_.addColumnLine(1, "bar");
+    formatter_.addColumnLine(2, g_wrapText);
+    formatter_.addColumnLine(3, g_wrapText2);
+    checkText(formatter_.formatRow(), "FormattedTable");
+}
+
+TEST_F(TextTableFormatterTest, HandlesEmptyColumnTitles)
+{
+    formatter_.addColumn(NULL, 4, false);
+    formatter_.addColumn("", 4, false);
+    formatter_.addColumn(NULL, 14, true);
+    formatter_.addColumn("", 14, true);
+
+    formatter_.clear();
+    formatter_.addColumnLine(0, "foo");
+    formatter_.addColumnLine(1, "bar");
+    formatter_.addColumnLine(2, g_wrapText);
+    formatter_.addColumnLine(3, g_wrapText2);
+    checkText(formatter_.formatRow(), "FormattedTable");
+}
+
+TEST_F(TextTableFormatterTest, HandlesIndentation)
+{
+    setupStandardColumns();
+    formatter_.setFirstColumnIndent(4);
     formatter_.clear();
     formatter_.addColumnLine(0, "foo");
     formatter_.addColumnLine(1, "bar");
@@ -79,6 +107,7 @@ TEST_F(TextTableFormatterTest, HandlesBasicCase)
 
 TEST_F(TextTableFormatterTest, HandlesOverflowingLines)
 {
+    setupStandardColumns();
     formatter_.clear();
     formatter_.addColumnLine(0, "foobar");
     formatter_.addColumnLine(1, "barfoo");
@@ -104,6 +133,7 @@ TEST_F(TextTableFormatterTest, HandlesOverflowingLines)
 
 TEST_F(TextTableFormatterTest, HandlesEmptyColumns)
 {
+    setupStandardColumns();
     formatter_.clear();
     formatter_.addColumnLine(0, "foo");
     formatter_.addColumnLine(1, "bar");
diff --git a/src/gromacs/onlinehelp/tests/refdata/TextTableFormatterTest_HandlesEmptyColumnTitles.xml b/src/gromacs/onlinehelp/tests/refdata/TextTableFormatterTest_HandlesEmptyColumnTitles.xml
new file mode 100644 (file)
index 0000000..8787afc
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="FormattedTable"><![CDATA[
+foo  bar  A quick brown  A quick brown
+          fox jumps over fox jumps
+          the lazy dog   over the lazy
+                         dog
+]]></String>
+</ReferenceData>
diff --git a/src/gromacs/onlinehelp/tests/refdata/TextTableFormatterTest_HandlesIndentation.xml b/src/gromacs/onlinehelp/tests/refdata/TextTableFormatterTest_HandlesIndentation.xml
new file mode 100644 (file)
index 0000000..12cb7bf
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="FormattedTable"><![CDATA[
+    Col1 Col2 Col3Wrap       Col4Wrap
+    ---------------------------------------
+    foo  bar  A quick brown  A quick brown
+              fox jumps over fox jumps
+              the lazy dog   over the lazy
+                             dog
+]]></String>
+</ReferenceData>