From 74d799acea54e569de205dd3c68017316999c818 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 26 Apr 2011 18:19:57 -0400 Subject: [PATCH] View - First pass at the interface, structure and algorithm used by the new View object that will ultimately obsolete Table, Grid and Cell. --- src/CMakeLists.txt | 2 +- src/View.cpp | 184 ++++++++++++++++++++++++++++++++ src/View.h | 78 ++++++++++++++ src/columns/Column.cpp | 44 +++----- src/columns/Column.h | 20 ++-- src/columns/ID.cpp | 30 ++++-- src/columns/ID.h | 5 +- src/sort.cpp | 235 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 549 insertions(+), 49 deletions(-) create mode 100644 src/View.cpp create mode 100644 src/View.h create mode 100644 src/sort.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 875f2a192..32b1e30f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,7 +20,7 @@ set (task_SRCS API.cpp API.h Att.cpp Att.h Cmd.cpp Cmd.h Color.cpp Color.h diag.cpp edit.cpp export.cpp history.cpp i18n.h import.cpp interactive.cpp recur.cpp report.cpp rules.cpp rx.cpp rx.h text.cpp text.h utf8.cpp utf8.h util.cpp util.h Uri.cpp Uri.h - Variant.cpp Variant.h) + Variant.cpp Variant.h View.cpp View.h) add_library (task STATIC ${task_SRCS}) add_executable (task_executable main.cpp) diff --git a/src/View.cpp b/src/View.cpp new file mode 100644 index 000000000..d9aa6c700 --- /dev/null +++ b/src/View.cpp @@ -0,0 +1,184 @@ +//////////////////////////////////////////////////////////////////////////////// +// task - 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 + +//////////////////////////////////////////////////////////////////////////////// +View::View () +: _width (0) +, _left_margin (0) +, _odd (0) +, _even (0) +, _intra_padding (0) +, _intra_odd (0) +, _intra_even (0) +, _extra_padding (0) +, _extra_odd (0) +, _extra_even (0) +, _truncate (0) +, _lines (0) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +View::~View () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +void View::add (Column* column) +{ + _columns.push_back (column); +} + +//////////////////////////////////////////////////////////////////////////////// +void View::width (int width) +{ + _width = width; +} + +//////////////////////////////////////////////////////////////////////////////// +void View::leftMargin (int margin) +{ + _left_margin = margin; +} + +//////////////////////////////////////////////////////////////////////////////// +void View::colorOdd (Color& c) +{ + _odd = c; +} + +//////////////////////////////////////////////////////////////////////////////// +void View::colorEven (Color& c) +{ + _even = c; +} + +//////////////////////////////////////////////////////////////////////////////// +void View::intraPadding (int padding) +{ + _intra_padding = padding; +} + +//////////////////////////////////////////////////////////////////////////////// +void View::intraColorOdd (Color& c) +{ + _intra_odd = c; +} + +//////////////////////////////////////////////////////////////////////////////// +void View::intraColorEven (Color& c) +{ + _intra_even = c; +} + +//////////////////////////////////////////////////////////////////////////////// +void View::extraPadding (int padding) +{ + _extra_padding = padding; +} + +//////////////////////////////////////////////////////////////////////////////// +void View::extraColorOdd (Color& c) +{ + _extra_odd = c; +} + +//////////////////////////////////////////////////////////////////////////////// +void View::extraColorEven (Color& c) +{ + _extra_even = c; +} + +//////////////////////////////////////////////////////////////////////////////// +void View::truncate (int n) +{ + _truncate = n; +} + +//////////////////////////////////////////////////////////////////////////////// +int View::lines () +{ + return _lines; +} + +//////////////////////////////////////////////////////////////////////////////// +// +-------+ +-------+ +-------+ +// |header | |header | |header | +// +--+--+-------+--+-------+--+-------+--+ +// |ma|ex|cell |in|cell |in|cell |ex| +// +--+--+-------+--+-------+--+-------+--+ +// |ma|ex|cell |in|cell |in|cell |ex| +// +--+--+-------+--+-------+--+-------+--+ +// +std::string View::render (std::vector & data, std::vector & sequence) +{ + // Determine minimal, ideal column widths. + std::vector minimal; + std::vector ideal; + + std::vector ::iterator i; + for (i = _columns.begin (); i != _columns.end (); ++i) + { + int global_min = 0; + int global_ideal = 0; + + std::vector ::iterator d; + for (d = data.begin (); d != data.end (); ++d) + { + int min; + int ideal; + (*i)->measure (*d, min, ideal); + + if (min > global_min) global_min = min; + if (ideal > global_ideal) global_ideal = ideal; + } + + minimal.push_back (global_min); + ideal.push_back (global_ideal); + } + + // TODO Calculate final column widths. + + // TODO Compose column headers. + + // TODO Render column headers. + + // TODO Compose, render columns, in sequence. + std::stringstream output; + std::vector ::iterator s; + for (s = sequence.begin (); s != sequence.end (); ++s) + { + } + + return output.str (); +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/View.h b/src/View.h new file mode 100644 index 000000000..4f8aa6b37 --- /dev/null +++ b/src/View.h @@ -0,0 +1,78 @@ +//////////////////////////////////////////////////////////////////////////////// +// task - 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_VIEW +#define INCLUDED_VIEW + +#include +#include +#include +#include +#include + +class View +{ +public: + View (); + ~View (); + + // View specifications. + void add (Column*); + void width (int); + void leftMargin (int); + void colorOdd (Color&); + void colorEven (Color&); + void intraPadding (int); + void extraPadding (int); + void intraColorOdd (Color&); + void intraColorEven (Color&); + void extraColorOdd (Color&); + void extraColorEven (Color&); + void truncate (int); + int lines (); + + // View rendering. + std::string render (std::vector &, std::vector &); + +private: + std::vector _columns; + int _width; + int _left_margin; + Color _odd; + Color _even; + int _intra_padding; + Color _intra_odd; + Color _intra_even; + int _extra_padding; + Color _extra_odd; + Color _extra_even; + int _truncate; + int _lines; +}; + +#endif +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/columns/Column.cpp b/src/columns/Column.cpp index 8f1551011..450fb0e02 100644 --- a/src/columns/Column.cpp +++ b/src/columns/Column.cpp @@ -28,44 +28,34 @@ #include #include #include +#include extern Context context; //////////////////////////////////////////////////////////////////////////////// Column* Column::factory (const std::string& name) { -/* - if (name == "description") return new ColumnDescription (); + if (name == "id") return new ColumnID (); throw std::string ("Unrecognized column type '") + name + "'"; -*/ return NULL; } //////////////////////////////////////////////////////////////////////////////// Column::Column () -: _name ("") -/* +: _style ("default") +, _label ("") , _minimum (0) , _maximum (0) -, _wrap (false) -, _just (left) -, _sizing (minimal) -*/ { } //////////////////////////////////////////////////////////////////////////////// Column::Column (const Column& other) { - _name = other._name; -/* + _label = other._label; _minimum = other._minimum; _maximum = other._maximum; - _wrap = other._wrap; - _just = other._just; - _sizing = other._sizing; -*/ } //////////////////////////////////////////////////////////////////////////////// @@ -73,14 +63,9 @@ Column& Column::operator= (const Column& other) { if (this != &other) { - _name = other._name; -/* + _label = other._label; _minimum = other._minimum; _maximum = other._maximum; - _wrap = other._wrap; - _just = other._just; - _sizing = other._sizing; -*/ } return *this; @@ -89,12 +74,9 @@ Column& Column::operator= (const Column& other) //////////////////////////////////////////////////////////////////////////////// bool Column::operator== (const Column& other) const { - return _name == other._name /*&& + return _label == other._label && _minimum == other._minimum && - _maximum == other._maximum && - _wrap == other._wrap && - _just == other._just && - _sizing == other._sizing*/; + _maximum == other._maximum; } //////////////////////////////////////////////////////////////////////////////// @@ -103,9 +85,15 @@ Column::~Column () } //////////////////////////////////////////////////////////////////////////////// -void Column::setName (const std::string& name) +void Column::setStyle (const std::string& style) { - _name = name; + _style = style; +} + +//////////////////////////////////////////////////////////////////////////////// +void Column::setLabel (const std::string& label) +{ + _label = label; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/columns/Column.h b/src/columns/Column.h index d811d8a82..a9a65d985 100644 --- a/src/columns/Column.h +++ b/src/columns/Column.h @@ -33,11 +33,6 @@ class Column { public: -/* - enum just {right = 0, left, center}; - enum sizing {minimal = 0, fixed, proportional, maximal}; -*/ - static Column* factory (const std::string&); Column (); @@ -46,19 +41,18 @@ public: bool operator== (const Column&) const; // TODO Is this necessary? ~Column (); - virtual void setName (const std::string&); - virtual std::string render (Task*, int, int, const std::string style = "default") = 0; + virtual void setStyle (const std::string&); + virtual void setLabel (const std::string&); + virtual void measure (Task&, int&, int&) = 0; + virtual void renderHeader (std::vector &, int) = 0; + virtual void render (std::vector &, Task*, int) = 0; virtual std::string type () const = 0; protected: - std::string _name; -/* + std::string _style; + std::string _label; int _minimum; int _maximum; - bool _wrap; - just _just; - sizing _sizing; -*/ }; #endif diff --git a/src/columns/ID.cpp b/src/columns/ID.cpp index a5dbb1aea..40006ed01 100644 --- a/src/columns/ID.cpp +++ b/src/columns/ID.cpp @@ -25,6 +25,7 @@ // //////////////////////////////////////////////////////////////////////////////// +#include #include #include @@ -33,7 +34,7 @@ extern Context context; //////////////////////////////////////////////////////////////////////////////// ColumnID::ColumnID () { - setName ("id"); + setLabel ("id"); } //////////////////////////////////////////////////////////////////////////////// @@ -42,11 +43,28 @@ ColumnID::~ColumnID () } //////////////////////////////////////////////////////////////////////////////// -std::string ColumnID::render ( - Task* task, - int width, - int height, - const std::string style) +// Set the minimum and maximum widths for the value. +void ColumnID::measure (Task& task, int& minimum, int& maximum) +{ + int length; + + if (task.id < 10) length = 1; // Fast + else if (task.id < 100) length = 2; // Fast + else if (task.id < 1000) length = 3; // Fast + else if (task.id < 10000) length = 4; // Fast + else length = (int) log10 ((double) task.id); // Slow + + minimum = maximum = length; +} + +//////////////////////////////////////////////////////////////////////////////// +void ColumnID::renderHeader (std::vector & lines, int width) +{ + lines.push_back ("ID"); +} + +//////////////////////////////////////////////////////////////////////////////// +void ColumnID::render (std::vector & lines, Task* task, int width) { } diff --git a/src/columns/ID.h b/src/columns/ID.h index f055d98fd..6c112d259 100644 --- a/src/columns/ID.h +++ b/src/columns/ID.h @@ -27,6 +27,7 @@ #ifndef INCLUDED_ID #define INCLUDED_ID +#include #include #include #include @@ -37,7 +38,9 @@ public: ColumnID (); ~ColumnID (); - std::string render (Task*, int, int, const std::string style = "default"); + void measure (Task&, int&, int&); + void renderHeader (std::vector &, int); + void render (std::vector &, Task*, int); std::string type () const; private: diff --git a/src/sort.cpp b/src/sort.cpp new file mode 100644 index 000000000..77c2d116a --- /dev/null +++ b/src/sort.cpp @@ -0,0 +1,235 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 + +static std::vector * data = NULL; + +//////////////////////////////////////////////////////////////////////////////// +void view_sort ( + std::vector & data) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// Re-implementation, using direct Task access instead of data copies that +// require re-parsing. +bool sort_compare (int left, int right) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// 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; +}