reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

commit f32c826a00dd174e6ac31f0e132c2f0341d2d2f7
parent 1e7a26d986ef051b363078f35945708b195f76be
Author: cfillion <cfillion@users.noreply.github.com>
Date:   Tue, 21 Jun 2016 03:34:36 -0400

browser: add Last Update column (collapsed by default)

Diffstat:
Msrc/browser.cpp | 17++++++++++++++++-
Msrc/browser.hpp | 1+
Msrc/listview.cpp | 19+++++++++++--------
Msrc/report.cpp | 2+-
Asrc/time.cpp | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/time.hpp | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/version.cpp | 20+++-----------------
Msrc/version.hpp | 8++++----
Mtest/helper/io.cpp | 6++++++
Mtest/helper/io.hpp | 2++
Mtest/index_v1.cpp | 8++++----
Atest/time.cpp | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest/version.cpp | 29++++++-----------------------
13 files changed, 279 insertions(+), 58 deletions(-)

diff --git a/src/browser.cpp b/src/browser.cpp @@ -87,6 +87,7 @@ void Browser::onInit() {AUTO_STR("Author"), 95}, {AUTO_STR("Type"), 70}, {AUTO_STR("Repository"), 120, ListView::CollapseFlag}, + {AUTO_STR("Last Update"), 120, ListView::CollapseFlag}, }); m_list->onActivate([=] { history(m_list->itemUnderMouse()); }); @@ -95,6 +96,17 @@ void Browser::onInit() this, placeholders::_1, placeholders::_2)); m_list->sortByColumn(1); + m_list->setSortCallback(7 /* last update */, [&] (const int ai, const int bi) { + const Entry &a = m_entries[ai]; + const Entry &b = m_entries[bi]; + + if(!a.latest) + return -1; + else if(!b.latest) + return 1; + + return a.latest->time().compare(b.latest->time()); + }); const auto config = m_reapack->config()->browser(); m_list->restore(config->list, 1); @@ -640,11 +652,12 @@ ListView::Row Browser::makeRow(const Entry &entry) const const string &author = getValue(AuthorColumn, entry); const string &type = getValue(TypeColumn, entry); const string &remote = getValue(RemoteColumn, entry); + const string &date = getValue(TimeColumn, entry); return { make_autostring(state), make_autostring(name), make_autostring(category), make_autostring(version), make_autostring(author), make_autostring(type), - make_autostring(remote), + make_autostring(remote), make_autostring(date), }; } @@ -708,6 +721,8 @@ string Browser::getValue(const Column col, const Entry &entry) const return pkg ? pkg->displayType() : Package::displayType(regEntry.type); case RemoteColumn: return pkg ? pkg->category()->index()->name() : regEntry.remote; + case TimeColumn: + return ver ? ver->time().toString() : string(); } return {}; // for MSVC diff --git a/src/browser.hpp b/src/browser.hpp @@ -86,6 +86,7 @@ private: AuthorColumn, TypeColumn, RemoteColumn, + TimeColumn, }; enum View { diff --git a/src/listview.cpp b/src/listview.cpp @@ -141,19 +141,22 @@ void ListView::sort() static const auto compare = [](LPARAM aRow, LPARAM bRow, LPARAM param) { ListView *view = reinterpret_cast<ListView *>(param); - const int column = view->m_sort->column; + + int ret; + const auto it = view->m_sortFuncs.find(column); if(it != view->m_sortFuncs.end()) - return it->second((int)aRow, (int)bRow); + ret = it->second((int)aRow, (int)bRow); + else { + auto_string a = view->m_rows[aRow][column]; + boost::algorithm::to_lower(a); - auto_string a = view->m_rows[aRow][column]; - boost::algorithm::to_lower(a); + auto_string b = view->m_rows[bRow][column]; + boost::algorithm::to_lower(b); - auto_string b = view->m_rows[bRow][column]; - boost::algorithm::to_lower(b); - - const int ret = a.compare(b); + ret = a.compare(b); + } switch(view->m_sort->order) { case AscendingOrder: diff --git a/src/report.cpp b/src/report.cpp @@ -61,7 +61,7 @@ void ReportDialog::printVersion(const Version *ver) if(!ver->author().empty()) stream() << " by " << ver->author(); - const string &date = ver->displayTime(); + const string &date = ver->time().toString(); if(!date.empty()) stream() << " – " << date; diff --git a/src/time.cpp b/src/time.cpp @@ -0,0 +1,91 @@ +/* ReaPack: Package manager for REAPER + * Copyright (C) 2015-2016 Christian Fillion + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "time.hpp" + +#include <iomanip> +#include <sstream> + +using namespace std; + +Time::Time(const string &iso8601) : m_tm() +{ + tm time = {}; + + istringstream stream(iso8601); + stream >> std::get_time(&time, "%Y-%m-%dT%H:%M:%S"); + + if(stream.good()) + swap(m_tm, time); +} + +Time::Time(int year, int month, int day, int hour, int minute, int second) + : m_tm() +{ + m_tm.tm_year = year - 1900; + m_tm.tm_mon = month - 1; + m_tm.tm_mday = day; + + m_tm.tm_hour = hour; + m_tm.tm_min = minute; + m_tm.tm_sec = second; +} + +string Time::toString() const +{ + if(!isValid()) + return {}; + + char buf[32] = {}; + strftime(buf, sizeof(buf), "%B %d %Y", &m_tm); + return buf; +} + +int Time::compare(const Time &o) const +{ + if(year() > o.year()) + return 1; + else if(year() < o.year()) + return -1; + + if(month() > o.month()) + return 1; + else if(month() < o.month()) + return -1; + + if(day() > o.day()) + return 1; + else if(day() < o.day()) + return -1; + + if(hour() > o.hour()) + return 1; + else if(hour() < o.hour()) + return -1; + + if(minute() > o.minute()) + return 1; + else if(minute() < o.minute()) + return -1; + + if(second() > o.second()) + return 1; + else if(second() < o.second()) + return -1; + + return 0; +} diff --git a/src/time.hpp b/src/time.hpp @@ -0,0 +1,54 @@ +/* ReaPack: Package manager for REAPER + * Copyright (C) 2015-2016 Christian Fillion + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef REAPACK_TIME_HPP +#define REAPACK_TIME_HPP + +#include <ctime> +#include <string> + +class Time { +public: + Time(const std::string &); + Time(int year, int month, int day, int hour = 0, int minute = 0, int second = 0); + Time(const std::tm &tm = {}) : m_tm(tm) {} + + bool isValid() const { return m_tm.tm_year > 0; } + operator bool() const { return isValid(); } + + int year() const { return m_tm.tm_year + 1900; } + int month() const { return m_tm.tm_mon + 1; } + int day() const { return m_tm.tm_mday; } + int hour() const { return m_tm.tm_hour; } + int minute() const { return m_tm.tm_min; } + int second() const { return m_tm.tm_sec; } + + std::string toString() const; + + int compare(const Time &) const; + bool operator<(const Time &o) const { return compare(o) < 0; } + bool operator<=(const Time &o) const { return compare(o) <= 0; } + bool operator>(const Time &o) const { return compare(o) > 0; } + bool operator>=(const Time &o) const { return compare(o) >= 0; } + bool operator==(const Time &o) const { return compare(o) == 0; } + bool operator!=(const Time &o) const { return compare(o) != 0; } + +private: + std::tm m_tm; +}; + +#endif diff --git a/src/version.cpp b/src/version.cpp @@ -23,7 +23,6 @@ #include <boost/lexical_cast.hpp> #include <cctype> -#include <iomanip> #include <regex> using namespace std; @@ -138,23 +137,10 @@ void Version::setChangelog(const string &changelog) void Version::setTime(const char *iso8601) { - tm time = {}; + const Time time(iso8601); - istringstream stream(iso8601); - stream >> std::get_time(&time, "%Y-%m-%d"); - - if(stream.good()) - swap(m_time, time); -} - -string Version::displayTime() const -{ - if(m_time.tm_year == 0) - return {}; - - char buf[32] = {}; - strftime(buf, sizeof(buf), "%B %d %Y", &m_time); - return buf; + if(time) + m_time = time; } const Source *Version::source(const size_t index) const diff --git a/src/version.hpp b/src/version.hpp @@ -20,12 +20,13 @@ #include <boost/variant.hpp> #include <cstdint> -#include <ctime> #include <map> #include <set> #include <string> #include <vector> +#include "time.hpp" + class Package; class Source; class Path; @@ -55,8 +56,7 @@ public: std::string displayAuthor() const; void setTime(const char *iso8601); - const std::tm &time() const { return m_time; } - std::string displayTime() const; + const Time &time() const { return m_time; } void setChangelog(const std::string &); const std::string &changelog() const { return m_changelog; } @@ -88,7 +88,7 @@ private: std::string m_author; std::string m_changelog; - std::tm m_time; + Time m_time; const Package *m_package; SourceList m_mainSources; diff --git a/test/helper/io.cpp b/test/helper/io.cpp @@ -23,6 +23,12 @@ ostream &operator<<(ostream &os, const set<Path> &list) return os; } +ostream &operator<<(ostream &os, const Time &time) +{ + os << time.toString(); + return os; +} + ostream &operator<<(ostream &os, const Version &ver) { os << ver.name(); diff --git a/test/helper/io.hpp b/test/helper/io.hpp @@ -5,10 +5,12 @@ #include <set> class Path; +class Time; class Version; std::ostream &operator<<(std::ostream &, const Path &); std::ostream &operator<<(std::ostream &, const std::set<Path> &); +std::ostream &operator<<(std::ostream &, const Time &); std::ostream &operator<<(std::ostream &, const Version &); #endif diff --git a/test/index_v1.cpp b/test/index_v1.cpp @@ -84,10 +84,10 @@ TEST_CASE("read version time", M) { IndexPtr ri = Index::load("time"); CHECK(ri->packages().size() == 1); - const tm &time = ri->category(0)->package(0)->version(0)->time(); - REQUIRE(time.tm_year == 2016 - 1900); - REQUIRE(time.tm_mon == 2 - 1); - REQUIRE(time.tm_mday == 12); + const Time &time = ri->category(0)->package(0)->version(0)->time(); + REQUIRE(time.year() == 2016); + REQUIRE(time.month() == 2); + REQUIRE(time.day() == 12); } TEST_CASE("invalid version tag", M) { diff --git a/test/time.cpp b/test/time.cpp @@ -0,0 +1,80 @@ +#include <catch.hpp> + +#include "helper/io.hpp" + +#include <time.hpp> + +using namespace std; + +static const char *M = "[time]"; + +TEST_CASE("valid time", M) { + const Time time("2016-02-12T01:16:40Z"); + REQUIRE(time.year() == 2016); + REQUIRE(time.month() == 2); + REQUIRE(time.day() == 12); + REQUIRE(time.hour() == 1); + REQUIRE(time.minute() == 16); + REQUIRE(time.second() == 40); + REQUIRE(time == Time(2016, 2, 12, 1, 16, 40)); + REQUIRE(time.isValid()); + REQUIRE(time); +} + +TEST_CASE("garbage time string", M) { + const Time time("hello world"); + REQUIRE_FALSE(time.isValid()); + REQUIRE_FALSE(time); + REQUIRE(time == Time()); + REQUIRE(time.toString() == string()); +} + +TEST_CASE("out of range time string", M) { + const Time time("2016-99-99T99:99:99Z"); + REQUIRE_FALSE(time.isValid()); + REQUIRE_FALSE(time); + REQUIRE(time == Time()); + REQUIRE(time.toString() == string()); +} + +TEST_CASE("compare times", M) { + SECTION("equality") { + REQUIRE(Time(2016,1,2,3,4,5).compare(Time(2016,1,2,3,4,5)) == 0); + + REQUIRE(Time(2016,1,2,3,4,5) == Time(2016,1,2,3,4,5)); + REQUIRE_FALSE(Time(2016,1,2,3,4,5) == Time(2016,1,2,3,4)); + } + + SECTION("inequality") { + REQUIRE_FALSE(Time(2016,1,2,3,4,5) != Time(2016,1,2,3,4,5)); + REQUIRE(Time(2016,1,2,3,4,5) != Time(2017,5,4,3,2,1)); + } + + SECTION("less than") { + REQUIRE(Time(2015, 2, 3).compare(Time(2016, 2, 3)) == -1); + + REQUIRE(Time(2015, 2, 3) < Time(2016, 2, 3)); + REQUIRE_FALSE(Time(2016, 2, 3) < Time(2016, 2, 3)); + REQUIRE_FALSE(Time(2016, 2, 1) < Time(2015, 2, 2)); + } + + SECTION("less than or equal") { + REQUIRE(Time(2015, 2, 3) <= Time(2016, 2, 3)); + REQUIRE(Time(2016, 2, 3) <= Time(2016, 2, 3)); + REQUIRE_FALSE(Time(2016, 2, 1) <= Time(2015, 2, 2)); + } + + SECTION("greater than") { + REQUIRE(Time(2016, 2, 3).compare(Time(2015, 2, 3)) == 1); + + REQUIRE_FALSE(Time(2015, 2, 30) > Time(2016, 2, 3)); + REQUIRE_FALSE(Time(2016, 2, 3) > Time(2016, 2, 3)); + REQUIRE(Time(2016, 2, 3) > Time(2015, 2, 3)); + } + + SECTION("greater than or equal") { + REQUIRE_FALSE(Time(2015, 2, 30) >= Time(2016, 2, 3)); + REQUIRE(Time(2016, 2, 3) >= Time(2016, 2, 3)); + REQUIRE(Time(2016, 2, 3) >= Time(2015, 2, 3)); + } +} diff --git a/test/version.cpp b/test/version.cpp @@ -23,7 +23,7 @@ TEST_CASE("construct null version", M) { REQUIRE(ver.size() == 0); REQUIRE(ver.isStable()); - REQUIRE(ver.displayTime().empty()); + REQUIRE_FALSE(ver.time().isValid()); REQUIRE(ver.package() == nullptr); REQUIRE(ver.mainSources().empty()); } @@ -317,29 +317,12 @@ TEST_CASE("version author", M) { TEST_CASE("version date", M) { Version ver("1.0"); - CHECK(ver.time().tm_year == 0); - CHECK(ver.time().tm_mon == 0); - CHECK(ver.time().tm_mday == 0); - CHECK(ver.displayTime() == ""); - SECTION("valid") { - ver.setTime("2016-02-12T01:16:40Z"); - REQUIRE(ver.time().tm_year == 2016 - 1900); - REQUIRE(ver.time().tm_mon == 2 - 1); - REQUIRE(ver.time().tm_mday == 12); - REQUIRE(ver.displayTime() != ""); - } + ver.setTime("2016-02-12T01:16:40Z"); + REQUIRE(ver.time().year() == 2016); - SECTION("garbage") { - ver.setTime("hello world"); - REQUIRE(ver.time().tm_year == 0); - REQUIRE(ver.displayTime() == ""); - } - - SECTION("out of range") { - ver.setTime("2016-99-99T99:99:99Z"); - REQUIRE(ver.displayTime() == ""); - } + ver.setTime("hello world"); + REQUIRE(ver.time().year() == 2016); } TEST_CASE("copy version constructor", M) { @@ -356,7 +339,7 @@ TEST_CASE("copy version constructor", M) { REQUIRE(copy1.isStable() == original.isStable()); REQUIRE(copy1.author() == original.author()); REQUIRE(copy1.changelog() == original.changelog()); - REQUIRE(copy1.displayTime() == original.displayTime()); + REQUIRE(copy1.time() == original.time()); REQUIRE(copy1.package() == nullptr); REQUIRE(copy1.mainSources().empty()); REQUIRE(copy1.sources().empty());