reapack

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

commit 36391c18a123db9b867d038a937f5fceb202bb5b
parent 43c2732e960d23e4d1c7107f8254de74bc16d919
Author: cfillion <cfillion@users.noreply.github.com>
Date:   Sat, 26 Aug 2017 17:10:12 -0400

browser: split Browser::Entry (big refactoring)

Diffstat:
Msrc/browser.cpp | 278+++++--------------------------------------------------------------------------
Msrc/browser.hpp | 66+++++++++++++++++++-----------------------------------------------
Asrc/browser_entry.cpp | 260+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/browser_entry.hpp | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 376 insertions(+), 308 deletions(-)

diff --git a/src/browser.cpp b/src/browser.cpp @@ -18,36 +18,19 @@ #include "browser.hpp" #include "about.hpp" +#include "browser_entry.hpp" #include "config.hpp" #include "encoding.hpp" #include "errors.hpp" #include "index.hpp" +#include "listview.hpp" #include "menu.hpp" #include "reapack.hpp" #include "resource.hpp" #include "transaction.hpp" -#include <boost/range/adaptor/reversed.hpp> - using namespace std; -enum Action { - ACTION_VERSION = 80, - ACTION_FILTERTYPE, - ACTION_LATEST = 300, - ACTION_LATEST_ALL, - ACTION_REINSTALL, - ACTION_REINSTALL_ALL, - ACTION_UNINSTALL, - ACTION_UNINSTALL_ALL, - ACTION_PIN, - ACTION_ABOUT_PKG, - ACTION_ABOUT_REMOTE, - ACTION_RESET_ALL, - ACTION_REFRESH, - ACTION_MANAGE, -}; - enum Timers { TIMER_FILTER = 1, TIMER_ABOUT }; Browser::Browser() @@ -228,7 +211,7 @@ bool Browser::onKeyDown(const int key, const int mods) vector<string> values; for(const int index : m_list->selection(false)) - values.push_back(getValue(NameColumn, *getEntry(index))); + values.push_back(getEntry(index)->displayName()); setClipboard(values); } @@ -285,94 +268,11 @@ void Browser::fillMenu(Menu &menu) if(entry) { Menu pkgMenu = menu.addMenu(AUTO_STR("Package under cursor")); - fillPackageMenu(entry, pkgMenu); + entry->fillMenu(pkgMenu); } } else if(entry) - fillPackageMenu(entry, menu); -} - -void Browser::fillPackageMenu(const Entry *entry, Menu &menu) -{ - if(entry->test(InstalledFlag)) { - if(entry->test(OutOfDateFlag)) { - auto_char installLabel[32]; - auto_snprintf(installLabel, auto_size(installLabel), - AUTO_STR("U&pdate to v%s"), - make_autostring(entry->latest->name().toString()).c_str()); - - const UINT actionIndex = menu.addAction(installLabel, ACTION_LATEST); - if(entry->target && *entry->target == entry->latest) - menu.check(actionIndex); - } - - auto_char reinstallLabel[32]; - auto_snprintf(reinstallLabel, auto_size(reinstallLabel), - AUTO_STR("&Reinstall v%s"), - make_autostring(entry->regEntry.version.toString()).c_str()); - - const UINT actionIndex = menu.addAction(reinstallLabel, ACTION_REINSTALL); - if(!entry->current || entry->test(ObsoleteFlag)) - menu.disable(actionIndex); - else if(entry->target && *entry->target == entry->current) - menu.check(actionIndex); - } - else { - auto_char installLabel[32]; - auto_snprintf(installLabel, auto_size(installLabel), - AUTO_STR("&Install v%s"), - make_autostring(entry->latest->name().toString()).c_str()); - - const UINT actionIndex = menu.addAction(installLabel, ACTION_LATEST); - if(entry->target && *entry->target == entry->latest) - menu.check(actionIndex); - } - - Menu versionMenu = menu.addMenu(AUTO_STR("Versions")); - const UINT versionMenuIndex = menu.size() - 1; - if(entry->test(ObsoleteFlag)) - menu.disable(versionMenuIndex); - else { - const auto &versions = entry->package->versions(); - int verIndex = (int)versions.size(); - for(const Version *ver : versions | boost::adaptors::reversed) { - const UINT actionIndex = versionMenu.addAction( - make_autostring(ver->name().toString()).c_str(), - --verIndex | (ACTION_VERSION << 8)); - - if(entry->target ? *entry->target == ver : ver == entry->current) { - if(entry->target && ver != entry->latest) - menu.check(versionMenuIndex); - - versionMenu.checkRadio(actionIndex); - } - } - } - - const UINT pinIndex = menu.addAction( - AUTO_STR("&Pin current version"), ACTION_PIN); - if(!entry->canPin()) - menu.disable(pinIndex); - if(entry->pin.value_or(entry->regEntry.pinned)) - menu.check(pinIndex); - - const UINT uninstallIndex = - menu.addAction(AUTO_STR("&Uninstall"), ACTION_UNINSTALL); - if(!entry->test(InstalledFlag) || getRemote(*entry).isProtected()) - menu.disable(uninstallIndex); - else if(entry->target && *entry->target == nullptr) - menu.check(uninstallIndex); - - menu.addSeparator(); - - menu.setEnabled(!entry->test(ObsoleteFlag), - menu.addAction(AUTO_STR("About this &package"), ACTION_ABOUT_PKG)); - - auto_char aboutLabel[64]; - const auto_string &name = make_autostring(getValue(RemoteColumn, *entry)); - auto_snprintf(aboutLabel, auto_size(aboutLabel), - AUTO_STR("&About %s..."), name.c_str()); - menu.addAction(aboutLabel, ACTION_ABOUT_REMOTE); + entry->fillMenu(menu); } void Browser::updateDisplayLabel() @@ -552,12 +452,12 @@ void Browser::populate(const vector<IndexPtr> &indexes) for(const IndexPtr &index : indexes) { for(const Package *pkg : index->packages()) - m_entries.push_back(makeEntry(pkg, reg.getEntry(pkg), index)); + m_entries.push_back({pkg, reg.getEntry(pkg), index}); // obsolete packages for(const Registry::Entry &regEntry : reg.getEntries(index->name())) { if(!index->find(regEntry.category, regEntry.package)) - m_entries.push_back({InstalledFlag | ObsoleteFlag, regEntry, index}); + m_entries.push_back({regEntry, index}); } } @@ -611,35 +511,6 @@ void Browser::transferActions() disable(m_applyBtn); } -auto Browser::makeEntry(const Package *pkg, - const Registry::Entry &regEntry, const IndexPtr &index) - const -> Entry -{ - const auto &instOpts = g_reapack->config()->install; - const Version *latest = pkg->lastVersion(instOpts.bleedingEdge, regEntry.version); - const Version *current = nullptr; - - int flags = 0; - - if(regEntry) { - flags |= InstalledFlag; - - if(latest && regEntry.version < latest->name()) - flags |= OutOfDateFlag; - - current = pkg->findVersion(regEntry.version); - } - else - flags |= UninstalledFlag; - - // Show latest pre-release if no stable version is available, - // or the newest available version if older than current installed version. - if(!latest) - latest = pkg->lastVersion(true); - - return {flags, regEntry, index, pkg, latest, current}; -} - void Browser::fillList() { InhibitControl freeze(m_list); @@ -660,7 +531,7 @@ void Browser::fillList() const auto &matchingEntryIt = find_if(oldSelection.begin(), oldSelection.end(), [&entry] (const Entry *oldEntry) { return *oldEntry == entry; }); - const int index = m_list->addRow(makeRow(entry)); + const int index = m_list->addRow(entry.makeRow()); if(matchingEntryIt != oldSelection.end()) m_list->select(index); @@ -672,93 +543,6 @@ void Browser::fillList() updateDisplayLabel(); } -ListView::Row Browser::makeRow(const Entry &entry) const -{ - const string &state = getValue(StateColumn, entry); - const string &name = getValue(NameColumn, entry); - const string &category = getValue(CategoryColumn, entry); - const string &version = getValue(VersionColumn, entry); - const string &author = getValue(AuthorColumn, entry); - const string &type = getValue(TypeColumn, entry); - const string &remote = getValue(RemoteColumn, entry); - const string &date = getValue(TimeColumn, entry); - - ListView::Row row{ - make_autostring(state), make_autostring(name), make_autostring(category), - make_autostring(version), make_autostring(author), make_autostring(type), - make_autostring(remote), make_autostring(date), - }; - row.userData = (void *)&entry; - return row; -} - -string Browser::getValue(const Column col, const Entry &entry) const -{ - const Package *pkg = entry.package; - const Version *ver = entry.latest; - const Registry::Entry &regEntry = entry.regEntry; - - string display; - - switch(col) { - case StateColumn: { - if(entry.test(ObsoleteFlag)) - display += 'o'; - else if(entry.test(OutOfDateFlag)) - display += 'u'; - else if(entry.test(InstalledFlag)) - display += 'i'; - else - display += '\x20'; - - if(entry.regEntry.pinned) - display += 'p'; - - if(entry.target) - display += *entry.target == nullptr ? 'R' : 'I'; - if(entry.pin && entry.canPin()) - display += 'P'; - - return display; - } - case NameColumn: { - if(pkg) - return pkg->displayName(); - else - return Package::displayName(regEntry.package, regEntry.description); - } - case CategoryColumn: - return entry.categoryName(); - case VersionColumn: - if(entry.test(InstalledFlag)) - display = regEntry.version.toString(); - - if(ver && (!regEntry || ver->name() > regEntry.version)) { - if(!display.empty()) - display += '\x20'; - - display += '(' + ver->name().toString() + ')'; - } - - return display; - case AuthorColumn: - return ver ? ver->displayAuthor() : Version::displayAuthor(regEntry.author); - case TypeColumn: - return pkg ? pkg->displayType() : Package::displayType(regEntry.type); - case RemoteColumn: - return entry.indexName(); - case TimeColumn: - return ver ? ver->time().toString() : string(); - } - - return {}; // for MSVC -} - -Remote Browser::getRemote(const Entry &entry) const -{ - return g_reapack->remote(getValue(RemoteColumn, entry)); -} - bool Browser::match(const Entry &entry) const { switch(currentView()) { @@ -769,35 +553,28 @@ bool Browser::match(const Entry &entry) const return false; break; case InstalledView: - if(!entry.test(InstalledFlag)) + if(!entry.test(Entry::InstalledFlag)) return false; break; case OutOfDateView: - if(!entry.test(OutOfDateFlag)) + if(!entry.test(Entry::OutOfDateFlag)) return false; break; case UninstalledView: - if(!entry.test(UninstalledFlag)) + if(!entry.test(Entry::UninstalledFlag)) return false; break; case ObsoleteView: - if(!entry.test(ObsoleteFlag)) + if(!entry.test(Entry::ObsoleteFlag)) return false; break; } - const Package::Type type = - entry.latest ? entry.package->type() : entry.regEntry.type; - - if(isFiltered(type)) + if(isFiltered(entry.type())) return false; - const string &name = getValue(NameColumn, entry); - const string &category = getValue(CategoryColumn, entry); - const string &author = getValue(AuthorColumn, entry); - const string &remote = getValue(RemoteColumn, entry); - - return m_filter.match({name, category, author, remote}); + return m_filter.match({entry.displayName(), entry.categoryName(), + entry.displayAuthor(), entry.indexName()}); } auto Browser::getEntry(const int index) -> Entry * @@ -890,7 +667,7 @@ void Browser::uninstall(const int index, const bool toggle) { const Entry *entry = getEntry(index); - if(entry && entry->test(InstalledFlag) && !getRemote(*entry).isProtected()) + if(entry && entry->test(Entry::InstalledFlag) && !entry->remote().isProtected()) setTarget(index, nullptr, toggle); } @@ -968,7 +745,7 @@ void Browser::updateAction(const int index) updateDisplayLabel(); } else { - m_list->replaceRow(index, makeRow(*entry)); + m_list->replaceRow(index, entry->makeRow()); m_list->sort(); // TODO: only re-sort if sorted by status column } @@ -1059,24 +836,3 @@ bool Browser::apply() return true; } - -const string &Browser::Entry::indexName() const -{ - return package ? package->category()->index()->name() : regEntry.remote; -} - -const string &Browser::Entry::categoryName() const -{ - return package ? package->category()->name() : regEntry.category; -} - -const string &Browser::Entry::packageName() const -{ - return package ? package->name() : regEntry.package; -} - -bool Browser::Entry::operator==(const Entry &o) const -{ - return indexName() == o.indexName() && categoryName() == o.categoryName() && - packageName() == o.packageName(); -} diff --git a/src/browser.hpp b/src/browser.hpp @@ -21,13 +21,11 @@ #include "dialog.hpp" #include "filter.hpp" -#include "listview.hpp" -#include "registry.hpp" +#include "package.hpp" #include <boost/optional.hpp> #include <functional> #include <list> -#include <map> #include <memory> #include <string> #include <vector> @@ -35,13 +33,29 @@ class Index; class ListView; class Menu; -class Remote; class Version; typedef std::shared_ptr<const Index> IndexPtr; class Browser : public Dialog { public: + enum Action { + ACTION_VERSION = 80, + ACTION_FILTERTYPE, + ACTION_LATEST = 300, + ACTION_LATEST_ALL, + ACTION_REINSTALL, + ACTION_REINSTALL_ALL, + ACTION_UNINSTALL, + ACTION_UNINSTALL_ALL, + ACTION_PIN, + ACTION_ABOUT_PKG, + ACTION_ABOUT_REMOTE, + ACTION_RESET_ALL, + ACTION_REFRESH, + ACTION_MANAGE, + }; + Browser(); void refresh(bool stale = false); void setFilter(const std::string &); @@ -54,43 +68,7 @@ protected: void onClose() override; private: - enum Flag { - UninstalledFlag = 1<<0, - InstalledFlag = 1<<1, - OutOfDateFlag = 1<<2, - ObsoleteFlag = 1<<3, - }; - - struct Entry { - int flags; - Registry::Entry regEntry; - IndexPtr index; - const Package *package; - const Version *latest; - const Version *current; - - const std::string &indexName() const; - const std::string &categoryName() const; - const std::string &packageName() const; - - boost::optional<const Version *> target; - boost::optional<bool> pin; - - bool test(Flag f) const { return (flags & f) != 0; } - bool canPin() const { return target ? *target != nullptr : test(InstalledFlag); } - bool operator==(const Entry &o) const; - }; - - enum Column { - StateColumn, - NameColumn, - CategoryColumn, - VersionColumn, - AuthorColumn, - TypeColumn, - RemoteColumn, - TimeColumn, - }; + class Entry; // browser_entry.hpp enum View { AllView, @@ -108,8 +86,6 @@ private: Done, }; - Entry makeEntry(const Package *, const Registry::Entry &, const IndexPtr &) const; - void onSelection(); bool fillContextMenu(Menu &, int index); void populate(const std::vector<IndexPtr> &); @@ -118,15 +94,11 @@ private: void updateFilter(); void updateAbout(); void fillList(); - std::string getValue(Column, const Entry &entry) const; - ListView::Row makeRow(const Entry &) const; Entry *getEntry(int); - Remote getRemote(const Entry &) const; void updateDisplayLabel(); void displayButton(); void actionsButton(); void fillMenu(Menu &); - void fillPackageMenu(const Entry *, Menu &); bool isFiltered(Package::Type) const; bool hasAction(const Entry *) const; void setTarget(const int index, const Version *, bool toggle = true); diff --git a/src/browser_entry.cpp b/src/browser_entry.cpp @@ -0,0 +1,260 @@ +/* ReaPack: Package manager for REAPER + * Copyright (C) 2015-2017 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 "browser_entry.hpp" + +#include "config.hpp" +#include "index.hpp" +#include "menu.hpp" +#include "reapack.hpp" + +#include <boost/range/adaptor/reversed.hpp> + +using namespace std; + +Browser::Entry::Entry(const Package *pkg, const Registry::Entry &re, const IndexPtr &i) + : m_flags(0), regEntry(re), package(pkg), index(i), current(nullptr) +{ + const auto &instOpts = g_reapack->config()->install; + latest = pkg->lastVersion(instOpts.bleedingEdge, regEntry.version); + + if(regEntry) { + m_flags |= InstalledFlag; + + if(latest && regEntry.version < latest->name()) + m_flags |= OutOfDateFlag; + + current = pkg->findVersion(regEntry.version); + } + else + m_flags |= UninstalledFlag; + + // Show latest pre-release if no stable version is available, + // or the newest available version if older than current installed version. + if(!latest) + latest = pkg->lastVersion(true); +} + +Browser::Entry::Entry(const Registry::Entry &re, const IndexPtr &i) + : m_flags(InstalledFlag | ObsoleteFlag), regEntry(re), package(nullptr), + index(i), current(nullptr), latest(nullptr) +{} + +string Browser::Entry::displayState() const +{ + string state; + + if(test(ObsoleteFlag)) + state += 'o'; + else if(test(OutOfDateFlag)) + state += 'u'; + else if(test(InstalledFlag)) + state += 'i'; + else + state += '\x20'; + + if(regEntry.pinned) + state += 'p'; + + if(target) + state += *target == nullptr ? 'R' : 'I'; + if(pin && canPin()) + state += 'P'; + + return state; +} + +const string &Browser::Entry::indexName() const +{ + return package ? package->category()->index()->name() : regEntry.remote; +} + +const string &Browser::Entry::categoryName() const +{ + return package ? package->category()->name() : regEntry.category; +} + +const string &Browser::Entry::packageName() const +{ + return package ? package->name() : regEntry.package; +} + +string Browser::Entry::displayName() const +{ + if(package) + return package->displayName(); + else + return Package::displayName(regEntry.package, regEntry.description); +} + +Package::Type Browser::Entry::type() const +{ + return latest ? package->type() : regEntry.type; +} + +string Browser::Entry::displayType() const +{ + return package ? package->displayType() : Package::displayType(regEntry.type); +} + +string Browser::Entry::displayVersion() const +{ + string display; + + if(test(InstalledFlag)) + display = regEntry.version.toString(); + + if(latest && (!regEntry || latest->name() > regEntry.version)) { + if(!display.empty()) + display += '\x20'; + + display += '(' + latest->name().toString() + ')'; + } + + return display; +} + +const VersionName *Browser::Entry::sortVersion() const +{ + if(test(InstalledFlag)) + return &regEntry.version; + else + return &latest->name(); +} + +string Browser::Entry::displayAuthor() const +{ + return latest ? latest->displayAuthor() : Version::displayAuthor(regEntry.author); +} + +const Time *Browser::Entry::lastUpdate() const +{ + return latest ? &latest->time() : nullptr; +} + +Remote Browser::Entry::remote() const +{ + return g_reapack->remote(indexName()); +} + +ListView::Row Browser::Entry::makeRow() const +{ + const Time *time = lastUpdate(); + + ListView::Row row; + row.userData = (void *)this; + row.push_back(make_autostring(displayState())); + row.push_back(make_autostring(displayName())); + row.push_back(make_autostring(categoryName())); + row.push_back({make_autostring(displayVersion()), (void *)sortVersion()}); + row.push_back(make_autostring(displayAuthor())); + row.push_back(make_autostring(displayType())); + row.push_back(make_autostring(indexName())); + row.push_back({time ? make_autostring(time->toString()) : auto_string(), + (void *)time}); + + return row; +} + +void Browser::Entry::fillMenu(Menu &menu) const +{ + if(test(InstalledFlag)) { + if(test(OutOfDateFlag)) { + auto_char installLabel[32]; + auto_snprintf(installLabel, auto_size(installLabel), + AUTO_STR("U&pdate to v%s"), + make_autostring(latest->name().toString()).c_str()); + + const UINT actionIndex = menu.addAction(installLabel, ACTION_LATEST); + if(target && *target == latest) + menu.check(actionIndex); + } + + auto_char reinstallLabel[32]; + auto_snprintf(reinstallLabel, auto_size(reinstallLabel), + AUTO_STR("&Reinstall v%s"), + make_autostring(regEntry.version.toString()).c_str()); + + const UINT actionIndex = menu.addAction(reinstallLabel, ACTION_REINSTALL); + if(!current || test(ObsoleteFlag)) + menu.disable(actionIndex); + else if(target && *target == current) + menu.check(actionIndex); + } + else { + auto_char installLabel[32]; + auto_snprintf(installLabel, auto_size(installLabel), + AUTO_STR("&Install v%s"), + make_autostring(latest->name().toString()).c_str()); + + const UINT actionIndex = menu.addAction(installLabel, ACTION_LATEST); + if(target && *target == latest) + menu.check(actionIndex); + } + + Menu versionMenu = menu.addMenu(AUTO_STR("Versions")); + const UINT versionMenuIndex = menu.size() - 1; + if(test(ObsoleteFlag)) + menu.disable(versionMenuIndex); + else { + const auto &versions = package->versions(); + int verIndex = (int)versions.size(); + for(const Version *ver : versions | boost::adaptors::reversed) { + const UINT actionIndex = versionMenu.addAction( + make_autostring(ver->name().toString()).c_str(), + --verIndex | (ACTION_VERSION << 8)); + + if(target ? *target == ver : ver == current) { + if(target && ver != latest) + menu.check(versionMenuIndex); + + versionMenu.checkRadio(actionIndex); + } + } + } + + const UINT pinIndex = menu.addAction( + AUTO_STR("&Pin current version"), ACTION_PIN); + if(!canPin()) + menu.disable(pinIndex); + if(pin.value_or(regEntry.pinned)) + menu.check(pinIndex); + + const UINT uninstallIndex = + menu.addAction(AUTO_STR("&Uninstall"), ACTION_UNINSTALL); + if(!test(InstalledFlag) || remote().isProtected()) + menu.disable(uninstallIndex); + else if(target && *target == nullptr) + menu.check(uninstallIndex); + + menu.addSeparator(); + + menu.setEnabled(!test(ObsoleteFlag), + menu.addAction(AUTO_STR("About this &package"), ACTION_ABOUT_PKG)); + + auto_char aboutLabel[64]; + const auto_string &name = make_autostring(indexName()); + auto_snprintf(aboutLabel, auto_size(aboutLabel), + AUTO_STR("&About %s..."), name.c_str()); + menu.addAction(aboutLabel, ACTION_ABOUT_REMOTE); +} + +bool Browser::Entry::operator==(const Entry &o) const +{ + return indexName() == o.indexName() && categoryName() == o.categoryName() && + packageName() == o.packageName(); +} diff --git a/src/browser_entry.hpp b/src/browser_entry.hpp @@ -0,0 +1,80 @@ +/* ReaPack: Package manager for REAPER + * Copyright (C) 2015-2017 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_BROWSER_ENTRY_HPP +#define REAPACK_BROWSER_ENTRY_HPP + +#include "browser.hpp" +#include "listview.hpp" +#include "registry.hpp" + +#include <boost/optional.hpp> +#include <memory> + +class Index; +class Menu; +class Remote; + +typedef std::shared_ptr<const Index> IndexPtr; + +class Browser::Entry { +public: + enum Flag { + UninstalledFlag = 1<<0, + InstalledFlag = 1<<1, + OutOfDateFlag = 1<<2, + ObsoleteFlag = 1<<3, + }; + + Entry(const Package *, const Registry::Entry &, const IndexPtr &); + Entry(const Registry::Entry &, const IndexPtr &); + + boost::optional<const Version *> target; + boost::optional<bool> pin; + + std::string displayState() const; + const std::string &indexName() const; + const std::string &categoryName() const; + const std::string &packageName() const; + std::string displayName() const; + Package::Type type() const; + std::string displayType() const; + std::string displayVersion() const; + const VersionName *sortVersion() const; + std::string displayAuthor() const; + const Time *lastUpdate() const; + + Remote remote() const; + ListView::Row makeRow() const; + void fillMenu(Menu &) const; + + bool test(Flag f) const { return (m_flags & f) != 0; } + bool canPin() const { return target ? *target != nullptr : test(InstalledFlag); } + bool operator==(const Entry &o) const; + +private: + int m_flags; + +public: + Registry::Entry regEntry; + const Package *package; + IndexPtr index; + const Version *current; + const Version *latest; +}; + +#endif