From 17de9fec9f182f8599241f40e530e5f0ea7c249f Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Mon, 9 Mar 2009 22:01:08 -0400 Subject: [PATCH] New Column - recur - Added new column 'recur' for use in custom reports. - Implemented Table::ascendingPeriod, Table::descendingPeriod allowing sorting on the recur column. - Added unit tests to both use the new column and test the sorting. - Code cleanup. --- ChangeLog | 2 ++ html/custom.html | 1 + html/task.html | 2 ++ src/Table.cpp | 18 +++++++++++++ src/Table.h | 13 ++++++--- src/report.cpp | 17 ++++++++++++ src/task.h | 2 +- src/tests/recur.t | 67 +++++++++++++++++++++++++++++++++++++++++++++++ src/util.cpp | 15 +++++------ 9 files changed, 125 insertions(+), 12 deletions(-) create mode 100755 src/tests/recur.t diff --git a/ChangeLog b/ChangeLog index 7b2c3a6ff..b25b789ba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -29,6 +29,8 @@ to help ensure higher quality releases. + Fixed bug that caused performance hit during table rendering. + Fixed bug that concatenated a modified description without spaces. + + Added new column 'recur' that displays the recurrence period of any + recurring tasks. This column can be added to any custom report. ------ old releases ------------------------------ diff --git a/html/custom.html b/html/custom.html index 7a970e58e..8b202f5c1 100644 --- a/html/custom.html +++ b/html/custom.html @@ -88,6 +88,7 @@ report.mine.sort=priority-,project+
  • age
  • active
  • tags +
  • recur
  • description diff --git a/html/task.html b/html/task.html index dd258f2fc..6634516dd 100644 --- a/html/task.html +++ b/html/task.html @@ -123,6 +123,8 @@ to help ensure higher quality releases.
  • Fixed bug that caused large performance hit during table rendering.
  • Fixed bug that concatenated a modified description without spaces. +
  • Added new column 'recur' that displays the recurrence period of any + recurring tasks. This column can be added to any custom report.

    diff --git a/src/Table.cpp b/src/Table.cpp index fc0ff1296..071837cdf 100644 --- a/src/Table.cpp +++ b/src/Table.cpp @@ -941,6 +941,24 @@ void Table::sort (std::vector & order) ((std::string)*left == "M" && (std::string)*right == "H")) SWAP break; + + case ascendingPeriod: + if ((std::string)*left == "" && (std::string)*right != "") + break; + else if ((std::string)*left != "" && (std::string)*right == "") + SWAP + else if (convertDuration ((std::string)*left) > convertDuration ((std::string)*right)) + SWAP + break; + + case descendingPeriod: + if ((std::string)*left != "" && (std::string)*right == "") + break; + else if ((std::string)*left == "" && (std::string)*right != "") + SWAP + else if (convertDuration ((std::string)*left) < convertDuration ((std::string)*right)) + SWAP + break; } } } diff --git a/src/Table.h b/src/Table.h index 4048dae70..fe098e896 100644 --- a/src/Table.h +++ b/src/Table.h @@ -37,9 +37,16 @@ class Table { public: enum just {left, center, right}; - enum order {ascendingNumeric, ascendingCharacter, ascendingPriority, - ascendingDate, descendingNumeric, descendingCharacter, - descendingPriority, descendingDate}; + enum order {ascendingNumeric, + ascendingCharacter, + ascendingPriority, + ascendingDate, + ascendingPeriod, + descendingNumeric, + descendingCharacter, + descendingPriority, + descendingDate, + descendingPeriod}; enum sizing {minimum = -1, flexible = 0}; Table (); diff --git a/src/report.cpp b/src/report.cpp index afa460821..6f25c90a4 100644 --- a/src/report.cpp +++ b/src/report.cpp @@ -2447,6 +2447,16 @@ std::string handleCustomReport ( table.addCell (row, columnCount, tasks[row].getDescription ()); } + else if (*col == "recur") + { + table.addColumn ("Recur"); + table.setColumnWidth (columnCount, Table::minimum); + table.setColumnJustification (columnCount, Table::right); + + for (unsigned int row = 0; row < tasks.size (); ++row) + table.addCell (row, columnCount, tasks[row].getAttribute ("recur")); + } + // Common to all columns. // Add underline. if (conf.get (std::string ("color"), true) || conf.get (std::string ("_forcecolor"), false)) @@ -2487,6 +2497,12 @@ std::string handleCustomReport ( Table::ascendingDate : Table::descendingDate)); + else if (column == "recur") + table.sortOn (columnIndex[column], + (direction == '+' ? + Table::ascendingPeriod : + Table::descendingPeriod)); + else table.sortOn (columnIndex[column], (direction == '+' ? @@ -2567,6 +2583,7 @@ void validReportColumns (const std::vector & columns) *it != "age" && *it != "active" && *it != "tags" && + *it != "recur" && *it != "description") bad.push_back (*it); diff --git a/src/task.h b/src/task.h index 03a5d5f7d..925b75811 100644 --- a/src/task.h +++ b/src/task.h @@ -126,7 +126,7 @@ void formatTimeDeltaDays (std::string&, time_t); std::string formatSeconds (time_t); const std::string uuid (); const char* optionalBlankLine (Config&); -int convertDuration (std::string&); +int convertDuration (const std::string&); std::string expandPath (const std::string&); #ifdef SOLARIS diff --git a/src/tests/recur.t b/src/tests/recur.t new file mode 100755 index 000000000..96a251bd2 --- /dev/null +++ b/src/tests/recur.t @@ -0,0 +1,67 @@ +#! /usr/bin/perl +################################################################################ +## task - a command line task list manager. +## +## Copyright 2006 - 2009, Paul Beckingham. +## 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 +## +################################################################################ + +use strict; +use warnings; +use Test::More tests => 6; + +# Create the rc file. +if (open my $fh, '>', 'recur.rc') +{ + print $fh "data.location=.\n", + "report.asc.columns=id,recur,description\n", + "report.asc.sort=recur+\n", + "report.desc.columns=id,recur,description\n", + "report.desc.sort=recur-\n"; + close $fh; + ok (-r 'recur.rc', 'Created recur.rc'); +} + +# Create a few recurring tasks, and test the sort order of the recur column. +qx{../task rc:recur.rc add due:tomorrow recur:daily first}; +qx{../task rc:recur.rc add due:tomorrow recur:weekly second}; +qx{../task rc:recur.rc add due:tomorrow recur:3d third}; + +my $output = qx{../task rc:recur.rc asc}; +like ($output, qr/first .* third .* second/msx, 'daily 3d weekly'); + +$output = qx{../task rc:recur.rc desc}; +like ($output, qr/second .* third .* first/msx, 'weekly 3d daily'); + +# Cleanup. +unlink 'shadow.txt'; +ok (!-r 'shadow.txt', 'Removed shadow.txt'); + +unlink 'pending.data'; +ok (!-r 'pending.data', 'Removed pending.data'); + +unlink 'recur.rc'; +ok (!-r 'recur.rc', 'Removed recur.rc'); + +exit 0; + diff --git a/src/util.cpp b/src/util.cpp index bc1bea9f2..7f1e6b911 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -241,9 +241,9 @@ const std::string uuid () //////////////////////////////////////////////////////////////////////////////// // Recognize the following constructs, and return the number of days represented -int convertDuration (std::string& input) +int convertDuration (const std::string& input) { - input = lowerCase (input); + std::string lower_input = lowerCase (input); Date today; std::vector supported; @@ -263,7 +263,7 @@ int convertDuration (std::string& input) supported.push_back ("yearly"); std::vector matches; - if (autoComplete (input, supported, matches) == 1) + if (autoComplete (lower_input, supported, matches) == 1) { std::string found = matches[0]; @@ -279,19 +279,18 @@ int convertDuration (std::string& input) } // Support \d+ d|w|m|q|y - else { // Verify all digits followed by d, w, m, q, or y. - unsigned int length = input.length (); + unsigned int length = lower_input.length (); for (unsigned int i = 0; i < length; ++i) { - if (! isdigit (input[i]) && + if (! isdigit (lower_input[i]) && i == length - 1) { - int number = ::atoi (input.substr (0, i).c_str ()); + int number = ::atoi (lower_input.substr (0, i).c_str ()); - switch (input[length - 1]) + switch (lower_input[length - 1]) { case 'd': return number * 1; break; case 'w': return number * 7; break;