diff --git a/src/Makefile.am b/src/Makefile.am index 203f55eee..8d9c31a1a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,8 +3,8 @@ task_SOURCES = Att.cpp Cmd.cpp Config.cpp Context.cpp Date.cpp Duration.cpp \ Filter.cpp Grid.cpp Keymap.cpp Location.cpp Nibbler.cpp \ Record.cpp Sequence.cpp StringTable.cpp Subst.cpp Task.cpp \ TDB2.cpp Table.cpp Timer.cpp color.cpp command.cpp edit.cpp \ - import.cpp interactive.cpp parse.cpp recur.cpp report.cpp \ - rules.cpp main.cpp text.cpp util.cpp \ + import.cpp interactive.cpp valid.cpp recur.cpp report.cpp \ + custom.cpp rules.cpp main.cpp text.cpp util.cpp \ Att.h Cmd.h Config.h Context.h Date.h Duration.h Filter.h \ Grid.h Keymap.h Location.h Nibbler.h Record.h Sequence.h \ StringTable.h Subst.h Task.h TDB2.h Table.h Timer.h color.h \ diff --git a/src/custom.cpp b/src/custom.cpp new file mode 100644 index 000000000..c3648b9fa --- /dev/null +++ b/src/custom.cpp @@ -0,0 +1,473 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +// +//////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Context.h" +#include "Date.h" +#include "Table.h" +#include "T.h" +#include "text.h" +#include "util.h" +#include "main.h" + +#ifdef HAVE_LIBNCURSES +#include +#endif + +extern Context context; + +//////////////////////////////////////////////////////////////////////////////// +// This report will eventually become the one report that many others morph into +// via the .taskrc file. +std::string handleCustomReport (const std::string& report) +{ +/* + // Load report configuration. + std::string columnList = context.config.get ("report." + report + ".columns"); + std::vector columns; + split (columns, columnList, ','); + validReportColumns (columns); + + std::string labelList = context.config.get ("report." + report + ".labels"); + std::vector labels; + split (labels, labelList, ','); + + if (columns.size () != labels.size () && labels.size () != 0) + throw std::string ("There are a different number of columns than labels ") + + "for report '" + report + "'. Please correct this."; + + std::map columnLabels; + if (labels.size ()) + for (unsigned int i = 0; i < columns.size (); ++i) + columnLabels[columns[i]] = labels[i]; + + std::string sortList = context.config.get ("report." + report + ".sort"); + std::vector sortOrder; + split (sortOrder, sortList, ','); + validSortColumns (columns, sortOrder); + + std::string filterList = context.config.get ("report." + report + ".filter"); + std::vector filterArgs; + split (filterArgs, filterList, ' '); + + // Load all pending tasks. + std::vector tasks; + tdb.allPendingT (tasks); + handleRecurrence (tdb, tasks); + + // Apply filters. + { + std::string ignore; + T filterTask; + parse (filterArgs, ignore, filterTask); + + filter (tasks, filterTask); // Filter from custom report + filter (tasks, task); // Filter from command line + } + + // Initialize colorization for subsequent auto colorization. + initializeColorRules (); + + Table table; + table.setTableWidth (context.getWidth ()); + table.setDateFormat (context.config.get ("dateformat", "m/d/Y")); + + for (unsigned int i = 0; i < tasks.size (); ++i) + table.addRow (); + + int columnCount = 0; + int dueColumn = -1; + foreach (col, columns) + { + // Add each column individually. + if (*col == "id") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "ID"); + 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].getId ()); + } + + else if (*col == "uuid") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "UUID"); + table.setColumnWidth (columnCount, Table::minimum); + table.setColumnJustification (columnCount, Table::left); + + for (unsigned int row = 0; row < tasks.size(); ++row) + table.addCell (row, columnCount, tasks[row].getUUID ()); + } + + else if (*col == "project") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Project"); + table.setColumnWidth (columnCount, Table::minimum); + table.setColumnJustification (columnCount, Table::left); + + for (unsigned int row = 0; row < tasks.size(); ++row) + table.addCell (row, columnCount, tasks[row].getAttribute ("project")); + } + + else if (*col == "priority") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Pri"); + table.setColumnWidth (columnCount, Table::minimum); + table.setColumnJustification (columnCount, Table::left); + + for (unsigned int row = 0; row < tasks.size(); ++row) + table.addCell (row, columnCount, tasks[row].getAttribute ("priority")); + } + + else if (*col == "entry") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Added"); + table.setColumnWidth (columnCount, Table::minimum); + table.setColumnJustification (columnCount, Table::right); + + std::string entered; + for (unsigned int row = 0; row < tasks.size(); ++row) + { + entered = tasks[row].getAttribute ("entry"); + if (entered.length ()) + { + Date dt (::atoi (entered.c_str ())); + entered = dt.toString (context.config.get ("dateformat", "m/d/Y")); + table.addCell (row, columnCount, entered); + } + } + } + + else if (*col == "start") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Started"); + table.setColumnWidth (columnCount, Table::minimum); + table.setColumnJustification (columnCount, Table::right); + + std::string started; + for (unsigned int row = 0; row < tasks.size(); ++row) + { + started = tasks[row].getAttribute ("start"); + if (started.length ()) + { + Date dt (::atoi (started.c_str ())); + started = dt.toString (context.config.get ("dateformat", "m/d/Y")); + table.addCell (row, columnCount, started); + } + } + } + + else if (*col == "due") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Due"); + table.setColumnWidth (columnCount, Table::minimum); + table.setColumnJustification (columnCount, Table::right); + + std::string due; + for (unsigned int row = 0; row < tasks.size(); ++row) + { + due = tasks[row].getAttribute ("due"); + if (due.length ()) + { + Date dt (::atoi (due.c_str ())); + due = dt.toString (context.config.get ("dateformat", "m/d/Y")); + table.addCell (row, columnCount, due); + } + } + + dueColumn = columnCount; + } + + else if (*col == "age") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Age"); + table.setColumnWidth (columnCount, Table::minimum); + table.setColumnJustification (columnCount, Table::right); + + std::string created; + std::string age; + Date now; + for (unsigned int row = 0; row < tasks.size(); ++row) + { + created = tasks[row].getAttribute ("entry"); + if (created.length ()) + { + Date dt (::atoi (created.c_str ())); + age = formatSeconds ((time_t) (now - dt)); + table.addCell (row, columnCount, age); + } + } + } + + else if (*col == "age_compact") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Age"); + table.setColumnWidth (columnCount, Table::minimum); + table.setColumnJustification (columnCount, Table::right); + + std::string created; + std::string age; + Date now; + for (unsigned int row = 0; row < tasks.size(); ++row) + { + created = tasks[row].getAttribute ("entry"); + if (created.length ()) + { + Date dt (::atoi (created.c_str ())); + age = formatSecondsCompact ((time_t) (now - dt)); + table.addCell (row, columnCount, age); + } + } + } + + else if (*col == "active") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Active"); + table.setColumnWidth (columnCount, Table::minimum); + table.setColumnJustification (columnCount, Table::left); + + for (unsigned int row = 0; row < tasks.size(); ++row) + if (tasks[row].getAttribute ("start") != "") + table.addCell (row, columnCount, "*"); + } + + else if (*col == "tags") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Tags"); + table.setColumnWidth (columnCount, Table::minimum); + table.setColumnJustification (columnCount, Table::left); + + std::vector all; + std::string tags; + for (unsigned int row = 0; row < tasks.size(); ++row) + { + tasks[row].getTags (all); + join (tags, " ", all); + table.addCell (row, columnCount, tags); + } + } + + else if (*col == "description_only") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Description"); + table.setColumnWidth (columnCount, Table::flexible); + table.setColumnJustification (columnCount, Table::left); + + for (unsigned int row = 0; row < tasks.size(); ++row) + table.addCell (row, columnCount, tasks[row].getDescription ()); + } + + else if (*col == "description") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Description"); + table.setColumnWidth (columnCount, Table::flexible); + table.setColumnJustification (columnCount, Table::left); + + std::string description; + std::string when; + for (unsigned int row = 0; row < tasks.size(); ++row) + { + description = tasks[row].getDescription (); + std::map annotations; + tasks[row].getAnnotations (annotations); + foreach (anno, annotations) + { + Date dt (anno->first); + when = dt.toString (context.config.get ("dateformat", "m/d/Y")); + description += "\n" + when + " " + anno->second; + } + + table.addCell (row, columnCount, description); + } + } + + else if (*col == "recur") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "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")); + } + + else if (*col == "recurrence_indicator") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "R"); + 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") != "" ? "R" : ""); + } + + else if (*col == "tag_indicator") + { + table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "T"); + 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].getTagCount () ? "+" : ""); + } + + // Common to all columns. + // Add underline. + if ((context.config.get (std::string ("color"), true) || context.config.get (std::string ("_forcecolor"), false)) && + context.config.get (std::string ("fontunderline"), "true")) + table.setColumnUnderline (columnCount); + else + table.setTableDashedUnderline (); + + ++columnCount; + } + + // Dynamically add sort criteria. + // Build a map of column names -> index. + std::map columnIndex; + for (unsigned int c = 0; c < columns.size (); ++c) + columnIndex[columns[c]] = c; + + foreach (sortColumn, sortOrder) + { + // Separate column and direction. + std::string column = sortColumn->substr (0, sortColumn->length () - 1); + char direction = (*sortColumn)[sortColumn->length () - 1]; + + if (column == "id") + table.sortOn (columnIndex[column], + (direction == '+' ? + Table::ascendingNumeric : + Table::descendingNumeric)); + + else if (column == "priority") + table.sortOn (columnIndex[column], + (direction == '+' ? + Table::ascendingPriority : + Table::descendingPriority)); + + else if (column == "entry" || column == "start" || column == "due") + table.sortOn (columnIndex[column], + (direction == '+' ? + Table::ascendingDate : + Table::descendingDate)); + + else if (column == "recur") + table.sortOn (columnIndex[column], + (direction == '+' ? + Table::ascendingPeriod : + Table::descendingPeriod)); + + else + table.sortOn (columnIndex[column], + (direction == '+' ? + Table::ascendingCharacter : + Table::descendingCharacter)); + } + + // Now auto colorize all rows. + std::string due; + bool imminent; + bool overdue; + for (unsigned int row = 0; row < tasks.size (); ++row) + { + imminent = false; + overdue = false; + due = tasks[row].getAttribute ("due"); + if (due.length ()) + { + switch (getDueState (due)) + { + case 2: overdue = true; break; + case 1: imminent = true; break; + case 0: + default: break; + } + } + + if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false)) + { + Text::color fg = Text::colorCode (tasks[row].getAttribute ("fg")); + Text::color bg = Text::colorCode (tasks[row].getAttribute ("bg")); + autoColorize (tasks[row], fg, bg); + table.setRowFg (row, fg); + table.setRowBg (row, bg); + + if (fg == Text::nocolor) + { + if (dueColumn != -1) + { + if (overdue) + table.setCellFg (row, columnCount, Text::colorCode (context.config.get ("color.overdue", "red"))); + else if (imminent) + table.setCellFg (row, columnCount, Text::colorCode (context.config.get ("color.due", "yellow"))); + } + } + } + } + + // Limit the number of rows according to the report definition. + int maximum = context.config.get (std::string ("report.") + report + ".limit", (int)0); + + // If the custom report has a defined limit, then allow an override, which + // will show up as a single ID sequence. + if (context.config.get (std::string ("report.") + report + ".limit", (int)0) != 0) + { + std::vector sequence = task.getAllIds (); + if (sequence.size () == 1) + maximum = sequence[0]; + } +*/ + std::stringstream out; +/* + if (table.rowCount ()) + out << optionalBlankLine () + << table.render (maximum) + << optionalBlankLine () + << table.rowCount () + << (table.rowCount () == 1 ? " task" : " tasks") + << std::endl; + else + out << "No matches." + << std::endl; +*/ + return out.str (); +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/src/main.h b/src/main.h index 410fa252f..e89d781e0 100644 --- a/src/main.h +++ b/src/main.h @@ -36,8 +36,7 @@ #include "color.h" #include "../auto.h" -// parse.cpp -void parse (std::vector &, std::string&, T&); +// valid.cpp bool validPriority (const std::string&); bool validDate (std::string&); bool validDuration (std::string&); @@ -103,6 +102,8 @@ std::string handleReportActive (); std::string handleReportOverdue (); std::string handleReportStats (); std::string handleReportTimesheet (); + +// custom.cpp std::string handleCustomReport (const std::string&); // rules.cpp diff --git a/src/report.cpp b/src/report.cpp index fcb457268..6e413f8ca 100644 --- a/src/report.cpp +++ b/src/report.cpp @@ -2613,425 +2613,4 @@ void gatherNextTasks ( all.push_back (i->first); } -//////////////////////////////////////////////////////////////////////////////// -// This report will eventually become the one report that many others morph into -// via the .taskrc file. -std::string handleCustomReport (const std::string& report) -{ -/* - // Load report configuration. - std::string columnList = context.config.get ("report." + report + ".columns"); - std::vector columns; - split (columns, columnList, ','); - validReportColumns (columns); - - std::string labelList = context.config.get ("report." + report + ".labels"); - std::vector labels; - split (labels, labelList, ','); - - if (columns.size () != labels.size () && labels.size () != 0) - throw std::string ("There are a different number of columns than labels ") + - "for report '" + report + "'. Please correct this."; - - std::map columnLabels; - if (labels.size ()) - for (unsigned int i = 0; i < columns.size (); ++i) - columnLabels[columns[i]] = labels[i]; - - std::string sortList = context.config.get ("report." + report + ".sort"); - std::vector sortOrder; - split (sortOrder, sortList, ','); - validSortColumns (columns, sortOrder); - - std::string filterList = context.config.get ("report." + report + ".filter"); - std::vector filterArgs; - split (filterArgs, filterList, ' '); - - // Load all pending tasks. - std::vector tasks; - tdb.allPendingT (tasks); - handleRecurrence (tdb, tasks); - - // Apply filters. - { - std::string ignore; - T filterTask; - parse (filterArgs, ignore, filterTask); - - filter (tasks, filterTask); // Filter from custom report - filter (tasks, task); // Filter from command line - } - - // Initialize colorization for subsequent auto colorization. - initializeColorRules (); - - Table table; - table.setTableWidth (context.getWidth ()); - table.setDateFormat (context.config.get ("dateformat", "m/d/Y")); - - for (unsigned int i = 0; i < tasks.size (); ++i) - table.addRow (); - - int columnCount = 0; - int dueColumn = -1; - foreach (col, columns) - { - // Add each column individually. - if (*col == "id") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "ID"); - 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].getId ()); - } - - else if (*col == "uuid") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "UUID"); - table.setColumnWidth (columnCount, Table::minimum); - table.setColumnJustification (columnCount, Table::left); - - for (unsigned int row = 0; row < tasks.size(); ++row) - table.addCell (row, columnCount, tasks[row].getUUID ()); - } - - else if (*col == "project") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Project"); - table.setColumnWidth (columnCount, Table::minimum); - table.setColumnJustification (columnCount, Table::left); - - for (unsigned int row = 0; row < tasks.size(); ++row) - table.addCell (row, columnCount, tasks[row].getAttribute ("project")); - } - - else if (*col == "priority") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Pri"); - table.setColumnWidth (columnCount, Table::minimum); - table.setColumnJustification (columnCount, Table::left); - - for (unsigned int row = 0; row < tasks.size(); ++row) - table.addCell (row, columnCount, tasks[row].getAttribute ("priority")); - } - - else if (*col == "entry") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Added"); - table.setColumnWidth (columnCount, Table::minimum); - table.setColumnJustification (columnCount, Table::right); - - std::string entered; - for (unsigned int row = 0; row < tasks.size(); ++row) - { - entered = tasks[row].getAttribute ("entry"); - if (entered.length ()) - { - Date dt (::atoi (entered.c_str ())); - entered = dt.toString (context.config.get ("dateformat", "m/d/Y")); - table.addCell (row, columnCount, entered); - } - } - } - - else if (*col == "start") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Started"); - table.setColumnWidth (columnCount, Table::minimum); - table.setColumnJustification (columnCount, Table::right); - - std::string started; - for (unsigned int row = 0; row < tasks.size(); ++row) - { - started = tasks[row].getAttribute ("start"); - if (started.length ()) - { - Date dt (::atoi (started.c_str ())); - started = dt.toString (context.config.get ("dateformat", "m/d/Y")); - table.addCell (row, columnCount, started); - } - } - } - - else if (*col == "due") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Due"); - table.setColumnWidth (columnCount, Table::minimum); - table.setColumnJustification (columnCount, Table::right); - - std::string due; - for (unsigned int row = 0; row < tasks.size(); ++row) - { - due = tasks[row].getAttribute ("due"); - if (due.length ()) - { - Date dt (::atoi (due.c_str ())); - due = dt.toString (context.config.get ("dateformat", "m/d/Y")); - table.addCell (row, columnCount, due); - } - } - - dueColumn = columnCount; - } - - else if (*col == "age") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Age"); - table.setColumnWidth (columnCount, Table::minimum); - table.setColumnJustification (columnCount, Table::right); - - std::string created; - std::string age; - Date now; - for (unsigned int row = 0; row < tasks.size(); ++row) - { - created = tasks[row].getAttribute ("entry"); - if (created.length ()) - { - Date dt (::atoi (created.c_str ())); - age = formatSeconds ((time_t) (now - dt)); - table.addCell (row, columnCount, age); - } - } - } - - else if (*col == "age_compact") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Age"); - table.setColumnWidth (columnCount, Table::minimum); - table.setColumnJustification (columnCount, Table::right); - - std::string created; - std::string age; - Date now; - for (unsigned int row = 0; row < tasks.size(); ++row) - { - created = tasks[row].getAttribute ("entry"); - if (created.length ()) - { - Date dt (::atoi (created.c_str ())); - age = formatSecondsCompact ((time_t) (now - dt)); - table.addCell (row, columnCount, age); - } - } - } - - else if (*col == "active") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Active"); - table.setColumnWidth (columnCount, Table::minimum); - table.setColumnJustification (columnCount, Table::left); - - for (unsigned int row = 0; row < tasks.size(); ++row) - if (tasks[row].getAttribute ("start") != "") - table.addCell (row, columnCount, "*"); - } - - else if (*col == "tags") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Tags"); - table.setColumnWidth (columnCount, Table::minimum); - table.setColumnJustification (columnCount, Table::left); - - std::vector all; - std::string tags; - for (unsigned int row = 0; row < tasks.size(); ++row) - { - tasks[row].getTags (all); - join (tags, " ", all); - table.addCell (row, columnCount, tags); - } - } - - else if (*col == "description_only") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Description"); - table.setColumnWidth (columnCount, Table::flexible); - table.setColumnJustification (columnCount, Table::left); - - for (unsigned int row = 0; row < tasks.size(); ++row) - table.addCell (row, columnCount, tasks[row].getDescription ()); - } - - else if (*col == "description") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Description"); - table.setColumnWidth (columnCount, Table::flexible); - table.setColumnJustification (columnCount, Table::left); - - std::string description; - std::string when; - for (unsigned int row = 0; row < tasks.size(); ++row) - { - description = tasks[row].getDescription (); - std::map annotations; - tasks[row].getAnnotations (annotations); - foreach (anno, annotations) - { - Date dt (anno->first); - when = dt.toString (context.config.get ("dateformat", "m/d/Y")); - description += "\n" + when + " " + anno->second; - } - - table.addCell (row, columnCount, description); - } - } - - else if (*col == "recur") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "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")); - } - - else if (*col == "recurrence_indicator") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "R"); - 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") != "" ? "R" : ""); - } - - else if (*col == "tag_indicator") - { - table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "T"); - 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].getTagCount () ? "+" : ""); - } - - // Common to all columns. - // Add underline. - if ((context.config.get (std::string ("color"), true) || context.config.get (std::string ("_forcecolor"), false)) && - context.config.get (std::string ("fontunderline"), "true")) - table.setColumnUnderline (columnCount); - else - table.setTableDashedUnderline (); - - ++columnCount; - } - - // Dynamically add sort criteria. - // Build a map of column names -> index. - std::map columnIndex; - for (unsigned int c = 0; c < columns.size (); ++c) - columnIndex[columns[c]] = c; - - foreach (sortColumn, sortOrder) - { - // Separate column and direction. - std::string column = sortColumn->substr (0, sortColumn->length () - 1); - char direction = (*sortColumn)[sortColumn->length () - 1]; - - if (column == "id") - table.sortOn (columnIndex[column], - (direction == '+' ? - Table::ascendingNumeric : - Table::descendingNumeric)); - - else if (column == "priority") - table.sortOn (columnIndex[column], - (direction == '+' ? - Table::ascendingPriority : - Table::descendingPriority)); - - else if (column == "entry" || column == "start" || column == "due") - table.sortOn (columnIndex[column], - (direction == '+' ? - Table::ascendingDate : - Table::descendingDate)); - - else if (column == "recur") - table.sortOn (columnIndex[column], - (direction == '+' ? - Table::ascendingPeriod : - Table::descendingPeriod)); - - else - table.sortOn (columnIndex[column], - (direction == '+' ? - Table::ascendingCharacter : - Table::descendingCharacter)); - } - - // Now auto colorize all rows. - std::string due; - bool imminent; - bool overdue; - for (unsigned int row = 0; row < tasks.size (); ++row) - { - imminent = false; - overdue = false; - due = tasks[row].getAttribute ("due"); - if (due.length ()) - { - switch (getDueState (due)) - { - case 2: overdue = true; break; - case 1: imminent = true; break; - case 0: - default: break; - } - } - - if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false)) - { - Text::color fg = Text::colorCode (tasks[row].getAttribute ("fg")); - Text::color bg = Text::colorCode (tasks[row].getAttribute ("bg")); - autoColorize (tasks[row], fg, bg); - table.setRowFg (row, fg); - table.setRowBg (row, bg); - - if (fg == Text::nocolor) - { - if (dueColumn != -1) - { - if (overdue) - table.setCellFg (row, columnCount, Text::colorCode (context.config.get ("color.overdue", "red"))); - else if (imminent) - table.setCellFg (row, columnCount, Text::colorCode (context.config.get ("color.due", "yellow"))); - } - } - } - } - - // Limit the number of rows according to the report definition. - int maximum = context.config.get (std::string ("report.") + report + ".limit", (int)0); - - // If the custom report has a defined limit, then allow an override, which - // will show up as a single ID sequence. - if (context.config.get (std::string ("report.") + report + ".limit", (int)0) != 0) - { - std::vector sequence = task.getAllIds (); - if (sequence.size () == 1) - maximum = sequence[0]; - } -*/ - std::stringstream out; -/* - if (table.rowCount ()) - out << optionalBlankLine () - << table.render (maximum) - << optionalBlankLine () - << table.rowCount () - << (table.rowCount () == 1 ? " task" : " tasks") - << std::endl; - else - out << "No matches." - << std::endl; -*/ - return out.str (); -} - /////////////////////////////////////////////////////////////////////////////// diff --git a/src/parse.cpp b/src/valid.cpp similarity index 100% rename from src/parse.cpp rename to src/valid.cpp