QString getterName() const { if (type == "bool" && !(name.startsWith("has") || name.startsWith("is"))) { return "is" + ucFirst(name); } else { return name; } }
std::string Date::dayName (int dow) { static const char* days[7] = { STRING_DATE_SUNDAY_LONG, STRING_DATE_MONDAY_LONG, STRING_DATE_TUESDAY_LONG, STRING_DATE_WEDNESDAY_LONG, STRING_DATE_THURSDAY_LONG, STRING_DATE_FRIDAY_LONG, STRING_DATE_SATURDAY_LONG, }; return ucFirst (days[dow]); }
void processEnumsForHeader(QDomNodeList fieldList, QTextStream& out) { for (int i = 0; i < fieldList.size(); i++) { QDomElement f = fieldList.at(i).toElement(); QDomNodeList enumNodes = f.elementsByTagName("enum"); if (enumNodes.size()) { QString name = ucFirst(f.attribute("name")); out << " enum " << name << " {\n"; for (int j = 0; j < enumNodes.size(); j++) { QDomElement en = enumNodes.at(j).toElement(); out << " " << en.attribute("name"); if (en.hasAttribute("value")) out << " = " << en.attribute("value"); if (j != enumNodes.size() - 1) out << ","; out << "\n"; } out << " };\n\n" << " static QString " << lcFirst(f.attribute("name")) << "ToString(" << name << " " << f.attribute("name") << ");\n\n"; } } }
std::string Date::monthName (int month) { static const char* months[12] = { STRING_DATE_JANUARY_LONG, STRING_DATE_FEBRUARY_LONG, STRING_DATE_MARCH_LONG, STRING_DATE_APRIL_LONG, STRING_DATE_MAY_LONG, STRING_DATE_JUNE_LONG, STRING_DATE_JULY_LONG, STRING_DATE_AUGUST_LONG, STRING_DATE_SEPTEMBER_LONG, STRING_DATE_OCTOBER_LONG, STRING_DATE_NOVEMBER_LONG, STRING_DATE_DECEMBER_LONG, }; assert (month > 0); assert (month <= 12); return ucFirst (months[month - 1]); }
std::string taskDifferences (const Task& before, const Task& after) { // Attributes are all there is, so figure the different attribute names // between before and after. std::vector <std::string> beforeAtts; Task::const_iterator att; for (att = before.begin (); att != before.end (); ++att) beforeAtts.push_back (att->first); std::vector <std::string> afterAtts; for (att = after.begin (); att != after.end (); ++att) afterAtts.push_back (att->first); std::vector <std::string> beforeOnly; std::vector <std::string> afterOnly; listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly); // Now start generating a description of the differences. std::stringstream out; std::vector <std::string>::iterator name; for (name = beforeOnly.begin (); name != beforeOnly.end (); ++name) out << " - " << format (STRING_FEEDBACK_DELETED, ucFirst (*name)) << "\n"; for (name = afterOnly.begin (); name != afterOnly.end (); ++name) { if (*name == "depends") { std::vector <int> deps_after; after.getDependencies (deps_after); std::string to; join (to, ", ", deps_after); out << " - " << format (STRING_FEEDBACK_DEP_SET, to) << "\n"; } else out << " - " << format (STRING_FEEDBACK_ATT_SET, ucFirst (*name), renderAttribute (*name, after.get (*name))) << "\n"; } for (name = beforeAtts.begin (); name != beforeAtts.end (); ++name) { // Ignore UUID differences, and find values that changed, but are not also // in the beforeOnly and afterOnly lists, which have been handled above.. if (*name != "uuid" && before.get (*name) != after.get (*name) && std::find (beforeOnly.begin (), beforeOnly.end (), *name) == beforeOnly.end () && std::find (afterOnly.begin (), afterOnly.end (), *name) == afterOnly.end ()) { if (*name == "depends") { std::vector <int> deps_before; before.getDependencies (deps_before); std::string from; join (from, ", ", deps_before); std::vector <int> deps_after; after.getDependencies (deps_after); std::string to; join (to, ", ", deps_after); out << " - " << format (STRING_FEEDBACK_DEP_MOD, from, to) << "\n"; } else out << " - " << format (STRING_FEEDBACK_ATT_MOD, ucFirst (*name), renderAttribute (*name, before.get (*name)), renderAttribute (*name, after.get (*name))) << "\n"; } } // Shouldn't just say nothing. if (out.str ().length () == 0) out << " - " << STRING_FEEDBACK_NOP << "\n"; return out.str (); }
std::string taskInfoDifferences ( const Task& before, const Task& after, const std::string& dateformat, long& last_timestamp, const long current_timestamp) { // Attributes are all there is, so figure the different attribute names // between before and after. std::vector <std::string> beforeAtts; Task::const_iterator att; for (att = before.begin (); att != before.end (); ++att) beforeAtts.push_back (att->first); std::vector <std::string> afterAtts; for (att = after.begin (); att != after.end (); ++att) afterAtts.push_back (att->first); std::vector <std::string> beforeOnly; std::vector <std::string> afterOnly; listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly); // Now start generating a description of the differences. std::stringstream out; std::vector <std::string>::iterator name; for (name = beforeOnly.begin (); name != beforeOnly.end (); ++name) { if (*name == "depends") { std::vector <int> deps_before; before.getDependencies (deps_before); std::string from; join (from, ", ", deps_before); out << format (STRING_FEEDBACK_DEP_DEL, from) << "\n"; } else if (name->substr (0, 11) == "annotation_") { out << format (STRING_FEEDBACK_ANN_DEL, before.get (*name)) << "\n"; } else if (*name == "start") { out << format (STRING_FEEDBACK_ATT_DEL_DUR, ucFirst (*name), Duration (current_timestamp - last_timestamp).formatPrecise ()) << "\n"; } else { out << format (STRING_FEEDBACK_ATT_DEL, ucFirst (*name)) << "\n"; } } for (name = afterOnly.begin (); name != afterOnly.end (); ++name) { if (*name == "depends") { std::vector <int> deps_after; after.getDependencies (deps_after); std::string to; join (to, ", ", deps_after); out << format (STRING_FEEDBACK_DEP_WAS_SET, to) << "\n"; } else if (name->substr (0, 11) == "annotation_") { out << format (STRING_FEEDBACK_ANN_ADD, after.get (*name)) << "\n"; } else { if (*name == "start") last_timestamp = current_timestamp; out << format (STRING_FEEDBACK_ATT_WAS_SET, ucFirst (*name), renderAttribute (*name, after.get (*name), dateformat)) << "\n"; } } for (name = beforeAtts.begin (); name != beforeAtts.end (); ++name) if (*name != "uuid" && before.get (*name) != after.get (*name) && before.get (*name) != "" && after.get (*name) != "") { if (*name == "depends") { std::vector <int> deps_before; before.getDependencies (deps_before); std::string from; join (from, ", ", deps_before); std::vector <int> deps_after; after.getDependencies (deps_after); std::string to; join (to, ", ", deps_after); out << format (STRING_FEEDBACK_DEP_WAS_MOD, from, to) << "\n"; } else if (name->substr (0, 11) == "annotation_") { out << format (STRING_FEEDBACK_ANN_WAS_MOD, after.get (*name)) << "\n"; } else out << format (STRING_FEEDBACK_ATT_WAS_MOD, ucFirst (*name), renderAttribute (*name, before.get (*name), dateformat), renderAttribute (*name, after.get (*name), dateformat)) << "\n"; } // Shouldn't just say nothing. if (out.str ().length () == 0) out << STRING_FEEDBACK_WAS_NOP << "\n"; return out.str (); }
std::string CmdEdit::formatTask (Task task, const std::string& dateformat) { std::stringstream before; bool verbose = context.verbose ("edit"); if (verbose) before << "# " << STRING_EDIT_HEADER_1 << "\n" << "# " << STRING_EDIT_HEADER_2 << "\n" << "# " << STRING_EDIT_HEADER_3 << "\n" << "# " << STRING_EDIT_HEADER_4 << "\n" << "# " << STRING_EDIT_HEADER_5 << "\n" << "# " << STRING_EDIT_HEADER_6 << "\n" << "#\n" << "# " << STRING_EDIT_HEADER_7 << "\n" << "# " << STRING_EDIT_HEADER_8 << "\n" << "# " << STRING_EDIT_HEADER_9 << "\n" << "#\n" << "# " << STRING_EDIT_HEADER_10 << "\n" << "# " << STRING_EDIT_HEADER_11 << "\n" << "# " << STRING_EDIT_HEADER_12 << "\n" << "#\n"; before << "# " << STRING_EDIT_TABLE_HEADER_1 << "\n" << "# " << STRING_EDIT_TABLE_HEADER_2 << "\n" << "# ID: " << task.id << "\n" << "# UUID: " << task.get ("uuid") << "\n" << "# Status: " << ucFirst (Task::statusToText (task.getStatus ())) << "\n" // L10N safe ucFirst. << "# Mask: " << task.get ("mask") << "\n" << "# iMask: " << task.get ("imask") << "\n" << " Project: " << task.get ("project") << "\n"; std::vector <std::string> tags; task.getTags (tags); std::string allTags; join (allTags, " ", tags); if (verbose) before << "# " << STRING_EDIT_TAG_SEP << "\n"; before << " Tags: " << allTags << "\n" << " Description: " << task.get ("description") << "\n" << " Created: " << formatDate (task, "entry", dateformat) << "\n" << " Started: " << formatDate (task, "start", dateformat) << "\n" << " Ended: " << formatDate (task, "end", dateformat) << "\n" << " Scheduled: " << formatDate (task, "scheduled", dateformat) << "\n" << " Due: " << formatDate (task, "due", dateformat) << "\n" << " Until: " << formatDate (task, "until", dateformat) << "\n" << " Recur: " << task.get ("recur") << "\n" << " Wait until: " << formatDate (task, "wait", dateformat) << "\n" << "# Modified: " << formatDate (task, "modified", dateformat) << "\n" << " Parent: " << task.get ("parent") << "\n"; if (verbose) before << "# " << STRING_EDIT_HEADER_13 << "\n" << "# " << STRING_EDIT_HEADER_14 << "\n" << "# " << STRING_EDIT_HEADER_15 << "\n"; std::map <std::string, std::string> annotations; task.getAnnotations (annotations); std::map <std::string, std::string>::iterator anno; for (anno = annotations.begin (); anno != annotations.end (); ++anno) { Date dt (strtol (anno->first.substr (11).c_str (), NULL, 10)); before << " Annotation: " << dt.toString (dateformat) << " -- " << anno->second << "\n"; } Date now; before << " Annotation: " << now.toString (dateformat) << " -- \n"; // Add dependencies here. std::vector <std::string> dependencies; task.getDependencies (dependencies); std::stringstream allDeps; for (unsigned int i = 0; i < dependencies.size (); ++i) { if (i) allDeps << ","; Task t; context.tdb2.get (dependencies[i], t); if (t.getStatus () == Task::pending || t.getStatus () == Task::waiting) allDeps << t.id; else allDeps << dependencies[i]; } if (verbose) before << "# " << STRING_EDIT_DEP_SEP << "\n"; before << " Dependencies: " << allDeps.str () << "\n"; // UDAs std::vector <std::string> udas; std::map <std::string, Column*>::iterator col; for (col = context.columns.begin (); col != context.columns.end (); ++col) if (context.config.get ("uda." + col->first + ".type") != "") udas.push_back (col->first); if (udas.size ()) { before << "# " << STRING_EDIT_UDA_SEP << "\n"; std::sort (udas.begin (), udas.end ()); std::vector <std::string>::iterator uda; for (uda = udas.begin (); uda != udas.end (); ++uda) { int pad = 13 - uda->length (); std::string padding = ""; if (pad > 0) padding = std::string (pad, ' '); std::string type = context.config.get ("uda." + *uda + ".type"); if (type == "string" || type == "numeric") before << " UDA " << *uda << ": " << padding << task.get (*uda) << "\n"; else if (type == "date") before << " UDA " << *uda << ": " << padding << formatDate (task, *uda, dateformat) << "\n"; else if (type == "duration") before << " UDA " << *uda << ": " << padding << formatDuration (task, *uda) << "\n"; } } // UDA orphans std::vector <std::string> orphans; task.getUDAOrphans (orphans); if (orphans.size ()) { before << "# " << STRING_EDIT_UDA_ORPHAN_SEP << "\n"; std::sort (orphans.begin (), orphans.end ()); std::vector <std::string>::iterator orphan; for (orphan = orphans.begin (); orphan != orphans.end (); ++orphan) { int pad = 6 - orphan->length (); std::string padding = ""; if (pad > 0) padding = std::string (pad, ' '); before << " UDA Orphan " << *orphan << ": " << padding << task.get (*orphan) << "\n"; } } before << "# " << STRING_EDIT_END << "\n"; return before.str (); }
static QMap<QString, Field> getFields(QDomElement record, bool* foundStrings = 0) { QDomNodeList types = record.elementsByTagName("type"); QMap<QString, QString> extraTypes; QMap<QString, QString> extraTypesDefaults; for (int i = 0; i < types.size(); i++) { QDomElement e = types.at(i).toElement(); extraTypes[e.attribute("name")] = e.attribute("type"); if (e.elementsByTagName("enum").size() > 0) extraTypesDefaults[e.attribute("name")] = e.elementsByTagName("enum").at(0).toElement().attribute("name"); } QDomNodeList fields = record.elementsByTagName("field"); QMap<QString, Field> map; for (int i = 0; i < fields.size(); i++) { QDomElement e = fields.at(i).toElement(); QString name = e.attribute("name"); if (!name.startsWith("reserved")) { map[name] = Field(name, getFieldType(e.attribute("type"), e.attribute("size").toUInt(), map[name].type, extraTypes)); if (foundStrings && map[name].type == "QString") *foundStrings = true; if (hasParentNode(e, "array")) { map[name].isArray = true; } if (e.elementsByTagName("enum").size() > 0) { map[name].isEnum = true; map[name].type = ucFirst(name); map[name].defaultValue = e.elementsByTagName("enum").at(0).toElement().attribute("name"); } if (extraTypes.contains(e.attribute("type"))) { map[name].isEnum = true; map[name].type = e.attribute("type"); map[name].defaultValue = extraTypesDefaults[e.attribute("type")]; } if (e.hasAttribute("default")) map[name].defaultValue = e.attribute("default"); } } for (int i = 0; i < fields.size(); i++) { QDomElement e = fields.at(i).toElement(); if (e.hasAttribute("length")) { QString name = e.attribute("length"); if (map.contains(name)) { map[name].isStringLength = true; map[name].lengthFor = e.attribute("name"); } } } QDomNodeList arrays = record.elementsByTagName("array"); for (int i = 0; i < arrays.size(); i++) { QDomElement e = arrays.at(i).toElement(); QString name = e.attribute("length"); if (map.contains(name)) { Field& field = map[name]; field.isArrayLength = true; QDomNodeList afields = e.elementsByTagName("field"); for (int j = 0; j < afields.size(); j++) { QDomElement af = afields.at(j).toElement(); QString fname = af.attribute("name"); if (!fname.startsWith("reserved")) field.arrayFields.append(map[fname]); } } } return map; }
QString setterName() const { return "set" + ucFirst(name); }
int CmdInfo::execute (std::string& output) { int rc = 0; // Apply filter. std::vector <Task> filtered; filter (filtered); if (! filtered.size ()) { context.footnote (STRING_FEEDBACK_NO_MATCH); rc = 1; } // Get the undo data. std::vector <std::string> undo; if (context.config.getBoolean ("journal.info")) undo = context.tdb2.undo.get_lines (); // Determine the output date format, which uses a hierarchy of definitions. // rc.dateformat.info // rc.dateformat std::string dateformat = context.config.get ("dateformat.info"); if (dateformat == "") dateformat = context.config.get ("dateformat"); std::string dateformatanno = context.config.get ("dateformat.annotation"); if (dateformatanno == "") dateformatanno = dateformat; // Render each task. std::stringstream out; std::vector <Task>::iterator task; for (task = filtered.begin (); task != filtered.end (); ++task) { ViewText view; view.width (context.getWidth ()); view.add (Column::factory ("string", STRING_COLUMN_LABEL_NAME)); view.add (Column::factory ("string", STRING_COLUMN_LABEL_VALUE)); // If an alternating row color is specified, notify the table. if (context.color ()) { Color alternate (context.config.get ("color.alternate")); view.colorOdd (alternate); view.intraColorOdd (alternate); } Date now; // id int row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_ID); view.set (row, 1, (task->id ? format (task->id) : "-")); std::string status = ucFirst (Task::statusToText (task->getStatus ())); // description Color c; autoColorize (*task, c); std::string description = task->get ("description"); int indent = context.config.getInteger ("indent.annotation"); std::map <std::string, std::string> annotations; task->getAnnotations (annotations); std::map <std::string, std::string>::iterator ann; for (ann = annotations.begin (); ann != annotations.end (); ++ann) description += "\n" + std::string (indent, ' ') + Date (ann->first.substr (11)).toString (dateformatanno) + " " + ann->second; row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_DESC); view.set (row, 1, description, c); // status row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_STATUS); view.set (row, 1, status); // project if (task->has ("project")) { row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_PROJECT); view.set (row, 1, task->get ("project")); } // priority if (task->has ("priority")) { row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_PRIORITY); view.set (row, 1, task->get ("priority")); } // dependencies: blocked { std::vector <Task> blocked; dependencyGetBlocking (*task, blocked); if (blocked.size ()) { std::stringstream message; std::vector <Task>::const_iterator it; for (it = blocked.begin (); it != blocked.end (); ++it) message << it->id << " " << it->get ("description") << "\n"; row = view.addRow (); view.set (row, 0, STRING_CMD_INFO_BLOCKED); view.set (row, 1, message.str ()); } } // dependencies: blocking { std::vector <Task> blocking; dependencyGetBlocked (*task, blocking); if (blocking.size ()) { std::stringstream message; std::vector <Task>::const_iterator it; for (it = blocking.begin (); it != blocking.end (); ++it) message << it->id << " " << it->get ("description") << "\n"; row = view.addRow (); view.set (row, 0, STRING_CMD_INFO_BLOCKING); view.set (row, 1, message.str ()); } } // recur if (task->has ("recur")) { row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_RECUR_L); view.set (row, 1, task->get ("recur")); } // until if (task->has ("until")) { row = view.addRow (); view.set (row, 0, STRING_CMD_INFO_UNTIL); view.set (row, 1, Date (task->get_date ("until")).toString (dateformat)); } // mask if (task->getStatus () == Task::recurring) { row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_MASK); view.set (row, 1, task->get ("mask")); } if (task->has ("parent")) { // parent row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_PARENT); view.set (row, 1, task->get ("parent")); // imask row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_MASK_IDX); view.set (row, 1, task->get ("imask")); } // due (colored) if (task->has ("due")) { row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_DUE); view.set (row, 1, Date (task->get_date ("due")).toString (dateformat)); } // wait if (task->has ("wait")) { row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_WAITING); view.set (row, 1, Date (task->get_date ("wait")).toString (dateformat)); } // scheduled if (task->has ("scheduled")) { row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_SCHED); view.set (row, 1, Date (task->get_date ("scheduled")).toString (dateformat)); } // start if (task->has ("start")) { row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_START); view.set (row, 1, Date (task->get_date ("start")).toString (dateformat)); } // end if (task->has ("end")) { row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_END); view.set (row, 1, Date (task->get_date ("end")).toString (dateformat)); } // tags ... std::vector <std::string> tags; task->getTags (tags); if (tags.size ()) { std::string allTags; join (allTags, " ", tags); row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_TAGS); view.set (row, 1, allTags); } // uuid row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_UUID); std::string uuid = task->get ("uuid"); view.set (row, 1, uuid); // entry row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_ENTERED); Date dt (task->get_date ("entry")); std::string entry = dt.toString (dateformat); std::string age; std::string created = task->get ("entry"); if (created.length ()) { Date dt (strtol (created.c_str (), NULL, 10)); age = Duration (now - dt).format (); } view.set (row, 1, entry + " (" + age + ")"); // fg TODO deprecated 2.0 std::string color = task->get ("fg"); if (color != "") { row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_FG); view.set (row, 1, color); } // bg TODO deprecated 2.0 color = task->get ("bg"); if (color != "") { row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_BG); view.set (row, 1, color); } // Task::urgency row = view.addRow (); view.set (row, 0, STRING_COLUMN_LABEL_URGENCY); view.set (row, 1, trimLeft (format (task->urgency (), 4, 4))); // Show any UDAs std::vector <std::string> all = task->all (); std::vector <std::string>::iterator att; std::string type; for (att = all.begin (); att != all.end (); ++att) { type = context.config.get ("uda." + *att + ".type"); if (type != "") { Column* col = context.columns[*att]; if (col) { std::string value = task->get (*att); if (value != "") { row = view.addRow (); view.set (row, 0, col->label ()); if (type == "date") value = Date (value).toString (dateformat); else if (type == "duration") value = Duration (value).formatCompact (); view.set (row, 1, value); } } } } // Show any orphaned UDAs, which are identified by not being represented in // the context.columns map. for (att = all.begin (); att != all.end (); ++att) if (att->substr (0, 11) != "annotation_" && context.columns.find (*att) == context.columns.end ()) { row = view.addRow (); view.set (row, 0, "[" + *att); view.set (row, 1, task->get (*att) + "]"); } // Create a second table, containing undo log change details. ViewText journal; // If an alternating row color is specified, notify the table. if (context.color ()) { Color alternate (context.config.get ("color.alternate")); journal.colorOdd (alternate); journal.intraColorOdd (alternate); } journal.width (context.getWidth ()); journal.add (Column::factory ("string", STRING_COLUMN_LABEL_DATE)); journal.add (Column::factory ("string", STRING_CMD_INFO_MODIFICATION)); if (context.config.getBoolean ("journal.info") && undo.size () > 3) { // Scan the undo data for entries matching this task. std::string when; std::string previous; std::string current; unsigned int i = 0; long total_time = 0; while (i < undo.size ()) { when = undo[i++]; previous = ""; if (undo[i].substr (0, 3) == "old") previous = undo[i++]; current = undo[i++]; i++; // Separator if (current.find ("uuid:\"" + uuid) != std::string::npos) { if (previous != "") { int row = journal.addRow (); Date timestamp (strtol (when.substr (5).c_str (), NULL, 10)); journal.set (row, 0, timestamp.toString (dateformat)); Task before (previous.substr (4)); Task after (current.substr (4)); journal.set (row, 1, taskInfoDifferences (before, after, dateformat)); // calculate the total active time if (before.get ("start") == "" && after.get ("start") != "") { // task started total_time -= timestamp.toEpoch (); } else if (((before.get ("start") != "" && after.get ("start") == "") || (before.get ("status") != "completed" && after.get ("status") == "completed")) && total_time < 0) { // task stopped or done total_time += timestamp.toEpoch (); } } } } // add now() if task is still active if (total_time < 0) total_time += Date ().toEpoch (); // print total active time if (total_time > 0) { row = journal.addRow (); journal.set (row, 0, STRING_CMD_INFO_TOTAL_ACTIVE); journal.set (row, 1, Duration (total_time).formatPrecise (), (context.color () ? Color ("bold") : Color ())); } } out << optionalBlankLine () << view.render () << "\n"; if (journal.rows () > 0) out << journal.render () << "\n"; } output = out.str (); return rc; }