diff --git a/src/TDB2.cpp b/src/TDB2.cpp index be3d7d83c..dc1b7762e 100644 --- a/src/TDB2.cpp +++ b/src/TDB2.cpp @@ -1025,203 +1025,24 @@ void TDB2::show_diff ( Color color_red (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.before") : ""); Color color_green (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.after") : ""); + auto before = prior == "" ? Task() : Task(prior); + auto after = Task(current); + if (Context::getContext ().config.get ("undo.style") == "side") { + Table view = before.diffForUndoSide(after); + std::cout << '\n' << format ("The last modification was made {1}", lastChange.toString ()) - << '\n'; - - // Attributes are all there is, so figure the different attribute names - // between before and after. - Table view; - view.width (Context::getContext ().getWidth ()); - view.intraPadding (2); - view.add (""); - view.add ("Prior Values"); - view.add ("Current Values"); - setHeaderUnderline (view); - - Task after (current); - - if (prior != "") - { - Task before (prior); - - std::vector beforeAtts; - for (auto& att : before.data_removeme ()) - beforeAtts.push_back (att.first); - - std::vector afterAtts; - for (auto& att : after.data_removeme ()) - afterAtts.push_back (att.first); - - std::vector beforeOnly; - std::vector afterOnly; - listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly); - - int row; - for (auto& name : beforeOnly) - { - row = view.addRow (); - view.set (row, 0, name); - view.set (row, 1, renderAttribute (name, before.get (name)), color_red); - } - - for (auto& att : before.data_removeme ()) - { - std::string priorValue = before.get (att.first); - std::string currentValue = after.get (att.first); - - if (currentValue != "") - { - row = view.addRow (); - view.set (row, 0, att.first); - view.set (row, 1, renderAttribute (att.first, priorValue), - (priorValue != currentValue ? color_red : Color ())); - view.set (row, 2, renderAttribute (att.first, currentValue), - (priorValue != currentValue ? color_green : Color ())); - } - } - - for (auto& name : afterOnly) - { - row = view.addRow (); - view.set (row, 0, name); - view.set (row, 2, renderAttribute (name, after.get (name)), color_green); - } - } - else - { - int row; - for (auto& att : after.data_removeme ()) - { - row = view.addRow (); - view.set (row, 0, att.first); - view.set (row, 2, renderAttribute (att.first, after.get (att.first)), color_green); - } - } - - std::cout << '\n' + << '\n' + << '\n' << view.render () << '\n'; } - // This style looks like this: - // --- before 2009-07-04 00:00:25.000000000 +0200 - // +++ after 2009-07-04 00:00:45.000000000 +0200 - // - // - name: old // att deleted - // + name: - // - // - name: old // att changed - // + name: new - // - // - name: - // + name: new // att added - // else if (Context::getContext ().config.get ("undo.style") == "diff") { - // Create reference tasks. - Task before; - if (prior != "") - before.parse (prior); - - Task after (current); - - // Generate table header. - Table view; - view.width (Context::getContext ().getWidth ()); - view.intraPadding (2); - view.add (""); - view.add (""); - - int row = view.addRow (); - view.set (row, 0, "--- previous state", color_red); - view.set (row, 1, "Undo will restore this state", color_red); - - row = view.addRow (); - view.set (row, 0, "+++ current state ", color_green); - view.set (row, 1, format ("Change made {1}", - lastChange.toString (Context::getContext ().config.get ("dateformat"))), - color_green); - - view.addRow (); - - // Add rows to table showing diffs. - std::vector all = Context::getContext ().getColumns (); - - // Now factor in the annotation attributes. - for (auto& it : before.data_removeme ()) - if (it.first.substr (0, 11) == "annotation_") - all.push_back (it.first); - - for (auto& it : after.data_removeme ()) - if (it.first.substr (0, 11) == "annotation_") - all.push_back (it.first); - - // Now render all the attributes. - std::sort (all.begin (), all.end ()); - - std::string before_att; - std::string after_att; - std::string last_att; - for (auto& a : all) - { - if (a != last_att) // Skip duplicates. - { - last_att = a; - - before_att = before.get (a); - after_att = after.get (a); - - // Don't report different uuid. - // Show nothing if values are the unchanged. - if (a == "uuid" || - before_att == after_att) - { - // Show nothing - no point displaying that which did not change. - - // row = view.addRow (); - // view.set (row, 0, *a + ":"); - // view.set (row, 1, before_att); - } - - // Attribute deleted. - else if (before_att != "" && after_att == "") - { - row = view.addRow (); - view.set (row, 0, '-' + a + ':', color_red); - view.set (row, 1, before_att, color_red); - - row = view.addRow (); - view.set (row, 0, '+' + a + ':', color_green); - } - - // Attribute added. - else if (before_att == "" && after_att != "") - { - row = view.addRow (); - view.set (row, 0, '-' + a + ':', color_red); - - row = view.addRow (); - view.set (row, 0, '+' + a + ':', color_green); - view.set (row, 1, after_att, color_green); - } - - // Attribute changed. - else - { - row = view.addRow (); - view.set (row, 0, '-' + a + ':', color_red); - view.set (row, 1, before_att, color_red); - - row = view.addRow (); - view.set (row, 0, '+' + a + ':', color_green); - view.set (row, 1, after_att, color_green); - } - } - } - + Table view = before.diffForUndoPatch(after, lastChange); std::cout << '\n' << view.render () << '\n'; diff --git a/src/Task.cpp b/src/Task.cpp index f0ddf833a..dd48514df 100644 --- a/src/Task.cpp +++ b/src/Task.cpp @@ -2425,7 +2425,8 @@ void Task::modify (modType type, bool text_required /* = false */) #endif //////////////////////////////////////////////////////////////////////////////// -// Compare this task to another and summarize the differences for display +// Compare this task to another and summarize the differences for display, in +// the future tense ("Foo will be set to .."). std::string Task::diff (const Task& after) const { // Attributes are all there is, so figure the different attribute names @@ -2670,3 +2671,206 @@ std::string Task::diffForInfo ( } //////////////////////////////////////////////////////////////////////////////// +// Similar to diff, but formatted as a side-by-side table for an Undo preview +Table Task::diffForUndoSide ( + const Task& after) const +{ + // Set the colors. + Color color_red (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.before") : ""); + Color color_green (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.after") : ""); + + // Attributes are all there is, so figure the different attribute names + // between before and after. + Table view; + view.width (Context::getContext ().getWidth ()); + view.intraPadding (2); + view.add (""); + view.add ("Prior Values"); + view.add ("Current Values"); + setHeaderUnderline (view); + + if (!is_empty ()) + { + const Task &before = *this; + + std::vector beforeAtts; + for (auto& att : before.data) + beforeAtts.push_back (att.first); + + std::vector afterAtts; + for (auto& att : after.data) + afterAtts.push_back (att.first); + + std::vector beforeOnly; + std::vector afterOnly; + listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly); + + int row; + for (auto& name : beforeOnly) + { + row = view.addRow (); + view.set (row, 0, name); + view.set (row, 1, renderAttribute (name, before.get (name)), color_red); + } + + for (auto& att : before.data) + { + std::string priorValue = before.get (att.first); + std::string currentValue = after.get (att.first); + + if (currentValue != "") + { + row = view.addRow (); + view.set (row, 0, att.first); + view.set (row, 1, renderAttribute (att.first, priorValue), + (priorValue != currentValue ? color_red : Color ())); + view.set (row, 2, renderAttribute (att.first, currentValue), + (priorValue != currentValue ? color_green : Color ())); + } + } + + for (auto& name : afterOnly) + { + row = view.addRow (); + view.set (row, 0, name); + view.set (row, 2, renderAttribute (name, after.get (name)), color_green); + } + } + else + { + int row; + for (auto& att : after.data) + { + row = view.addRow (); + view.set (row, 0, att.first); + view.set (row, 2, renderAttribute (att.first, after.get (att.first)), color_green); + } + } + + return view; +} + +//////////////////////////////////////////////////////////////////////////////// +// Similar to diff, but formatted as a diff for an Undo preview +Table Task::diffForUndoPatch ( + const Task& after, + const Datetime& lastChange) const +{ + // This style looks like this: + // --- before 2009-07-04 00:00:25.000000000 +0200 + // +++ after 2009-07-04 00:00:45.000000000 +0200 + // + // - name: old // att deleted + // + name: + // + // - name: old // att changed + // + name: new + // + // - name: + // + name: new // att added + // + + // Set the colors. + Color color_red (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.before") : ""); + Color color_green (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.after") : ""); + + const Task &before = *this; + + // Generate table header. + Table view; + view.width (Context::getContext ().getWidth ()); + view.intraPadding (2); + view.add (""); + view.add (""); + + int row = view.addRow (); + view.set (row, 0, "--- previous state", color_red); + view.set (row, 1, "Undo will restore this state", color_red); + + row = view.addRow (); + view.set (row, 0, "+++ current state ", color_green); + view.set (row, 1, format ("Change made {1}", + lastChange.toString (Context::getContext ().config.get ("dateformat"))), + color_green); + + view.addRow (); + + // Add rows to table showing diffs. + std::vector all = Context::getContext ().getColumns (); + + // Now factor in the annotation attributes. + for (auto& it : before.data) + if (it.first.substr (0, 11) == "annotation_") + all.push_back (it.first); + + for (auto& it : after.data) + if (it.first.substr (0, 11) == "annotation_") + all.push_back (it.first); + + // Now render all the attributes. + std::sort (all.begin (), all.end ()); + + std::string before_att; + std::string after_att; + std::string last_att; + for (auto& a : all) + { + if (a != last_att) // Skip duplicates. + { + last_att = a; + + before_att = before.get (a); + after_att = after.get (a); + + // Don't report different uuid. + // Show nothing if values are the unchanged. + if (a == "uuid" || + before_att == after_att) + { + // Show nothing - no point displaying that which did not change. + + // row = view.addRow (); + // view.set (row, 0, *a + ":"); + // view.set (row, 1, before_att); + } + + // Attribute deleted. + else if (before_att != "" && after_att == "") + { + row = view.addRow (); + view.set (row, 0, '-' + a + ':', color_red); + view.set (row, 1, before_att, color_red); + + row = view.addRow (); + view.set (row, 0, '+' + a + ':', color_green); + } + + // Attribute added. + else if (before_att == "" && after_att != "") + { + row = view.addRow (); + view.set (row, 0, '-' + a + ':', color_red); + + row = view.addRow (); + view.set (row, 0, '+' + a + ':', color_green); + view.set (row, 1, after_att, color_green); + } + + // Attribute changed. + else + { + row = view.addRow (); + view.set (row, 0, '-' + a + ':', color_red); + view.set (row, 1, before_att, color_red); + + row = view.addRow (); + view.set (row, 0, '+' + a + ':', color_green); + view.set (row, 1, after_att, color_green); + } + } + } + + return view; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Task.h b/src/Task.h index 13ec396fa..c3a6259f1 100644 --- a/src/Task.h +++ b/src/Task.h @@ -33,6 +33,8 @@ #include #include #include +#include +#include class Task { @@ -173,6 +175,8 @@ public: std::string diff (const Task& after) const; std::string diffForInfo (const Task& after, const std::string& dateformat, long& last_timestamp, const long current_timestamp) const; + Table diffForUndoSide (const Task& after) const; + Table diffForUndoPatch (const Task& after, const Datetime& lastChange) const; private: int determineVersion (const std::string&);