diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0c6327393..4d55b8808 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,7 +16,6 @@ set (task_SRCS API.cpp API.h Duration.cpp Duration.h File.cpp File.h Filter.cpp Filter.h - Grid.cpp Grid.h Hooks.cpp Hooks.h JSON.cpp JSON.h Location.cpp Location.h @@ -29,7 +28,6 @@ set (task_SRCS API.cpp API.h Subst.cpp Subst.h TDB.cpp TDB.h TDB2.cpp TDB2.h - Table.cpp Table.h Task.cpp Task.h Taskmod.cpp Taskmod.h Timer.cpp Timer.h diff --git a/src/Grid.cpp b/src/Grid.cpp deleted file mode 100644 index eba992c20..000000000 --- a/src/Grid.cpp +++ /dev/null @@ -1,421 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// taskwarrior - a command line task list manager. -// -// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez. -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free Software -// Foundation; either version 2 of the License, or (at your option) any later -// version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License along with -// this program; if not, write to the -// -// Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, -// Boston, MA -// 02110-1301 -// USA -// -// -// -// Grid implements a sparse 2D array of Cell objects. Grid makes every effort -// to perform well on cell insertion and retrieval. A Cell is a variant type, -// capable of storing char, bool, int, float, double and std::string types. -// -// Every cell is accessible from both mColumns and mRows. This allows the -// client code to specify which method is used, because there will be a -// performance penalty with one of the methods, depending on the layout of -// cells within the grid. -// -// mColumns, like mRows, is a vector of a vector of Cell*. -// -// mColumns -// [0..n] -// +---+---+-----------+---+ -// | 0 | 1 | | n | -// +---+---+-----------+---+ -// | | -// v | -// +---+ . +---+ . | . -// mRows | 0 | -------> | x | v -// [0..1] +---+ . +---+ +---+ -// | 1 | -------> | y | --------> | z | -// +---+ . +---+ +---+ -// | | -// | | -// | | -// +---+ . . . . . -// | n | -// +---+ . . . . . -// -// -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - -//////////////////////////////////////////////////////////////////////////////// -Grid::Grid () -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// The cells are deleted via their mRows reference, not by their mColumns -// reference. This is because the cells are doubly-linked, and so the -// convention is that rows own cells, columns merely own pointers. -Grid::~Grid () -{ - std::vector < std::vector * >::iterator row; - std::vector ::iterator col; - for (row = mRows.begin (); row != mRows.end (); ++row) - if (*row) - for (col = (*row)->begin (); col != (*row)->end (); ++col) - if (*col) - delete *col; - - std::vector < std::vector * >::iterator it; - for (it = mRows.begin (); it != mRows.end (); ++it) - if (*it) - delete *it; - - for (it = mColumns.begin (); it != mColumns.end (); ++it) - if (*it) - delete *it; -} - -//////////////////////////////////////////////////////////////////////////////// -void Grid::add ( - const unsigned int row, - const unsigned int col, - const bool value) -{ - expandGrid (row, col); - insertCell (row, col, new Cell (value)); -} - -void Grid::add ( - const unsigned int row, - const unsigned int col, - const char value) -{ - expandGrid (row, col); - insertCell (row, col, new Cell (value)); -} - -void Grid::add ( - const unsigned int row, - const unsigned int col, - const int value) -{ - expandGrid (row, col); - insertCell (row, col, new Cell (value)); -} - -void Grid::add ( - const unsigned int row, - const unsigned int col, - const float value) -{ - expandGrid (row, col); - insertCell (row, col, new Cell (value)); -} - -void Grid::add ( - const unsigned int row, - const unsigned int col, - const double value) -{ - expandGrid (row, col); - insertCell (row, col, new Cell (value)); -} - -void Grid::add ( - const unsigned int row, - const unsigned int col, - const char* value) -{ - expandGrid (row, col); - insertCell (row, col, new Cell (std::string (value))); -} - -void Grid::add ( - const unsigned int row, - const unsigned int col, - const std::string& value) -{ - expandGrid (row, col); - insertCell (row, col, new Cell (value)); -} - -//////////////////////////////////////////////////////////////////////////////// -unsigned int Grid::width () const -{ - return mColumns.size (); -} - -unsigned int Grid::height () const -{ - return mRows.size (); -} - -//////////////////////////////////////////////////////////////////////////////// -Grid::Cell* Grid::byRow (const unsigned int row, const unsigned int col) const -{ - if (row < mRows.size () && - mRows[row] != NULL && - col < mRows[row]->size ()) - return (*mRows[row])[col]; - - return NULL; -} - -Grid::Cell* Grid::byColumn (const unsigned int row, const unsigned int col) const -{ - if (col < mColumns.size () && - mColumns[col] != NULL && - row < mColumns[col]->size ()) - return (*mColumns[col])[row]; - - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////// -void Grid::expandGrid (const unsigned int row, const unsigned int col) -{ - - // If the new row is outside the bounds of the current grid, add blank rows to - // pad, then a new row vector. - if (row >= mRows.size ()) - { - for (unsigned int r = mRows.size (); r <= row; ++r) - if (r < row) - mRows.push_back (NULL); - else - mRows.push_back (new std::vector ); - } - // If the new row is within the bounds of the current grid, ensure that the - // row points to a vector of cells. - else if (mRows[row] == NULL) - mRows[row] = new std::vector ; - - if (col >= mRows[row]->size ()) - for (unsigned int c = mRows[row]->size (); c <= col; ++c) - mRows[row]->push_back (NULL); - - // If the new col is outside the bounds of the current grid, add blank cols to - // pad, then a new col vector. - if (col >= mColumns.size ()) - { - for (unsigned int c = mColumns.size (); c <= col; ++c) - if (c < col) - mColumns.push_back (NULL); - else - mColumns.push_back (new std::vector ); - } - // If the new col is within the bounds of the current grid, ensure that the - // col points to a vector of cells. - else if (mColumns[col] == NULL) - mColumns[col] = new std::vector ; - - if (row >= mColumns[col]->size ()) - for (unsigned int r = mColumns[col]->size (); r <= row; ++r) - mColumns[col]->push_back (NULL); -} - -//////////////////////////////////////////////////////////////////////////////// -void Grid::insertCell ( - const unsigned int row, - const unsigned int col, - Cell* cell) -{ - // Delete any existing cell, because cells are owned by rows, not columns. - if ((*mRows[row])[col] != NULL) - delete (*mRows[row])[col]; - - (*mRows[row])[col] = cell; - (*mColumns[col])[row] = cell; -} - -//////////////////////////////////////////////////////////////////////////////// -Grid::Cell::Cell (const bool value) -: mType (CELL_BOOL) -, mBool (value) -{ -} - -Grid::Cell::Cell (const char value) -: mType (CELL_CHAR) -, mChar (value) -{ -} - -Grid::Cell::Cell (const int value) -: mType (CELL_INT) -, mInt (value) -{ -} - -Grid::Cell::Cell (const float value) -: mType (CELL_FLOAT) -, mFloat (value) -{ -} - -Grid::Cell::Cell (const double value) -: mType (CELL_DOUBLE) -, mDouble (value) -{ -} - -Grid::Cell::Cell (const std::string& value) -: mType (CELL_STRING) -, mString (value) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// These cast operators make a best approximation to an appropriate rendering, -// given the format change. -Grid::Cell::operator bool () const -{ - switch (mType) - { - case CELL_BOOL: return mBool; - case CELL_CHAR: return mChar != '\0' && - mChar != ' ' && - mChar != '0'; - case CELL_INT: return mInt != 0; - case CELL_FLOAT: return mFloat != 0.0; - case CELL_DOUBLE: return mDouble != 0.0; - case CELL_STRING: return mString.length () > 0; - } - - return false; -} - -Grid::Cell::operator char () const -{ - switch (mType) - { - case CELL_BOOL: return mBool ? 'Y' : 'N'; // TODO i18n - case CELL_CHAR: return mChar; - case CELL_INT: return (char) mInt; - case CELL_FLOAT: return (char) (int) mFloat; - case CELL_DOUBLE: return (char) (int) mDouble; - case CELL_STRING: return mString[0]; - } - - return '\0'; -} - -Grid::Cell::operator int () const -{ - switch (mType) - { - case CELL_BOOL: return mBool ? 1 : 0; - case CELL_CHAR: return (int) mChar; - case CELL_INT: return mInt; - case CELL_FLOAT: return (int) mFloat; - case CELL_DOUBLE: return (int) mDouble; - case CELL_STRING: return atoi (mString.c_str ()); - } - - return 0; -} - -Grid::Cell::operator float () const -{ - switch (mType) - { - case CELL_BOOL: return mBool ? 1.0 : 0.0; - case CELL_CHAR: return (float) (int) mChar; - case CELL_INT: return (float) mInt; - case CELL_FLOAT: return mFloat; - case CELL_DOUBLE: return (float) mDouble; - case CELL_STRING: return (float) atof (mString.c_str ()); - } - - return 0.0; -} - -Grid::Cell::operator double () const -{ - switch (mType) - { - case CELL_BOOL: return mBool ? 1.0 : 0.0; - case CELL_CHAR: return (double) (int) mChar; - case CELL_INT: return (double) mInt; - case CELL_FLOAT: return (double) mFloat; - case CELL_DOUBLE: return mDouble; - case CELL_STRING: return (double) atof (mString.c_str ()); - } - - return 0.0; -} - -Grid::Cell::operator std::string () const -{ - switch (mType) - { - case CELL_BOOL: return mBool ? "true" : "false"; // TODO i18n - case CELL_CHAR: return format (mChar); - case CELL_INT: return format (mInt); - case CELL_FLOAT: return format (mFloat, 1, 6); - case CELL_DOUBLE: return format (mDouble, 1, 8); - case CELL_STRING: return mString; - } - - return std::string (""); -} - -//////////////////////////////////////////////////////////////////////////////// -bool Grid::Cell::operator== (const Grid::Cell& rhs) const -{ - switch (mType) - { - case CELL_BOOL: return mBool == rhs.mBool ? true : false; - case CELL_CHAR: return mChar == rhs.mChar ? true : false; - case CELL_INT: return mInt == rhs.mInt ? true : false; - case CELL_FLOAT: return mFloat == rhs.mFloat ? true : false; - case CELL_DOUBLE: return mDouble == rhs.mDouble ? true : false; - case CELL_STRING: return mString == rhs.mString ? true : false; - default: break; // To prevent warnings. - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Grid::Cell::operator!= (const Grid::Cell& rhs) const -{ - switch (mType) - { - case CELL_BOOL: return mBool != rhs.mBool ? true : false; - case CELL_CHAR: return mChar != rhs.mChar ? true : false; - case CELL_INT: return mInt != rhs.mInt ? true : false; - case CELL_FLOAT: return mFloat != rhs.mFloat ? true : false; - case CELL_DOUBLE: return mDouble != rhs.mDouble ? true : false; - case CELL_STRING: return mString != rhs.mString ? true : false; - default: break; // To prevent warnings. - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -Grid::Cell::cellType Grid::Cell::type () const -{ - return mType; -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Grid.h b/src/Grid.h deleted file mode 100644 index d9a9ea22f..000000000 --- a/src/Grid.h +++ /dev/null @@ -1,106 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// taskwarrior - a command line task list manager. -// -// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez. -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free Software -// Foundation; either version 2 of the License, or (at your option) any later -// version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License along with -// this program; if not, write to the -// -// Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, -// Boston, MA -// 02110-1301 -// USA -// -//////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDED_GRID -#define INCLUDED_GRID - -#include -#include -#include - -//////////////////////////////////////////////////////////////////////////////// -class Grid -{ -public: - class Cell - { - public: - Cell (const bool); - Cell (const char); - Cell (const int); - Cell (const float); - Cell (const double); - Cell (const std::string&); - - Cell (const Cell&); - Cell& operator= (const Cell&); - - operator bool () const; - operator char () const; - operator int () const; - operator float () const; - operator double () const; - operator std::string () const; - bool operator== (const Cell&) const; - bool operator!= (const Cell&) const; - - enum cellType {CELL_BOOL, CELL_CHAR, CELL_INT, CELL_FLOAT, CELL_DOUBLE, CELL_STRING}; - - cellType type () const; - - private: - cellType mType; - bool mBool; - char mChar; - int mInt; - float mFloat; - double mDouble; - std::string mString; - }; - -public: - Grid (); - ~Grid (); - - Grid (const Grid&); - Grid& operator= (const Grid&); - - void add (const unsigned int, const unsigned int, const bool); - void add (const unsigned int, const unsigned int, const char); - void add (const unsigned int, const unsigned int, const int); - void add (const unsigned int, const unsigned int, const float); - void add (const unsigned int, const unsigned int, const double); - void add (const unsigned int, const unsigned int, const char*); - void add (const unsigned int, const unsigned int, const std::string&); - - unsigned int width () const; - unsigned int height () const; - - Cell* byRow (const unsigned int, const unsigned int) const; - Cell* byColumn (const unsigned int, const unsigned int) const; - -private: - void expandGrid (const unsigned int, const unsigned int); - void insertCell (const unsigned int, const unsigned int, Cell*); - -private: - std::vector < std::vector * > mRows; - std::vector < std::vector * > mColumns; -}; - -#endif -//////////////////////////////////////////////////////////////////////////////// - diff --git a/src/TDB2.cpp b/src/TDB2.cpp index 03ea99e75..c3697a21d 100644 --- a/src/TDB2.cpp +++ b/src/TDB2.cpp @@ -284,7 +284,7 @@ void TDB2::commit () #include "TDB.h" #include "Directory.h" #include "File.h" -#include "Table.h" +#include "ViewText.h" #include "Timer.h" #include "Color.h" #include "main.h" @@ -1000,24 +1000,12 @@ void TDB::undo () // Attributes are all there is, so figure the different attribute names // between before and after. - Table table; - table.setTableWidth (context.getWidth ()); - table.setTableIntraPadding (2); - table.addColumn (" "); - table.addColumn ("Prior Values"); - table.addColumn ("Current Values"); - - if (context.color () && context.config.getBoolean ("fontunderline")) - { - table.setColumnUnderline (1); - table.setColumnUnderline (2); - } - else - table.setTableDashedUnderline (); - - table.setColumnWidth (0, Table::minimum); - table.setColumnWidth (1, Table::flexible); - table.setColumnWidth (2, Table::flexible); + ViewText view; + view.width (context.getWidth ()); + view.intraPadding (2); + view.add (Column::factory ("string", "")); + view.add (Column::factory ("string", "Prior Values")); + view.add (Column::factory ("string", "Current Values")); Task after (current); @@ -1040,10 +1028,9 @@ void TDB::undo () int row; foreach (name, beforeOnly) { - row = table.addRow (); - table.addCell (row, 0, *name); - table.addCell (row, 1, renderAttribute (*name, before.get (*name))); - table.setCellColor (row, 1, color_red); + row = view.addRow (); + view.set (row, 0, *name, red); + view.set (row, 1, renderAttribute (*name, before.get (*name)), red); } foreach (name, before) @@ -1053,25 +1040,18 @@ void TDB::undo () if (currentValue != "") { - row = table.addRow (); - table.addCell (row, 0, name->first); - table.addCell (row, 1, renderAttribute (name->first, priorValue)); - table.addCell (row, 2, renderAttribute (name->first, currentValue)); - - if (priorValue != currentValue) - { - table.setCellColor (row, 1, color_red); - table.setCellColor (row, 2, color_green); - } + row = view.addRow (); + view.set (row, 0, name->first); + view.set (row, 1, renderAttribute (name->first, priorValue), priorValue != currentValue ? color_red : color_green); + view.set (row, 2, renderAttribute (name->first, currentValue), priorValue != currentValue ? color_red : color_green); } } foreach (name, afterOnly) { - row = table.addRow (); - table.addCell (row, 0, *name); - table.addCell (row, 2, renderAttribute (*name, after.get (*name))); - table.setCellColor (row, 2, color_green); + row = view.addRow (); + view.set (row, 0, *name); + view.set (row, 2, renderAttribute (*name, after.get (*name)), color_green); } } else @@ -1079,15 +1059,14 @@ void TDB::undo () int row; foreach (name, after) { - row = table.addRow (); - table.addCell (row, 0, name->first); - table.addCell (row, 2, renderAttribute (name->first, after.get (name->first))); - table.setCellColor (row, 2, color_green); + row = view.addRow (); + view.set (row, 0, name->first); + view.set (row, 2, renderAttribute (name->first, after.get (name->first)), color_green); } } std::cout << "\n" - << table.render () + << view.render () << "\n"; } @@ -1114,27 +1093,21 @@ void TDB::undo () Task after (current); // Generate table header. - Table table; - table.setTableWidth (context.getWidth ()); - table.setTableIntraPadding (2); - table.addColumn (" "); - table.addColumn (" "); - table.setColumnWidth (0, Table::minimum); - table.setColumnWidth (1, Table::flexible); - table.setColumnJustification (0, Table::right); - table.setColumnJustification (1, Table::left); + ViewText view + view.width (context.getWidth ()); + view.intraPadding (2); + view.addColumn (Column::factory ("string.right", "")); + view.addColumn (Column::factory ("string", "")); - int row = table.addRow (); - table.addCell (row, 0, "--- previous state"); - table.addCell (row, 1, "Undo will restore this state"); - table.setRowColor (row, color_red); + int row = view.addRow (); + view.set (row, 0, "--- previous state", color_red); + view.set (row, 1, "Undo will restore this state", color_red); - row = table.addRow (); - table.addCell (row, 0, "+++ current state "); // Note trailing space. - table.addCell (row, 1, "Change made " + lastChange.toString (context.config.get ("dateformat"))); - table.setRowColor (row, color_green); + row = view.addRow (); + view.set (row, 0, "+++ current state ", color_green); // Note trailing space. + view.set (row, 1, "Change made " + lastChange.toString (context.config.get ("dateformat")), color_green); - table.addRow (); + view.addRow (); // Add rows to table showing diffs. std::vector all; @@ -1172,55 +1145,49 @@ void TDB::undo () { // Show nothing - no point displaying that which did not change. - // row = table.addRow (); - // table.addCell (row, 0, *a + ":"); - // table.addCell (row, 1, before_att); + // row = view.addRow (); + // view.set (row, 0, *a + ":"); + // view.set (row, 1, before_att); } // Attribute deleted. else if (before_att != "" && after_att == "") { - row = table.addRow (); - table.addCell (row, 0, "-" + *a + ":"); - table.addCell (row, 1, before_att); - table.setRowColor (row, color_red); + row = view.addRow (); + view.set (row, 0, "-" + *a + ":", color_red); + view.set (row, 1, before_att, color_red); - row = table.addRow (); - table.addCell (row, 0, "+" + *a + ":"); - table.setRowColor (row, color_green); + row = view.addRow (); + view.set (row, 0, "+" + *a + ":", color_green); } // Attribute added. else if (before_att == "" && after_att != "") { - row = table.addRow (); - table.addCell (row, 0, "-" + *a + ":"); - table.setRowColor (row, color_red); + row = view.addRow (); + view.set (row, 0, "-" + *a + ":", color_red); - row = table.addRow (); - table.addCell (row, 0, "+" + *a + ":"); - table.addCell (row, 1, after_att); - table.setRowColor (row, color_green); + row = view.addRow (); + view.set (row, 0, "+" + *a + ":", color_green); + view.set (row, 1, after_att, color_green); } // Attribute changed. else { - row = table.addRow (); - table.addCell (row, 0, "-" + *a + ":"); - table.addCell (row, 1, before_att); - table.setRowColor (row, color_red); + row = view.addRow (); + view.set (row, 0, "-" + *a + ":", color_red); + view.set (row, 1, before_att, color_red); - row = table.addRow (); - table.addCell (row, 0, "+" + *a + ":"); - table.addCell (row, 1, after_att); - table.setRowColor (row, color_green); + row = view.addRow (); + view.set (row, 0, "+" + *a + ":", color_green); + view.set (row, 1, after_att, color_green); } } } std::cout << "\n" - << table.render () + << view.render () << "\n"; } diff --git a/src/Table.cpp b/src/Table.cpp deleted file mode 100644 index 19fde779c..000000000 --- a/src/Table.cpp +++ /dev/null @@ -1,895 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// taskwarrior - a command line task list manager. -// -// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez. -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free Software -// Foundation; either version 2 of the License, or (at your option) any later -// version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License along with -// this program; if not, write to the -// -// Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, -// Boston, MA -// 02110-1301 -// USA -// -// -// -// Attributes Table Row Column Cell -// ---------------------------------------------------- -// foreground color Y Y Y Y -// background color Y Y Y Y -// padding Y Y Y Y -// wrap Y Y Y Y -// width Y - Y Y -// height - Y - Y -// justification Y Y Y Y -// -// Precedence -// If attributes conflict, the precedence order is: -// cell -// row -// column -// table -// -//////////////////////////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include "Table.h" -#include "Date.h" -#include "Duration.h" -#include "Timer.h" -#include "text.h" -#include "utf8.h" -#include "util.h" -#include "Context.h" - -extern Context context; -Table* table = NULL; - -//////////////////////////////////////////////////////////////////////////////// -Table::Table () - : mRows (0) - , mIntraPadding (1) - , mDashedUnderline (false) - , mTablePadding (0) - , mTableWidth (0) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Table::~Table () -{ -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setTableAlternateColor (const Color& c) -{ - alternate = c; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setTablePadding (int padding) -{ - mTablePadding = padding; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setTableIntraPadding (int padding) -{ - mIntraPadding = padding; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setTableWidth (int width) -{ - assert (width > 0); - mTableWidth = width; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setTableDashedUnderline () -{ - mDashedUnderline = true; -} - -//////////////////////////////////////////////////////////////////////////////// -int Table::addColumn (const std::string& col) -{ - mSpecifiedWidth.push_back (minimum); - mMaxDataWidth.push_back (col == "" ? 1 : utf8_length (col)); - mCalculatedWidth.push_back (0); - mColumnPadding.push_back (0); - - mColumns.push_back (col == "" ? " " : col); - return mColumns.size () - 1; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setColumnUnderline (int column) -{ - char id[12]; - sprintf (id, "col:%d", column); - mUnderline[id] = Color (Color::nocolor, Color::nocolor, true, false, false); -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setColumnPadding (int column, int padding) -{ - mColumnPadding[column] = padding; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setColumnWidth (int column, int width) -{ - assert (width > 0); - mSpecifiedWidth[column] = width; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setColumnWidth (int column, sizing s) -{ - mSpecifiedWidth[column] = (int) s; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setColumnCommify (int column) -{ - mCommify[column] = true; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setColumnJustification (int column, just j) -{ - mJustification[column] = j; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::sortOn (int column, order o) -{ - mSortColumns.push_back (column); - mSortOrder[column] = o; -} - -//////////////////////////////////////////////////////////////////////////////// -int Table::addRow () -{ - return mRows++; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setRowColor (const int row, const Color& c) -{ - char id[12]; - sprintf (id, "row:%d", row); - mColor[id].blend (c); -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::addCell (const int row, const int col, const std::string& data) -{ - int length = 0; - - if (mCommify.find (col) != mCommify.end ()) - mData.add (row, col, commify (data)); - else - mData.add (row, col, data); - - // For multi-line cells, find the longest line. - if (data.find ("\n") != std::string::npos) - { - length = 0; - std::vector lines; - split (lines, data, "\n"); - for (unsigned int i = 0; i < lines.size (); ++i) - if (utf8_length (lines[i]) > length) - length = utf8_length (lines[i]); - } - else - length = utf8_length (data); - - // Automatically maintain max width. - mMaxDataWidth[col] = max (mMaxDataWidth[col], length); -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::addCell (const int row, const int col, const char data) -{ - mData.add (row, col, data); - - // Automatically maintain max width. - mMaxDataWidth[col] = max (mMaxDataWidth[col], 1); -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::addCell (const int row, const int col, const int data) -{ - char value[12]; - sprintf (value, "%d", data); - - if (mCommify.find (col) != mCommify.end ()) - mData.add (row, col, commify (value)); - else - mData.add (row, col, value); - - // Automatically maintain max width. - mMaxDataWidth[col] = max (mMaxDataWidth[col], (signed) strlen (value)); -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::addCell (const int row, const int col, const float data) -{ - char value[24]; - sprintf (value, "%.2f", data); - - if (mCommify.find (col) != mCommify.end ()) - mData.add (row, col, commify (value)); - else - mData.add (row, col, value); - - // Automatically maintain max width. - mMaxDataWidth[col] = max (mMaxDataWidth[col], (signed) strlen (value)); -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::addCell (const int row, const int col, const double data) -{ - char value[24]; - sprintf (value, "%.6f", data); - - if (mCommify.find (col) != mCommify.end ()) - mData.add (row, col, commify (value)); - else - mData.add (row, col, value); - - // Automatically maintain max width. - mMaxDataWidth[col] = max (mMaxDataWidth[col], (signed) strlen (value)); -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setCellColor (const int row, const int col, const Color& c) -{ - char id[24]; - sprintf (id, "cell:%d,%d", row, col); - mColor[id] = c; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string Table::getCell (const int row, const int col) -{ - Grid::Cell* c = mData.byRow (row, col); - if (c) - return (std::string) *c; - - return ""; -} - -//////////////////////////////////////////////////////////////////////////////// -Color Table::getColor (const int index, const int row, const int col) -{ - // Color defaults to trivial. - Color c; - - // For alternating rows, use Table::alternate. - std::map ::iterator i; - char id[24]; - - if (index % 2) - c = alternate; - - // Blend with a row color, if specified. - sprintf (id, "row:%d", row); - if ((i = mColor.find (id)) != mColor.end ()) - c.blend (i->second); - - // Blend with a cell color, if specified. - sprintf (id, "cell:%d,%d", row, col); - if ((i = mColor.find (id)) != mColor.end ()) - c.blend (i->second); - - return c; -} - -//////////////////////////////////////////////////////////////////////////////// -Color Table::getHeaderUnderline (int col) -{ - char idCol[12]; - sprintf (idCol, "col:%d", col); - - return mUnderline.find (idCol) != mUnderline.end () ? mUnderline[idCol] - : Color (); -} - -//////////////////////////////////////////////////////////////////////////////// -int Table::getIntraPadding () -{ - return mIntraPadding; -} - -//////////////////////////////////////////////////////////////////////////////// -int Table::getPadding (int col) -{ - return max (mColumnPadding[col], mTablePadding); -} - -//////////////////////////////////////////////////////////////////////////////// -// Using mSpecifiedWidth, mMaxDataWidth, generate mCalculatedWidth. -void Table::calculateColumnWidths () -{ - // Ideal case: either no table width is specified, or everything fits without - // wrapping into mTableWidth. - std::vector ideal = mMaxDataWidth; - int width = 0; - int countFlexible = 0; - for (size_t c = 0; c < mColumns.size (); ++c) - { - if (mSpecifiedWidth[c] == flexible) - ++countFlexible; - - else if (mSpecifiedWidth[c] > 0) - ideal[c] = mSpecifiedWidth[c]; - - width += mColumnPadding[c] + - ideal[c] + - mColumnPadding[c] + - (c > 0 ? mIntraPadding : 0); - } - - if (!mTableWidth || width < mTableWidth) - { - mCalculatedWidth = ideal; - return; - } - - // Try again, with available space divided among the flexible columns. - if (countFlexible) - { - ideal = mMaxDataWidth; - width = 0; - for (size_t c = 0; c < mColumns.size (); ++c) - { - if (mSpecifiedWidth[c] > 0) - ideal[c] = mSpecifiedWidth[c]; - else if (mSpecifiedWidth[c] == flexible) - { - ideal[c] = 0; - } - - width += mColumnPadding[c] + - ideal[c] + - mColumnPadding[c] + - (c > 0 ? mIntraPadding : 0); - } - - int available = mTableWidth - width; - if (width < mTableWidth) // if there is room to wiggle in - { - int shared = available / countFlexible; - int remainder = available % countFlexible; - - int lastFlexible = mColumns.size () - 1; - for (size_t c = 0; c < mColumns.size (); ++c) - { - if (mSpecifiedWidth[c] == flexible) - { - lastFlexible = c; - ideal[c] += shared; - } - } - - // Remainder goes to last column. - ideal[lastFlexible] += remainder; - mCalculatedWidth = ideal; - return; - } - else - { - // The fallback position is to assume no width was specified, and just - // calculate widths accordingly. - mTableWidth = 0; - calculateColumnWidths (); - return; - } - } - - // Try again, treating minimum columns as flexible. -// std::cout << "# no flexible columns. Now what?\n"; -} - -//////////////////////////////////////////////////////////////////////////////// -Table::just Table::getJustification (const int row, const int col) -{ - if (mJustification.find (col) != mJustification.end ()) - return mJustification[col]; - - return left; -} - -//////////////////////////////////////////////////////////////////////////////// -Table::just Table::getHeaderJustification (int col) -{ - return mJustification.find (col) != mJustification.end () ? mJustification[col] - : left; -} - -//////////////////////////////////////////////////////////////////////////////// -// data One Data to be rendered -// width 8 Max data width for column/specified width -// padding 1 Extra padding around data -// intraPadding 0 Extra padding between columns only -// justification right Alignment withing padding -// -// Returns: -// " One " -// One data -// ^ ^ padding -// ^ intraPadding -// ^^^^^^^^ width -// ^ ^ fg/bg -// -const std::string Table::formatHeader ( - int col, - int width, - int padding) -{ - assert (width > 0); - - std::string data = mColumns[col]; - Color c = getHeaderUnderline (col); - int gap = width - utf8_length (data); - - std::string pad = std::string (padding, ' '); - - // TODO When the following is replaced by: - // std::string postJust = std::string (gap, ' '); - // two unit tests fail. - std::string postJust = ""; - for (int i = 0; i < gap; ++i) - postJust += " "; - - std::string intraPad = ""; - if (col < (signed) mColumns.size () - 1) - intraPad = std::string (getIntraPadding (), ' '); - - return c.colorize (pad + data + postJust + pad) + intraPad; -} - -//////////////////////////////////////////////////////////////////////////////// -// data One Data to be rendered -// width 8 Max data width for column/specified width -// padding 1 Extra padding around data -// intraPadding 0 Extra padding between columns only -// justification right Alignment withing padding -// -// Returns: -// "------- " -// ------- data -// ^ ^ padding -// ^ intraPadding -// ^^^^^^^^ width -// ^ ^ fg/bg -// -const std::string Table::formatHeaderDashedUnderline ( - int col, - int width, - int padding) -{ - assert (width > 0); - - Color c = getHeaderUnderline (col); - - std::string data = std::string (width, '-'); - std::string pad = std::string (padding, ' '); - std::string intraPad = ""; - - // Place the value within the available space - justify. - if (col < (signed) mColumns.size () - 1) - intraPad = std::string (getIntraPadding (), ' '); - - return c.colorize (pad + data + pad) + intraPad; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::formatCell ( - const int index, - const int row, - const int col, - const int width, - const int padding, - std::vector & lines, - std::string& blank) -{ - assert (width > 0); - - Color c = getColor (index, row, col); - just justification = getJustification (row, col); - std::string data = getCell (row, col); - - std::string pad = std::string (padding, ' '); - std::string intraPad = ""; - - if (col < (signed) mColumns.size () - 1) - intraPad = std::string (getIntraPadding (), ' '); - - // Break the text into chunks of width characters. - std::string preJust; - std::string postJust; - std::vector chunks; - wrapText (chunks, data, width); - for (size_t chunk = 0; chunk < chunks.size (); ++chunk) - { - // Place the data within the available space - justify. - int gap = width - utf8_length (chunks[chunk]); - - preJust = ""; - postJust = ""; - - if (justification == left) - postJust = std::string (gap, ' '); - - else if (justification == right) - preJust = std::string (gap, ' '); - - else if (justification == center) - { - preJust = std::string (gap / 2, ' '); - postJust = std::string (gap - preJust.length (), ' '); - } - - lines.push_back (c.colorize (pad + preJust + chunks[chunk] + postJust + pad + intraPad)); - } - - // The blank is used to vertically pad cells that have blank lines. - pad = std::string (width, ' '); - - blank = c.colorize (pad + intraPad); -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setDateFormat (const std::string& dateFormat) -{ - mDateFormat = dateFormat; -} - -//////////////////////////////////////////////////////////////////////////////// -void Table::setReportName (const std::string& reportName) -{ - mReportName = reportName; -} - -//////////////////////////////////////////////////////////////////////////////// -int Table::rowCount () -{ - return mRows; -} - -//////////////////////////////////////////////////////////////////////////////// -int Table::columnCount () -{ - return mColumns.size (); -} - -//////////////////////////////////////////////////////////////////////////////// -// Essentially a static implementation of a dynamic operator<. -bool sort_compare (int left, int right) -{ - for (size_t c = 0; c < table->mSortColumns.size (); ++c) - { - int column = table->mSortColumns[c]; - Table::order sort_type = table->mSortOrder[column]; - - Grid::Cell* cell_left = table->mData.byRow (left, column); - Grid::Cell* cell_right = table->mData.byRow (right, column); - - // Equally NULL - next column. - if (cell_left == NULL && cell_right == NULL) - continue; - - // Equal - next column - if (cell_left && cell_right && *cell_left == *cell_right) - continue; - - // Note: Table::ascendingDueDate is not represented here because it is not - // possible to have a NULL due date, only a blank "". - - // nothing < something. - if (cell_left == NULL && cell_right != NULL) - return (sort_type == Table::ascendingNumeric || - sort_type == Table::ascendingCharacter || - sort_type == Table::ascendingPriority || - sort_type == Table::ascendingDate || - sort_type == Table::ascendingPeriod) ? true : false; - - // something > nothing. - if (cell_left != NULL && cell_right == NULL) - return (sort_type == Table::ascendingNumeric || - sort_type == Table::ascendingCharacter || - sort_type == Table::ascendingPriority || - sort_type == Table::ascendingDate || - sort_type == Table::ascendingPeriod) ? false : true; - - // Differing data - do a proper comparison. - if (cell_left && cell_right) - { - switch (sort_type) - { - case Table::ascendingNumeric: - return (float)*cell_left < (float)*cell_right ? true : false; - break; - - case Table::descendingNumeric: - return (float)*cell_left < (float)*cell_right ? false : true; - break; - - case Table::ascendingCharacter: - return (std::string)*cell_left < (std::string)*cell_right ? true : false; - break; - - case Table::descendingCharacter: - return (std::string)*cell_left < (std::string)*cell_right ? false : true; - break; - - case Table::ascendingDate: - { - // something > nothing. - if ((std::string)*cell_left != "" && (std::string)*cell_right == "") - return false; - - // nothing < something. - else if ((std::string)*cell_left == "" && (std::string)*cell_right != "") - return true; - - else - { - Date dl ((std::string)*cell_left, table->mDateFormat); - Date dr ((std::string)*cell_right, table->mDateFormat); - return dl < dr ? true : false; - } - } - break; - - case Table::descendingDate: - { - // something > nothing. - if ((std::string)*cell_left != "" && (std::string)*cell_right == "") - return true; - - // nothing < something. - else if ((std::string)*cell_left == "" && (std::string)*cell_right != "") - return false; - - else - { - Date dl ((std::string)*cell_left, table->mDateFormat); - Date dr ((std::string)*cell_right, table->mDateFormat); - return dl < dr ? false : true; - } - } - break; - - case Table::ascendingDueDate: - { - // something > nothing. - if ((std::string)*cell_left != "" && (std::string)*cell_right == "") - return true; - - // nothing < something. - else if ((std::string)*cell_left == "" && (std::string)*cell_right != "") - return false; - - else - { - std::string format = context.config.get ("report." + table->mReportName + ".dateformat"); - if (format == "") - format = context.config.get ("dateformat.report"); - if (format == "") - format = context.config.get ("dateformat"); - - Date dl ((std::string)*cell_left, format); - Date dr ((std::string)*cell_right, format); - return dl < dr ? true : false; - } - } - break; - - case Table::descendingDueDate: - { - // something > nothing. - if ((std::string)*cell_left != "" && (std::string)*cell_right == "") - return true; - - // nothing < something. - else if ((std::string)*cell_left == "" && (std::string)*cell_right != "") - return false; - - else - { - std::string format = context.config.get ("report." + table->mReportName + ".dateformat"); - if (format == "") - format = context.config.get ("dateformat.report"); - if (format == "") - format = context.config.get ("dateformat"); - - Date dl ((std::string)*cell_left, format); - Date dr ((std::string)*cell_right, format); - return dl < dr ? false : true; - } - } - break; - - case Table::ascendingPriority: - if (((std::string)*cell_left == "" && (std::string)*cell_right != "") || - ((std::string)*cell_left == "L" && ((std::string)*cell_right == "M" || (std::string)*cell_right == "H")) || - ((std::string)*cell_left == "M" && (std::string)*cell_right == "H")) - return true; - else - return false; - break; - - case Table::descendingPriority: - if (((std::string)*cell_left != "" && (std::string)*cell_right == "") || - ((std::string)*cell_left == "M" && (std::string)*cell_right == "L") || - ((std::string)*cell_left == "H" && ((std::string)*cell_right == "L" || (std::string)*cell_right == "M"))) - return true; - else - return false; - break; - - case Table::ascendingPeriod: - if ((std::string)*cell_left == "" && (std::string)*cell_right != "") - return true; - else if ((std::string)*cell_left != "" && (std::string)*cell_right == "") - return false; - else - return Duration ((std::string)*cell_left) < Duration ((std::string)*cell_right) ? true : false; - break; - - case Table::descendingPeriod: - if ((std::string)*cell_left != "" && (std::string)*cell_right == "") - return false; - else if ((std::string)*cell_left == "" && (std::string)*cell_right != "") - return true; - else - return Duration ((std::string)*cell_left) < Duration ((std::string)*cell_right) ? false : true; - break; - } - } - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -const std::string Table::render (int maxrows /* = 0 */, int maxlines /* = 0 */) -{ - Timer t ("Table::render"); - - // May not exceed maxlines, if non-zero. - int renderedlines = 0; - - calculateColumnWidths (); - - // Print column headers in column order. - std::string output; - std::string underline; - for (size_t col = 0; col < mColumns.size (); ++col) - { - output += formatHeader ( - col, - mCalculatedWidth[col], - mColumnPadding[col]); - - if (mDashedUnderline) - underline += formatHeaderDashedUnderline ( - col, - mCalculatedWidth[col], - mColumnPadding[col]); - } - - output.erase (output.find_last_not_of (" ") + 1); - output += "\n"; - ++renderedlines; - if (underline.length ()) - { - output += underline + "\n"; - ++renderedlines; - } - - // Determine row order, according to sort options. - std::vector order; - { - Timer t ("Table::render/sort"); - for (int row = 0; row < mRows; ++row) - order.push_back (row); - - // Only sort if necessary. - if (mSortColumns.size ()) - { - table = this; // Substitute for 'this' in the static 'sort_compare'. - std::stable_sort (order.begin (), order.end (), sort_compare); - } - } - - // If a non-zero maxrows is specified, then it limits the number of rows of - // the table that are rendered. - int limitrows = mRows; - if (maxrows != 0) - limitrows = min (maxrows, mRows); - - // If a non-zero maxlines is specified, then it limits the number of lines - // of output from the table that are rendered. - - // Print all rows. - Timer t2 ("Table::render/compose"); - for (int row = 0; row < limitrows; ++row) - { - std::vector > columns; - std::vector blanks; - - size_t maxHeight = 0; - for (size_t col = 0; col < mColumns.size (); ++col) - { - std::vector lines; - std::string blank; - formatCell ( - row, - order[row], - col, - mCalculatedWidth[col], - mColumnPadding[col], - lines, - blank); - - columns.push_back (lines); - blanks.push_back (blank); - - maxHeight = max (maxHeight, columns[col].size ()); - } - - if (maxHeight) - { - for (size_t lines = 0; lines < maxHeight; ++lines) - { - for (size_t col = 0; col < mColumns.size (); ++col) - if (lines < columns[col].size ()) - output += columns[col][lines]; - else - output += blanks[col]; - - // Trim right. - output.erase (output.find_last_not_of (" ") + 1); - output += "\n"; - - ++renderedlines; - - if (maxlines != 0 && renderedlines >= maxlines) - break; - } - } - else - { - // Trim right. - output.erase (output.find_last_not_of (" ") + 1); - output += "\n"; - } - - if (maxlines != 0 && renderedlines >= maxlines) - break; - } - - return output; -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Table.h b/src/Table.h deleted file mode 100644 index 35ad63dad..000000000 --- a/src/Table.h +++ /dev/null @@ -1,141 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// taskwarrior - a command line task list manager. -// -// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez. -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free Software -// Foundation; either version 2 of the License, or (at your option) any later -// version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License along with -// this program; if not, write to the -// -// Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, -// Boston, MA -// 02110-1301 -// USA -// -//////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDED_TABLE -#define INCLUDED_TABLE - -#include -#include -#include -#include "Color.h" -#include "Grid.h" - -class Table -{ - friend bool sort_compare (int, int); - -public: - enum just {left, center, right}; - enum order {ascendingNumeric, - ascendingCharacter, - ascendingPriority, - ascendingDate, - ascendingDueDate, - ascendingPeriod, - descendingNumeric, - descendingCharacter, - descendingPriority, - descendingDate, - descendingDueDate, - descendingPeriod}; - enum sizing {minimum = -1, flexible = 0}; - - Table (); - virtual ~Table (); - - Table (const Table&); - Table& operator= (const Table&); - - void setTableAlternateColor (const Color&); - void setTablePadding (int); - void setTableIntraPadding (int); - void setTableWidth (int); - void setTableDashedUnderline (); - - int addColumn (const std::string&); - void setColumnUnderline (int); - void setColumnPadding (int, int); - void setColumnWidth (int, int); - void setColumnWidth (int, sizing); - void setColumnJustification (int, just); - void setColumnCommify (int); - void sortOn (int, order); - - int addRow (); - void setRowColor (int, const Color&); - - void addCell (int, int, const std::string&); - void addCell (int, int, char); - void addCell (int, int, int); - void addCell (int, int, float); - void addCell (int, int, double); - void setCellColor (int, int, const Color&); - - void setDateFormat (const std::string&); - void setReportName (const std::string&); - - int rowCount (); - int columnCount (); - const std::string render (int maxrows = 0, int maxlines = 0); - -private: - std::string getCell (const int, const int); - Color getColor (const int, const int, const int); - Color getHeaderUnderline (const int); - int getPadding (const int); - int getIntraPadding (); - void calculateColumnWidths (); - just getJustification (const int, const int); - just getHeaderJustification (const int); - const std::string formatHeader (const int, const int, const int); - const std::string formatHeaderDashedUnderline (const int, const int, const int); - void formatCell (const int, const int, const int, const int, const int, std::vector &, std::string&); - -private: - std::vector mColumns; - int mRows; - int mIntraPadding; - std::map mColor; - std::map mUnderline; - bool mDashedUnderline; - Color alternate; - - // Padding... - int mTablePadding; - std::vector mColumnPadding; - - // Width... - int mTableWidth; - std::vector mSpecifiedWidth; - std::vector mMaxDataWidth; - std::vector mCalculatedWidth; - - std::map mJustification; - std::map mCommify; - Grid mData; - - // Sorting... - std::vector mSortColumns; - std::map mSortOrder; - - // Misc... - std::string mDateFormat; - std::string mReportName; -}; - -#endif - -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/ViewTask.cpp b/src/ViewTask.cpp index 9901a0db5..6d1e060eb 100644 --- a/src/ViewTask.cpp +++ b/src/ViewTask.cpp @@ -111,13 +111,18 @@ std::string ViewTask::render (std::vector & data, std::vector & seque int global_min = utf8_length ((*i)->getLabel ()); int global_ideal = global_min; - std::vector ::iterator d; - for (d = data.begin (); d != data.end (); ++d) + for (int s = 0; s < sequence.size (); ++s) { + if (s >= _truncate_lines && _truncate_lines != 0) + break; + + if (s >= _truncate_rows && _truncate_rows != 0) + break; + // Determine minimum and ideal width for this column. int min; int ideal; - (*i)->measure (*d, min, ideal); + (*i)->measure (data[sequence[s]], min, ideal); if (min > global_min) global_min = min; if (ideal > global_ideal) global_ideal = ideal; @@ -162,14 +167,17 @@ std::string ViewTask::render (std::vector & data, std::vector & seque overage -= sum_minimal; // Spread 'overage' among columns where width[i] < ideal[i] - while (overage) + bool needed = true; + while (overage && needed) { + needed = false; for (int i = 0; i < _columns.size () && overage; ++i) { if (widths[i] < ideal[i]) { ++widths[i]; --overage; + needed = true; } } } diff --git a/src/ViewText.cpp b/src/ViewText.cpp index ebcd2df85..05e09963e 100644 --- a/src/ViewText.cpp +++ b/src/ViewText.cpp @@ -222,6 +222,10 @@ std::string ViewText::render () bool odd = (row % 2) ? true : false; Color row_color = odd ? _odd : _even; + // TODO row_color.blend (provided color); + // TODO Problem: colors for columns are specified, not rows, + // therefore there are only cell colors, not intra colors. + Color cell_color; for (int col = 0; col < _columns.size (); ++col) { diff --git a/src/command.cpp b/src/command.cpp index f04ea09bd..78a55d1c9 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -43,6 +43,7 @@ #include "util.h" #include "main.h" #include "Transport.h" +#include "ViewText.h" #include "../cmake.h" #ifdef HAVE_COMMIT #include "../commit.h" @@ -259,41 +260,24 @@ int handleProjects (std::string& outs) if (unique.size ()) { // Render a list of project names from the map. - Table table; - table.addColumn ("Project"); - table.addColumn ("Tasks"); - table.addColumn ("Pri:None"); - table.addColumn ("Pri:L"); - table.addColumn ("Pri:M"); - table.addColumn ("Pri:H"); - - if (context.color () && context.config.getBoolean ("fontunderline")) - { - table.setColumnUnderline (0); - table.setColumnUnderline (1); - table.setColumnUnderline (2); - table.setColumnUnderline (3); - table.setColumnUnderline (4); - table.setColumnUnderline (5); - } - else - table.setTableDashedUnderline (); - - table.setColumnJustification (1, Table::right); - table.setColumnJustification (2, Table::right); - table.setColumnJustification (3, Table::right); - table.setColumnJustification (4, Table::right); - table.setColumnJustification (5, Table::right); + ViewText view; + view.width (context.getWidth ()); + view.add (Column::factory ("string", "Project")); + view.add (Column::factory ("string.right", "Tasks")); + view.add (Column::factory ("string.right", "Pri:None")); + view.add (Column::factory ("string.right", "Pri:L")); + view.add (Column::factory ("string.right", "Pri:M")); + view.add (Column::factory ("string.right", "Pri:H")); foreach (i, unique) { - int row = table.addRow (); - table.addCell (row, 0, (i->first == "" ? "(none)" : i->first)); - table.addCell (row, 1, i->second); - table.addCell (row, 2, none[i->first]); - table.addCell (row, 3, low[i->first]); - table.addCell (row, 4, medium[i->first]); - table.addCell (row, 5, high[i->first]); + int row = view.addRow (); + view.set (row, 0, (i->first == "" ? "(none)" : i->first)); + view.set (row, 1, i->second); + view.set (row, 2, none[i->first]); + view.set (row, 3, low[i->first]); + view.set (row, 4, medium[i->first]); + view.set (row, 5, high[i->first]); } int number_projects = unique.size (); @@ -301,7 +285,7 @@ int handleProjects (std::string& outs) --number_projects; out << optionalBlankLine () - << table.render () + << view.render () << optionalBlankLine () << number_projects << (number_projects == 1 ? " project" : " projects") @@ -382,35 +366,28 @@ int handleTags (std::string& outs) if (unique.size ()) { // Render a list of tags names from the map. - Table table; - table.addColumn ("Tag"); - table.addColumn ("Count"); - - if (context.color ()) - { - table.setColumnUnderline (0); - table.setColumnUnderline (1); - } - - table.setColumnJustification (1, Table::right); + ViewText view; + view.width (context.getWidth ()); + view.add (Column::factory ("string", "Tag")); + view.add (Column::factory ("string.right", "Count")); Color bold ("bold"); + bool special = false; foreach (i, unique) { - int row = table.addRow (); - table.addCell (row, 0, i->first); - table.addCell (row, 1, i->second); - // Highlight the special tags. - if (context.color () && (i->first == "nocolor" || - i->first == "nonag")) - { - table.setRowColor (row, bold); - } + special = (context.color () && + (i->first == "nocolor" || + i->first == "nonag" || + i->first == "next")) ? true : false; + + int row = view.addRow (); + view.set (row, 0, i->first, special ? bold : Color ()); + view.set (row, 1, i->second, special ? bold : Color ()); } out << optionalBlankLine () - << table.render () + << view.render () << optionalBlankLine () << unique.size () << (unique.size () == 1 ? " tag" : " tags") @@ -1002,22 +979,18 @@ int handleVersion (std::string& outs) // Create a table for the disclaimer. int width = context.getWidth (); - Table disclaimer; - disclaimer.setTableWidth (width); - disclaimer.addColumn (" "); - disclaimer.setColumnWidth (0, Table::flexible); - disclaimer.setColumnJustification (0, Table::left); - disclaimer.addCell (disclaimer.addRow (), 0, + ViewText disclaimer; + disclaimer.width (width); + disclaimer.add (Column::factory ("string", "")); + disclaimer.set (disclaimer.addRow (), 0, "Taskwarrior may be copied only under the terms of the GNU General Public " "License, which may be found in the taskwarrior source kit."); // Create a table for the URL. - Table link; - link.setTableWidth (width); - link.addColumn (" "); - link.setColumnWidth (0, Table::flexible); - link.setColumnJustification (0, Table::left); - link.addCell (link.addRow (), 0, + ViewText link; + link.width (width); + link.add (Column::factory ("string", "")); + link.set (link.addRow (), 0, "Documentation for taskwarrior can be found using 'man task', 'man taskrc', " "'man task-tutorial', 'man task-color', 'man task-sync', 'man task-faq' or at " "http://taskwarrior.org"); @@ -1061,7 +1034,9 @@ int handleVersion (std::string& outs) #ifdef HAVE_LIBLUA << "Portions of this software Copyright (C) 1994 – 2008 Lua.org, PUC-Rio.\n" #endif + << "\n" << disclaimer.render () + << "\n" << link.render () << "\n"; @@ -1168,26 +1143,11 @@ int handleShow (std::string& outs) if (context.config.get (*i) != default_config.get (*i)) default_values.push_back (*i); - // Create a table for output. - Table table; - table.setTableWidth (width); - table.setDateFormat (context.config.get ("dateformat")); - table.addColumn ("Config variable"); - table.addColumn ("Value"); - - if (context.color ()) - { - table.setColumnUnderline (0); - table.setColumnUnderline (1); - } - else - table.setTableDashedUnderline (); - - table.setColumnWidth (0, Table::minimum); - table.setColumnWidth (1, Table::flexible); - table.setColumnJustification (0, Table::left); - table.setColumnJustification (1, Table::left); - table.sortOn (0, Table::ascendingCharacter); + // Create output view. + ViewText view; + view.width (width); + view.add (Column::factory ("string", "Config variable")); + view.add (Column::factory ("string", "Value")); Color error ("bold white on red"); Color warning ("black on yellow"); @@ -1206,25 +1166,22 @@ int handleShow (std::string& outs) if (loc != std::string::npos) { - int row = table.addRow (); - table.addCell (row, 0, *i); - table.addCell (row, 1, context.config.get (*i)); - // Look for unrecognized. - if (context.color ()) - { - if (std::find (unrecognized.begin (), unrecognized.end (), *i) != unrecognized.end ()) - table.setRowColor (row, error); + Color color; + if (std::find (unrecognized.begin (), unrecognized.end (), *i) != unrecognized.end ()) + color = error; + else if (std::find (default_values.begin (), default_values.end (), *i) != default_values.end ()) + color = warning; - else if (std::find (default_values.begin (), default_values.end (), *i) != default_values.end ()) - table.setRowColor (row, warning); - } + int row = view.addRow (); + view.set (row, 0, *i, color); + view.set (row, 1, context.config.get (*i), color); } } out << "\n" - << table.render () - << (table.rowCount () == 0 ? "No matching configuration variables.\n\n" : "\n"); + << view.render () + << (view.rows () == 0 ? "No matching configuration variables.\n\n" : "\n"); // Display the unrecognized variables. if (unrecognized.size ()) @@ -2374,17 +2331,10 @@ int handleColor (std::string& outs) std::vector all; context.config.all (all); - Table table; - table.addColumn ("Color"); - table.addColumn ("Definition"); - - if (context.color () && context.config.getBoolean ("fontunderline")) - { - table.setColumnUnderline (0); - table.setColumnUnderline (1); - } - else - table.setTableDashedUnderline (); + ViewText view; + view.width (context.getWidth ()); + view.add (Column::factory ("string", "Color")); + view.add (Column::factory ("string", "Definition")); foreach (item, all) { @@ -2394,16 +2344,14 @@ int handleColor (std::string& outs) *item != "color" && item->find ("color") == 0) { - int row = table.addRow (); - table.addCell (row, 0, *item); - table.addCell (row, 1, context.config.get (*item)); - table.setRowColor (row, context.config.get (*item)); + Color color (context.config.get (*item)); + int row = view.addRow (); + view.set (row, 0, *item, color); + view.set (row, 1, context.config.get (*item), color); } } - out << optionalBlankLine () - << table.render () - << optionalBlankLine () + out << view.render () << "\n"; } diff --git a/src/main.h b/src/main.h index 4c4cdf876..32542a8dc 100644 --- a/src/main.h +++ b/src/main.h @@ -36,7 +36,6 @@ #include #include #include "Context.h" -#include "Table.h" #include "Date.h" #include "Color.h" #include "../cmake.h" diff --git a/src/report.cpp b/src/report.cpp index 5cd65ca0b..afa598a1c 100644 --- a/src/report.cpp +++ b/src/report.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -787,6 +786,7 @@ int handleReportSummary (std::string& outs) // Create a table for output. ViewText view; + view.width (context.getWidth ()); view.add (Column::factory ("string", "Project")); view.add (Column::factory ("string", "Remaining")); view.add (Column::factory ("string", "Avg age")); @@ -900,31 +900,12 @@ int handleReportTimesheet (std::string& outs) << "\n"; // Render the completed table. - Table completed; - completed.setTableWidth (width); - completed.addColumn (" "); - completed.addColumn ("Project"); - completed.addColumn ("Due"); - completed.addColumn ("Description"); - - if (context.color () && context.config.getBoolean ("fontunderline")) - { - completed.setColumnUnderline (1); - completed.setColumnUnderline (2); - completed.setColumnUnderline (3); - } - else - completed.setTableDashedUnderline (); - - completed.setColumnWidth (0, Table::minimum); - completed.setColumnWidth (1, Table::minimum); - completed.setColumnWidth (2, Table::minimum); - completed.setColumnWidth (3, Table::flexible); - - completed.setColumnJustification (0, Table::left); - completed.setColumnJustification (1, Table::left); - completed.setColumnJustification (2, Table::right); - completed.setColumnJustification (3, Table::left); + ViewText completed; + completed.width (width); + completed.add (Column::factory ("string", " ")); + completed.add (Column::factory ("string", "Project")); + completed.add (Column::factory ("string.right", "Due")); + completed.add (Column::factory ("string", "Description")); std::vector ::iterator task; for (task = tasks.begin (); task != tasks.end (); ++task) @@ -935,56 +916,35 @@ int handleReportTimesheet (std::string& outs) Date compDate (atoi (task->get ("end").c_str ())); if (compDate >= start && compDate < end) { + Color c (task->get ("fg") + " " + task->get ("bg")); + if (context.color ()) + autoColorize (*task, c); + int row = completed.addRow (); std::string format = context.config.get ("dateformat.report"); if (format == "") format = context.config.get ("dateformat"); - completed.addCell (row, 1, task->get ("project")); - completed.addCell (row, 2, getDueDate (*task, format)); - completed.addCell (row, 3, getFullDescription (*task, "timesheet")); - - if (context.color ()) - { - Color c (task->get ("fg") + " " + task->get ("bg")); - autoColorize (*task, c); - completed.setRowColor (row, c); - } + completed.set (row, 1, task->get ("project"), c); + completed.set (row, 2, getDueDate (*task, format), c); + completed.set (row, 3, getFullDescription (*task, "timesheet"), c); } } } - out << " Completed (" << completed.rowCount () << " tasks)\n"; + out << " Completed (" << completed.rows () << " tasks)\n"; - if (completed.rowCount ()) + if (completed.rows ()) out << completed.render () << "\n"; // Now render the started table. - Table started; - started.setTableWidth (width); - started.addColumn (" "); - started.addColumn ("Project"); - started.addColumn ("Due"); - started.addColumn ("Description"); + ViewText started; + started.width (width); + started.add (Column::factory ("string", " ")); + started.add (Column::factory ("string", "Project")); + started.add (Column::factory ("string.right", "Due")); + started.add (Column::factory ("string", "Description")); - if (context.color () && context.config.getBoolean ("fontunderline")) - { - started.setColumnUnderline (1); - started.setColumnUnderline (2); - started.setColumnUnderline (3); - } - else - started.setTableDashedUnderline (); - - started.setColumnWidth (0, Table::minimum); - started.setColumnWidth (1, Table::minimum); - started.setColumnWidth (2, Table::minimum); - started.setColumnWidth (3, Table::flexible); - - started.setColumnJustification (0, Table::left); - started.setColumnJustification (1, Table::left); - started.setColumnJustification (2, Table::right); - started.setColumnJustification (3, Table::left); for (task = tasks.begin (); task != tasks.end (); ++task) { // If task started within range, but not completed withing range. @@ -994,27 +954,25 @@ int handleReportTimesheet (std::string& outs) Date startDate (atoi (task->get ("start").c_str ())); if (startDate >= start && startDate < end) { + Color c (task->get ("fg") + " " + task->get ("bg")); + if (context.color ()) + autoColorize (*task, c); + int row = started.addRow (); std::string format = context.config.get ("dateformat.report"); if (format == "") format = context.config.get ("dateformat"); - started.addCell (row, 1, task->get ("project")); - started.addCell (row, 2, getDueDate (*task, format)); - started.addCell (row, 3, getFullDescription (*task, "timesheet")); + started.set (row, 1, task->get ("project"), c); + started.set (row, 2, getDueDate (*task, format), c); + started.set (row, 3, getFullDescription (*task, "timesheet"), c); - if (context.color ()) - { - Color c (task->get ("fg") + " " + task->get ("bg")); - autoColorize (*task, c); - started.setRowColor (row, c); - } } } } - out << " Started (" << started.rowCount () << " tasks)\n"; + out << " Started (" << started.rows () << " tasks)\n"; - if (started.rowCount ()) + if (started.rows ()) out << started.render () << "\n\n"; @@ -1035,9 +993,6 @@ std::string renderMonths ( std::vector & all, int monthsPerLine) { - Table table; - table.setDateFormat (context.config.get ("dateformat")); - // What day of the week does the user consider the first? int weekStart = Date::dayOfWeek (context.config.get ("weekstart")); if (weekStart != 0 && weekStart != 1) @@ -1045,64 +1000,41 @@ std::string renderMonths ( "only contain 'Sunday' or 'Monday'."); // Build table for the number of months to be displayed. + ViewText view; + view.width (context.getWidth ()); for (int i = 0 ; i < (monthsPerLine * 8); i += 8) { if (weekStart == 1) { - table.addColumn (" "); - table.addColumn ("Mo"); - table.addColumn ("Tu"); - table.addColumn ("We"); - table.addColumn ("Th"); - table.addColumn ("Fr"); - table.addColumn ("Sa"); - table.addColumn ("Su"); + view.add (Column::factory ("string", " ")); + view.add (Column::factory ("string", "Mo")); + view.add (Column::factory ("string", "Tu")); + view.add (Column::factory ("string", "We")); + view.add (Column::factory ("string", "Th")); + view.add (Column::factory ("string", "Fr")); + view.add (Column::factory ("string", "Sa")); + view.add (Column::factory ("string", "Su")); } else { - table.addColumn (" "); - table.addColumn ("Su"); - table.addColumn ("Mo"); - table.addColumn ("Tu"); - table.addColumn ("We"); - table.addColumn ("Th"); - table.addColumn ("Fr"); - table.addColumn ("Sa"); + view.add (Column::factory ("string", " ")); + view.add (Column::factory ("string", "Su")); + view.add (Column::factory ("string", "Mo")); + view.add (Column::factory ("string", "Tu")); + view.add (Column::factory ("string", "We")); + view.add (Column::factory ("string", "Th")); + view.add (Column::factory ("string", "Fr")); + view.add (Column::factory ("string", "Sa")); } - - if (context.color () && context.config.getBoolean ("fontunderline")) - { - table.setColumnUnderline (i + 1); - table.setColumnUnderline (i + 2); - table.setColumnUnderline (i + 3); - table.setColumnUnderline (i + 4); - table.setColumnUnderline (i + 5); - table.setColumnUnderline (i + 6); - table.setColumnUnderline (i + 7); - } - else - table.setTableDashedUnderline (); - - table.setColumnJustification (i + 0, Table::right); - table.setColumnJustification (i + 1, Table::right); - table.setColumnJustification (i + 2, Table::right); - table.setColumnJustification (i + 3, Table::right); - table.setColumnJustification (i + 4, Table::right); - table.setColumnJustification (i + 5, Table::right); - table.setColumnJustification (i + 6, Table::right); - table.setColumnJustification (i + 7, Table::right); - - // This creates a nice gap between the months. - table.setColumnWidth (i + 0, 4); } // At most, we need 6 rows. - table.addRow (); - table.addRow (); - table.addRow (); - table.addRow (); - table.addRow (); - table.addRow (); + view.addRow (); + view.addRow (); + view.addRow (); + view.addRow (); + view.addRow (); + view.addRow (); // Set number of days per month, months to render, and years to render. std::vector years; @@ -1150,11 +1082,7 @@ std::string renderMonths ( int woy = temp.weekOfYear (weekStart); if (context.config.getBoolean ("displayweeknumber")) - { - table.addCell (row, (8 * mpl), woy); - if (context.color ()) - table.setCellColor (row, (8 * mpl), color_weeknumber); - } + view.set (row, (8 * mpl), woy, color_weeknumber); // Calculate column id. int thisCol = dow + // 0 = Sunday @@ -1164,7 +1092,7 @@ std::string renderMonths ( if (thisCol == (8 * mpl)) thisCol += 7; - table.addCell (row, thisCol, d); + view.set (row, thisCol, d); if (context.color ()) { @@ -1237,7 +1165,8 @@ std::string renderMonths ( } } } - table.setCellColor (row, thisCol, cellColor); +// TODO Solve this. +// table.setCellColor (row, thisCol, cellColor); } // Check for end of week, and... @@ -1249,7 +1178,7 @@ std::string renderMonths ( } } - return table.render (); + return view.render (); } //////////////////////////////////////////////////////////////////////////////// @@ -1567,32 +1496,18 @@ int handleReportCalendar (std::string& outs) std::vector holidays; context.config.all (holidays); - Table holTable; - holTable.setTableWidth (context.getWidth ()); - holTable.addColumn ("Date"); - holTable.addColumn ("Holiday"); - holTable.sortOn (0, Table::ascendingDueDate); + ViewText holTable; + holTable.width (context.getWidth ()); + holTable.add (Column::factory ("string", "Date")); + holTable.add (Column::factory ("string", "Holiday")); - if (context.color () && context.config.getBoolean ("fontunderline")) - { - holTable.setColumnUnderline (0); - holTable.setColumnUnderline (1); - } - else - holTable.setTableDashedUnderline (); - - holTable.setColumnWidth (0, Table::minimum); - holTable.setColumnWidth (1, Table::flexible); - - holTable.setColumnJustification (0, Table::left); - holTable.setColumnJustification (1, Table::left); - - foreach (hol, holidays) - if (hol->substr (0, 8) == "holiday.") - if (hol->substr (hol->size () - 4) == "name") + std::vector ::iterator it; + for (it = holidays.begin (); it != holidays.end (); ++it) + if (it->substr (0, 8) == "holiday.") + if (it->substr (it->size () - 4) == "name") { - std::string holName = context.config.get ("holiday." + hol->substr (8, hol->size () - 13) + ".name"); - std::string holDate = context.config.get ("holiday." + hol->substr (8, hol->size () - 13) + ".date"); + std::string holName = context.config.get ("holiday." + it->substr (8, it->size () - 13) + ".name"); + std::string holDate = context.config.get ("holiday." + it->substr (8, it->size () - 13) + ".date"); Date hDate (holDate.c_str (), context.config.get ("dateformat.holiday")); if (date_after < hDate && hDate < date_before) @@ -1606,8 +1521,8 @@ int handleReportCalendar (std::string& outs) format = context.config.get ("dateformat"); int row = holTable.addRow (); - holTable.addCell (row, 0, hDate.toString (format)); - holTable.addCell (row, 1, holName); + holTable.set (row, 0, hDate.toString (format)); + holTable.set (row, 1, holName); } } diff --git a/test/.gitignore b/test/.gitignore index 53ec7db64..49b882d3e 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -12,7 +12,6 @@ dom.t duration.t file.t filt.t -grid.t json.t lisp.t list.t diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 26daa6061..f8ab8bfdc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,8 +6,8 @@ include_directories (${CMAKE_SOURCE_DIR}/src ${TASK_INCLUDE_DIRS}) set (test_SRCS att.t autocomplete.t cmd.t color.t config.t date.t directory.t - dom.t duration.t file.t filt.t grid.t json.t list.t nibbler.t - path.t record.t rectangle.t rx.t seq.t subst.t t.benchmark.t t.t + dom.t duration.t file.t filt.t json.t list.t nibbler.t path.t + record.t rectangle.t rx.t seq.t subst.t t.benchmark.t t.t taskmod.t tdb.t tdb2.t text.t tree.t tree2.t uri.t util.t variant.t view.t) diff --git a/test/grid.t.cpp b/test/grid.t.cpp deleted file mode 100644 index 3218aec30..000000000 --- a/test/grid.t.cpp +++ /dev/null @@ -1,69 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// taskwarrior - a command line task list manager. -// -// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez. -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free Software -// Foundation; either version 2 of the License, or (at your option) any later -// version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License along with -// this program; if not, write to the -// -// Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, -// Boston, MA -// 02110-1301 -// USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -Context context; - -int main (int argc, char** argv) -{ - UnitTest ut (30); - - Grid g; - ut.is ((int) g.width (), 0, "Zero width for uninitialized grid"); - ut.is ((int) g.height (), 0, "Zero height for uninitialized grid"); - - g.add (2, 2, false); - ut.is ((int) g.width (), 3, "Width of 3 columns"); - ut.is ((int) g.height (), 3, "Height of 3 rows"); - - Grid g2; - g2.add (0, 1, "value"); - g2.add (1, 0, "value"); - ut.is ((int) g2.width (), 2, "Width of 2 columns"); - ut.is ((int) g2.height (), 2, "Height of 2 rows"); - ut.is (g2.byRow (0, 0), NULL, "Gap at 0,0"); - ut.ok (g2.byRow (0, 1), "Cell at 0,0"); - ut.ok (g2.byRow (1, 0), "Cell at 0,0"); - ut.is (g2.byRow (1, 1), NULL, "Gap at 1,1"); - - Grid g3; - for (int i = 0; i < 14; ++i) - g3.add (i / 4, i % 4, "value"); - - for (int i = 0; i < 20; ++i) - if (i < 14) - ut.ok (g3.byRow (i / 4, i % 4), "g3 good cell"); - else - ut.is (g3.byRow (i / 4, i % 4), NULL, "g3 missing cell"); - - return 0; -} - -////////////////////////////////////////////////////////////////////////////////