- Integrated ViewTask and ViewText completely.
- Obsoleted Table.{h,cpp}, Grid.{h,cpp}, grid.t.cpp
- Fixed ViewTask rendering bug that caused the full width to be used every time.
This commit is contained in:
Paul Beckingham 2011-05-13 01:10:30 -04:00
parent c8c7e02bc8
commit 6fb3bc5b03
14 changed files with 208 additions and 2002 deletions

View file

@ -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

View file

@ -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 <iostream>
#include <stdlib.h>
#include <text.h>
#include <Grid.h>
////////////////////////////////////////////////////////////////////////////////
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 <Cell*>* >::iterator row;
std::vector <Cell*>::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 <Cell*>* >::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 <Cell*>);
}
// 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 <Cell*>;
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 <Cell*>);
}
// 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 <Cell*>;
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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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 <stdio.h>
#include <string>
#include <vector>
////////////////////////////////////////////////////////////////////////////////
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 <Cell*>* > mRows;
std::vector < std::vector <Cell*>* > mColumns;
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -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 <std::string> 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";
}

View file

@ -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 <iostream>
#include <string.h>
#include <assert.h>
#include <algorithm>
#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 <std::string> 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 <std::string, Color>::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 <int> 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 <std::string>& 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 <std::string> 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 <int> 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 <std::vector <std::string> > columns;
std::vector <std::string> blanks;
size_t maxHeight = 0;
for (size_t col = 0; col < mColumns.size (); ++col)
{
std::vector <std::string> 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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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 <map>
#include <vector>
#include <string>
#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>&, std::string&);
private:
std::vector <std::string> mColumns;
int mRows;
int mIntraPadding;
std::map <std::string, Color> mColor;
std::map <std::string, Color> mUnderline;
bool mDashedUnderline;
Color alternate;
// Padding...
int mTablePadding;
std::vector <int> mColumnPadding;
// Width...
int mTableWidth;
std::vector <int> mSpecifiedWidth;
std::vector <int> mMaxDataWidth;
std::vector <int> mCalculatedWidth;
std::map <int, just> mJustification;
std::map <int, bool> mCommify;
Grid mData;
// Sorting...
std::vector <int> mSortColumns;
std::map <int, order> mSortOrder;
// Misc...
std::string mDateFormat;
std::string mReportName;
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -111,13 +111,18 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
int global_min = utf8_length ((*i)->getLabel ());
int global_ideal = global_min;
std::vector <Task>::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 <Task>& data, std::vector <int>& 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;
}
}
}

View file

@ -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)
{

View file

@ -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 <std::string> 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";
}

View file

@ -36,7 +36,6 @@
#include <map>
#include <sys/types.h>
#include "Context.h"
#include "Table.h"
#include "Date.h"
#include "Color.h"
#include "../cmake.h"

View file

@ -42,7 +42,6 @@
#include <File.h>
#include <Date.h>
#include <Duration.h>
#include <Table.h>
#include <ViewText.h>
#include <text.h>
#include <util.h>
@ -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 <Task>::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 <Task>& 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<int> 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 <std::string> 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 <std::string>::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);
}
}