hrev45959 adds 7 changesets to branch 'master' old head: 3785b9b45973c6bfa4d88898ed8265e5e5114e11 new head: 3a6ccc85790389640be1c6b3a7046186f5f34a66 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=3a6ccc8+%5E3785b9b ---------------------------------------------------------------------------- f75ec10: HaikuDepot: Added the notion of package categories * Defined PackageCategory class (icon, label and internal name) * Each PackageInfo has a list of PackageCategories * Model defines global PackageCategories, referenced by PackageInfos * Added Model.cpp to files needing translation * Added categories to dummy package infos 633ed4c: HaikuDepot: Make categories also accessible as List in Model 4abd2b7: HaikuDepot: Beginnings of supporting filters... ... to reduce the package list. No filters can be defined via the UI, but a DepotFilter is already implemented, although its performance will probably need to improve. 4247995: HaikuDepot: Implemented filtering by category 2c3e4ea: HaikuDepot: List.h: added IndexOf(), Contains() and Remove() * All of those take const ItemType& as argument. 706edd8: HaikuDepot: PackageInfoList -> PackageList, added PackageState enum * Model has SetPackageState(). It adds or removes a PackageInfo to/from three internal lists, installed, activated and uninstalled packages. 3a6ccc8: HaikuDepot: Fleshed out the code to support the virtual categories [ Stephan Aßmus <superstippi@xxxxxx> ] ---------------------------------------------------------------------------- 10 files changed, 533 insertions(+), 53 deletions(-) src/apps/haiku-depot/FilterView.cpp | 57 ++++--- src/apps/haiku-depot/FilterView.h | 10 +- src/apps/haiku-depot/Jamfile | 1 + src/apps/haiku-depot/List.h | 20 +++ src/apps/haiku-depot/MainWindow.cpp | 22 ++- src/apps/haiku-depot/MainWindow.h | 2 +- src/apps/haiku-depot/Model.cpp | 258 ++++++++++++++++++++++++++++++- src/apps/haiku-depot/Model.h | 70 ++++++++- src/apps/haiku-depot/PackageInfo.cpp | 85 +++++++++- src/apps/haiku-depot/PackageInfo.h | 61 ++++++-- ############################################################################ Commit: f75ec10dc6be224f669e626e50e2aea44a28dd15 URL: http://cgit.haiku-os.org/haiku/commit/?id=f75ec10 Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Aug 10 14:30:30 2013 UTC HaikuDepot: Added the notion of package categories * Defined PackageCategory class (icon, label and internal name) * Each PackageInfo has a list of PackageCategories * Model defines global PackageCategories, referenced by PackageInfos * Added Model.cpp to files needing translation * Added categories to dummy package infos ---------------------------------------------------------------------------- diff --git a/src/apps/haiku-depot/Jamfile b/src/apps/haiku-depot/Jamfile index b0e0217..97499e2 100644 --- a/src/apps/haiku-depot/Jamfile +++ b/src/apps/haiku-depot/Jamfile @@ -24,6 +24,7 @@ DoCatalogs HaikuDepot : App.cpp FilterView.cpp MainWindow.cpp + Model.cpp PackageInfoView.cpp PackageListView.cpp PackageManager.cpp diff --git a/src/apps/haiku-depot/MainWindow.cpp b/src/apps/haiku-depot/MainWindow.cpp index 0071cd6..563694c 100644 --- a/src/apps/haiku-depot/MainWindow.cpp +++ b/src/apps/haiku-depot/MainWindow.cpp @@ -175,6 +175,8 @@ MainWindow::_InitDummyModel() ); wonderbrush.AddScreenshot( BitmapRef(new SharedBitmap(603), true)); + wonderbrush.AddCategory(fModel.CategoryGraphics()); + wonderbrush.AddCategory(fModel.CategoryProductivity()); depot.AddPackage(wonderbrush); @@ -210,6 +212,8 @@ MainWindow::_InitDummyModel() ); paladin.AddScreenshot( BitmapRef(new SharedBitmap(604), true)); + paladin.AddCategory(fModel.CategoryDevelopment()); + depot.AddPackage(paladin); fModel.AddDepot(depot); diff --git a/src/apps/haiku-depot/Model.cpp b/src/apps/haiku-depot/Model.cpp index 78c7c2d..74c5365 100644 --- a/src/apps/haiku-depot/Model.cpp +++ b/src/apps/haiku-depot/Model.cpp @@ -7,11 +7,36 @@ #include <stdio.h> +#include <Catalog.h> + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "Model" + Model::Model() : fSearchTerms(), - fDepots() + fDepots(), + + fCategoryAudio(new PackageCategory( + BitmapRef(), + B_TRANSLATE("Audio"), "audio"), true), + fCategoryVideo(new PackageCategory( + BitmapRef(), + B_TRANSLATE("Video"), "video"), true), + fCategoryGraphics(new PackageCategory( + BitmapRef(), + B_TRANSLATE("Graphics"), "graphics"), true), + fCategoryProductivity(new PackageCategory( + BitmapRef(), + B_TRANSLATE("Productivity"), "productivity"), true), + fCategoryDevelopment(new PackageCategory( + BitmapRef(), + B_TRANSLATE("Development"), "development"), true), + fCategoryCommandLine(new PackageCategory( + BitmapRef(), + B_TRANSLATE("Command line"), "command-line"), true) { } diff --git a/src/apps/haiku-depot/Model.h b/src/apps/haiku-depot/Model.h index d498a32..d748edc 100644 --- a/src/apps/haiku-depot/Model.h +++ b/src/apps/haiku-depot/Model.h @@ -18,10 +18,32 @@ public: bool AddDepot(const DepotInfo& depot); + // Access to global categories + const CategoryRef& CategoryAudio() const + { return fCategoryAudio; } + const CategoryRef& CategoryVideo() const + { return fCategoryVideo; } + const CategoryRef& CategoryGraphics() const + { return fCategoryGraphics; } + const CategoryRef& CategoryProductivity() const + { return fCategoryProductivity; } + const CategoryRef& CategoryDevelopment() const + { return fCategoryDevelopment; } + const CategoryRef& CategoryCommandLine() const + { return fCategoryCommandLine; } + private: BString fSearchTerms; DepotInfoList fDepots; + + CategoryRef fCategoryAudio; + CategoryRef fCategoryVideo; + CategoryRef fCategoryGraphics; + CategoryRef fCategoryProductivity; + CategoryRef fCategoryDevelopment; + CategoryRef fCategoryCommandLine; + // TODO: More categories }; diff --git a/src/apps/haiku-depot/PackageInfo.cpp b/src/apps/haiku-depot/PackageInfo.cpp index cf12591..e338a9d 100644 --- a/src/apps/haiku-depot/PackageInfo.cpp +++ b/src/apps/haiku-depot/PackageInfo.cpp @@ -22,6 +22,7 @@ SharedBitmap::SharedBitmap(BBitmap* bitmap) : + BReferenceable(), fResourceID(-1), fMimeType() { @@ -33,6 +34,7 @@ SharedBitmap::SharedBitmap(BBitmap* bitmap) SharedBitmap::SharedBitmap(int32 resourceID) : + BReferenceable(), fResourceID(resourceID), fMimeType() { @@ -44,6 +46,7 @@ SharedBitmap::SharedBitmap(int32 resourceID) SharedBitmap::SharedBitmap(const char* mimeType) : + BReferenceable(), fResourceID(-1), fMimeType(mimeType) { @@ -361,6 +364,65 @@ PublisherInfo::operator!=(const PublisherInfo& other) const } +// #pragma mark - PackageCategory + + +PackageCategory::PackageCategory() + : + BReferenceable(), + fIcon(), + fName() +{ +} + + +PackageCategory::PackageCategory(const BitmapRef& icon, const BString& label, + const BString& name) + : + BReferenceable(), + fIcon(icon), + fLabel(label), + fName(name) +{ +} + + +PackageCategory::PackageCategory(const PackageCategory& other) + : + BReferenceable(), + fIcon(other.fIcon), + fLabel(other.fLabel), + fName(other.fName) +{ +} + + +PackageCategory& +PackageCategory::operator=(const PackageCategory& other) +{ + fIcon = other.fIcon; + fName = other.fName; + fLabel = other.fLabel; + return *this; +} + + +bool +PackageCategory::operator==(const PackageCategory& other) const +{ + return fIcon == other.fIcon + && fLabel == other.fLabel + && fName == other.fName; +} + + +bool +PackageCategory::operator!=(const PackageCategory& other) const +{ + return !(*this == other); +} + + // #pragma mark - PackageInfo @@ -391,6 +453,7 @@ PackageInfo::PackageInfo(const BitmapRef& icon, const BString& title, fShortDescription(shortDescription), fFullDescription(fullDescription), fChangelog(changelog), + fCategories(), fUserRatings(), fScreenshots() { @@ -406,6 +469,7 @@ PackageInfo::PackageInfo(const PackageInfo& other) fShortDescription(other.fShortDescription), fFullDescription(other.fFullDescription), fChangelog(other.fChangelog), + fCategories(other.fCategories), fUserRatings(other.fUserRatings), fScreenshots(other.fScreenshots) { @@ -422,6 +486,7 @@ PackageInfo::operator=(const PackageInfo& other) fShortDescription = other.fShortDescription; fFullDescription = other.fFullDescription; fChangelog = other.fChangelog; + fCategories = other.fCategories; fUserRatings = other.fUserRatings; fScreenshots = other.fScreenshots; return *this; @@ -438,6 +503,7 @@ PackageInfo::operator==(const PackageInfo& other) const && fShortDescription == other.fShortDescription && fFullDescription == other.fFullDescription && fChangelog == other.fChangelog + && fCategories == other.fCategories && fUserRatings == other.fUserRatings && fScreenshots == other.fScreenshots; } @@ -451,6 +517,13 @@ PackageInfo::operator!=(const PackageInfo& other) const bool +PackageInfo::AddCategory(const CategoryRef& category) +{ + return fCategories.Add(category); +} + + +bool PackageInfo::AddUserRating(const UserRating& rating) { return fUserRatings.Add(rating); diff --git a/src/apps/haiku-depot/PackageInfo.h b/src/apps/haiku-depot/PackageInfo.h index bf082c5..019fd1f 100644 --- a/src/apps/haiku-depot/PackageInfo.h +++ b/src/apps/haiku-depot/PackageInfo.h @@ -145,6 +145,35 @@ private: }; +class PackageCategory : public BReferenceable { +public: + PackageCategory(); + PackageCategory(const BitmapRef& icon, + const BString& label, + const BString& name); + PackageCategory(const PackageCategory& other); + + PackageCategory& operator=(const PackageCategory& other); + bool operator==(const PackageCategory& other) const; + bool operator!=(const PackageCategory& other) const; + + const BitmapRef& Icon() const + { return fIcon; } + const BString& Label() const + { return fLabel; } + const BString& Name() const + { return fName; } +private: + BitmapRef fIcon; + BString fLabel; + BString fName; +}; + + +typedef BReference<PackageCategory> CategoryRef; +typedef List<CategoryRef, false> CategoryList; + + class PackageInfo { public: PackageInfo(); @@ -176,15 +205,16 @@ public: const BString& Changelog() const { return fChangelog; } - bool AddUserRating(const UserRating& rating); + bool AddCategory(const CategoryRef& category); + const CategoryList& Categories() const + { return fCategories; } + bool AddUserRating(const UserRating& rating); const UserRatingList& UserRatings() const { return fUserRatings; } - RatingSummary CalculateRatingSummary() const; bool AddScreenshot(const BitmapRef& screenshot); - const BitmapList& Screenshots() const { return fScreenshots; } @@ -196,6 +226,7 @@ private: BString fShortDescription; BString fFullDescription; BString fChangelog; + CategoryList fCategories; UserRatingList fUserRatings; BitmapList fScreenshots; }; ############################################################################ Commit: 633ed4c48ec2b085686947229f0c5068463c6800 URL: http://cgit.haiku-os.org/haiku/commit/?id=633ed4c Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Aug 10 14:35:39 2013 UTC HaikuDepot: Make categories also accessible as List in Model ---------------------------------------------------------------------------- diff --git a/src/apps/haiku-depot/Model.cpp b/src/apps/haiku-depot/Model.cpp index 74c5365..195e8dc 100644 --- a/src/apps/haiku-depot/Model.cpp +++ b/src/apps/haiku-depot/Model.cpp @@ -38,6 +38,13 @@ Model::Model() BitmapRef(), B_TRANSLATE("Command line"), "command-line"), true) { + // Don't forget to add new categories to this list: + fCategories.Add(fCategoryAudio); + fCategories.Add(fCategoryVideo); + fCategories.Add(fCategoryGraphics); + fCategories.Add(fCategoryProductivity); + fCategories.Add(fCategoryDevelopment); + fCategories.Add(fCategoryCommandLine); } diff --git a/src/apps/haiku-depot/Model.h b/src/apps/haiku-depot/Model.h index d748edc..dc31179 100644 --- a/src/apps/haiku-depot/Model.h +++ b/src/apps/haiku-depot/Model.h @@ -32,6 +32,9 @@ public: const CategoryRef& CategoryCommandLine() const { return fCategoryCommandLine; } + const CategoryList& Categories() const + { return fCategories; } + private: BString fSearchTerms; @@ -44,6 +47,8 @@ private: CategoryRef fCategoryDevelopment; CategoryRef fCategoryCommandLine; // TODO: More categories + + CategoryList fCategories; }; ############################################################################ Commit: 4abd2b711028005315bbe67dafd1fce46bea8117 URL: http://cgit.haiku-os.org/haiku/commit/?id=4abd2b7 Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Aug 10 16:39:02 2013 UTC HaikuDepot: Beginnings of supporting filters... ... to reduce the package list. No filters can be defined via the UI, but a DepotFilter is already implemented, although its performance will probably need to improve. ---------------------------------------------------------------------------- diff --git a/src/apps/haiku-depot/FilterView.cpp b/src/apps/haiku-depot/FilterView.cpp index 5a7f6c8..41a35c6 100644 --- a/src/apps/haiku-depot/FilterView.cpp +++ b/src/apps/haiku-depot/FilterView.cpp @@ -16,6 +16,8 @@ #include <PopUpMenu.h> #include <TextControl.h> +#include "Model.h" + #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "FilterView" @@ -28,7 +30,7 @@ enum { }; -FilterView::FilterView() +FilterView::FilterView(const Model& model) : BGroupView("filter view") { @@ -36,21 +38,27 @@ FilterView::FilterView() BPopUpMenu* categoryMenu = new BPopUpMenu(B_TRANSLATE("Show")); categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All packages"), NULL)); categoryMenu->AddItem(new BSeparatorItem()); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Audio"), NULL)); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Games"), NULL)); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Graphics"), NULL)); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Development"), NULL)); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Miscellaneous"), NULL)); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Shell"), NULL)); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Video"), NULL)); + + const CategoryList& categories = model.Categories(); + for (int i = 0; i < categories.CountItems(); i++) { + const CategoryRef& category = categories.ItemAtFast(i); + BMessage* message = new BMessage(MSG_CATEGORY_SELECTED); + message->AddString("name", category->Name()); + BMenuItem* item = new BMenuItem(category->Label(), message); + categoryMenu->AddItem(item); + } + categoryMenu->AddItem(new BSeparatorItem()); + categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Installed packages"), NULL)); categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Uninstalled packages"), NULL)); categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("User selected packages"), NULL)); + categoryMenu->AddItem(new BSeparatorItem()); + categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Downloading"), NULL)); categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Update available"), NULL)); categoryMenu->ItemAt(0)->SetMarked(true); diff --git a/src/apps/haiku-depot/FilterView.h b/src/apps/haiku-depot/FilterView.h index 8877e3c..abfdc9f 100644 --- a/src/apps/haiku-depot/FilterView.h +++ b/src/apps/haiku-depot/FilterView.h @@ -10,11 +10,12 @@ class BMenuField; class BTextControl; +class Model; class FilterView : public BGroupView { public: - FilterView(); + FilterView(const Model& model); virtual ~FilterView(); virtual void AttachedToWindow(); diff --git a/src/apps/haiku-depot/MainWindow.cpp b/src/apps/haiku-depot/MainWindow.cpp index 563694c..f8990d0 100644 --- a/src/apps/haiku-depot/MainWindow.cpp +++ b/src/apps/haiku-depot/MainWindow.cpp @@ -36,7 +36,7 @@ MainWindow::MainWindow(BRect frame) BMenuBar* menuBar = new BMenuBar(B_TRANSLATE("Main Menu")); _BuildMenu(menuBar); - fFilterView = new FilterView(); + fFilterView = new FilterView(fModel); fPackageListView = new PackageListView(); fPackageInfoView = new PackageInfoView(&fPackageManager); diff --git a/src/apps/haiku-depot/Model.cpp b/src/apps/haiku-depot/Model.cpp index 195e8dc..2313c7d 100644 --- a/src/apps/haiku-depot/Model.cpp +++ b/src/apps/haiku-depot/Model.cpp @@ -14,6 +14,55 @@ #define B_TRANSLATION_CONTEXT "Model" +// #pragma mark - PackageFilters + + +PackageFilter::~PackageFilter() +{ +} + + +class AnyFilter : public PackageFilter { +public: + virtual bool AcceptsPackage(const PackageInfo& package) const + { + return true; + } +}; + + +class DepotFilter : public PackageFilter { +public: + DepotFilter(const DepotInfo& depot) + : + fDepot(depot) + { + } + + virtual bool AcceptsPackage(const PackageInfo& package) const + { + // TODO: Maybe a PackageInfo ought to know the Depot it came from? + // But right now the same package could theoretically be provided + // from different depots and the filter would work correctly. + // Also the PackageList could actually contain references to packages + // instead of the packages as objects. The equal operator is quite + // expensive as is. + const PackageInfoList& packageList = fDepot.PackageList(); + for (int i = packageList.CountItems() - 1; i >= 0; i--) { + if (packageList.ItemAtFast(i) == package) + return true; + } + return false; + } + +private: + DepotInfo fDepot; +}; + + +// #pragma mark - Model + + Model::Model() : fSearchTerms(), @@ -36,7 +85,14 @@ Model::Model() B_TRANSLATE("Development"), "development"), true), fCategoryCommandLine(new PackageCategory( BitmapRef(), - B_TRANSLATE("Command line"), "command-line"), true) + B_TRANSLATE("Command line"), "command-line"), true), + fCategoryGames(new PackageCategory( + BitmapRef(), + B_TRANSLATE("Games"), "games"), true), + + fCategoryFilter(PackageFilterRef(new AnyFilter(), true)), + fDepotFilter(PackageFilterRef(new AnyFilter(), true)), + fSearchTermsFilter(PackageFilterRef(new AnyFilter(), true)) { // Don't forget to add new categories to this list: fCategories.Add(fCategoryAudio); @@ -45,6 +101,7 @@ Model::Model() fCategories.Add(fCategoryProductivity); fCategories.Add(fCategoryDevelopment); fCategories.Add(fCategoryCommandLine); + fCategories.Add(fCategoryGames); } @@ -61,7 +118,12 @@ Model::CreatePackageList() const = fDepots.ItemAtFast(i).PackageList(); for (int32 j = 0; j < packageList.CountItems(); j++) { - resultList.Add(packageList.ItemAtFast(j)); + const PackageInfo& package = packageList.ItemAtFast(j); + if (fCategoryFilter->AcceptsPackage(package) + && fDepotFilter->AcceptsPackage(package) + && fSearchTermsFilter->AcceptsPackage(package)) { + resultList.Add(package); + } } } diff --git a/src/apps/haiku-depot/Model.h b/src/apps/haiku-depot/Model.h index dc31179..84cf35f 100644 --- a/src/apps/haiku-depot/Model.h +++ b/src/apps/haiku-depot/Model.h @@ -9,6 +9,17 @@ #include "PackageInfo.h" +class PackageFilter : public BReferenceable { +public: + virtual ~PackageFilter(); + + virtual bool AcceptsPackage( + const PackageInfo& package) const = 0; +}; + +typedef BReference<PackageFilter> PackageFilterRef; + + class Model { public: Model(); @@ -31,6 +42,8 @@ public: { return fCategoryDevelopment; } const CategoryRef& CategoryCommandLine() const { return fCategoryCommandLine; } + const CategoryRef& CategoryGames() const + { return fCategoryGames; } const CategoryList& Categories() const { return fCategories; } @@ -46,9 +59,14 @@ private: CategoryRef fCategoryProductivity; CategoryRef fCategoryDevelopment; CategoryRef fCategoryCommandLine; + CategoryRef fCategoryGames; // TODO: More categories CategoryList fCategories; + + PackageFilterRef fCategoryFilter; + PackageFilterRef fDepotFilter; + PackageFilterRef fSearchTermsFilter; }; ############################################################################ Commit: 42479955aef6ef698eb5b554449262f10d10ed8d URL: http://cgit.haiku-os.org/haiku/commit/?id=4247995 Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Aug 10 17:08:44 2013 UTC HaikuDepot: Implemented filtering by category ---------------------------------------------------------------------------- diff --git a/src/apps/haiku-depot/FilterView.cpp b/src/apps/haiku-depot/FilterView.cpp index 41a35c6..df090f9 100644 --- a/src/apps/haiku-depot/FilterView.cpp +++ b/src/apps/haiku-depot/FilterView.cpp @@ -23,20 +23,14 @@ #define B_TRANSLATION_CONTEXT "FilterView" -enum { - MSG_CATEGORY_SELECTED = 'ctsl', - MSG_REPOSITORY_SELECTED = 'rpsl', - MSG_SEARCH_TERMS_MODIFIED = 'stmd', -}; - - FilterView::FilterView(const Model& model) : BGroupView("filter view") { // Contruct category popup BPopUpMenu* categoryMenu = new BPopUpMenu(B_TRANSLATE("Show")); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All packages"), NULL)); + categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All packages"), + new BMessage(MSG_CATEGORY_SELECTED))); categoryMenu->AddItem(new BSeparatorItem()); const CategoryList& categories = model.Categories(); @@ -68,8 +62,21 @@ FilterView::FilterView(const Model& model) // Construct repository popup BPopUpMenu* repositoryMenu = new BPopUpMenu(B_TRANSLATE("Depot")); - repositoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All depots"), NULL)); + repositoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All depots"), + new BMessage(MSG_DEPOT_SELECTED))); repositoryMenu->ItemAt(0)->SetMarked(true); + + repositoryMenu->AddItem(new BSeparatorItem()); + + const DepotList& depots = model.Depots(); + for (int i = 0; i < depots.CountItems(); i++) { + const DepotInfo& depot = depots.ItemAtFast(i); + BMessage* message = new BMessage(MSG_DEPOT_SELECTED); + message->AddString("name", depot.Name()); + BMenuItem* item = new BMenuItem(depot.Name(), message); + repositoryMenu->AddItem(item); + } + fRepositoryField = new BMenuField("repository", B_TRANSLATE("Depot:"), repositoryMenu); diff --git a/src/apps/haiku-depot/FilterView.h b/src/apps/haiku-depot/FilterView.h index abfdc9f..8231854 100644 --- a/src/apps/haiku-depot/FilterView.h +++ b/src/apps/haiku-depot/FilterView.h @@ -13,6 +13,13 @@ class BTextControl; class Model; +enum { + MSG_CATEGORY_SELECTED = 'ctsl', + MSG_DEPOT_SELECTED = 'dpsl', + MSG_SEARCH_TERMS_MODIFIED = 'stmd', +}; + + class FilterView : public BGroupView { public: FilterView(const Model& model); diff --git a/src/apps/haiku-depot/MainWindow.cpp b/src/apps/haiku-depot/MainWindow.cpp index f8990d0..40cbfd4 100644 --- a/src/apps/haiku-depot/MainWindow.cpp +++ b/src/apps/haiku-depot/MainWindow.cpp @@ -33,6 +33,8 @@ MainWindow::MainWindow(BRect frame) B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS) { + _InitDummyModel(); + BMenuBar* menuBar = new BMenuBar(B_TRANSLATE("Main Menu")); _BuildMenu(menuBar); @@ -59,7 +61,6 @@ MainWindow::MainWindow(BRect frame) fSplitView->SetCollapsible(0, false); fSplitView->SetCollapsible(1, false); - _InitDummyModel(); _AdoptModel(); } @@ -100,6 +101,16 @@ MainWindow::MessageReceived(BMessage* message) break; } + case MSG_CATEGORY_SELECTED: + { + BString name; + if (message->FindString("name", &name) != B_OK) + name = ""; + fModel.SetCategory(name); + _AdoptModel(); + break; + } + default: BWindow::MessageReceived(message); break; diff --git a/src/apps/haiku-depot/Model.cpp b/src/apps/haiku-depot/Model.cpp index 2313c7d..a2f8935 100644 --- a/src/apps/haiku-depot/Model.cpp +++ b/src/apps/haiku-depot/Model.cpp @@ -60,6 +60,32 @@ private: }; +class CategoryFilter : public PackageFilter { +public: + CategoryFilter(const BString& category) + : + fCategory(category) + { + } + + virtual bool AcceptsPackage(const PackageInfo& package) const + { + const CategoryList& categories = package.Categories(); + for (int i = categories.CountItems() - 1; i >= 0; i--) { + const CategoryRef& category = categories.ItemAtFast(i); + if (category.Get() == NULL) + continue; + if (category->Name() == fCategory) + return true; + } + return false; + } + +private: + BString fCategory; +}; + + // #pragma mark - Model @@ -137,3 +163,13 @@ Model::AddDepot(const DepotInfo& depot) return fDepots.Add(depot); } + +void +Model::SetCategory(const BString& category) +{ + if (category.Length() == 0) + fCategoryFilter.SetTo(new AnyFilter(), true); + else + fCategoryFilter.SetTo(new CategoryFilter(category), true); +} + diff --git a/src/apps/haiku-depot/Model.h b/src/apps/haiku-depot/Model.h index 84cf35f..cdc0128 100644 --- a/src/apps/haiku-depot/Model.h +++ b/src/apps/haiku-depot/Model.h @@ -28,6 +28,8 @@ public: PackageInfoList CreatePackageList() const; bool AddDepot(const DepotInfo& depot); + const DepotList& Depots() const + { return fDepots; } // Access to global categories const CategoryRef& CategoryAudio() const @@ -48,10 +50,13 @@ public: const CategoryList& Categories() const { return fCategories; } + // Configure PackageFilters + void SetCategory(const BString& category); + private: BString fSearchTerms; - DepotInfoList fDepots; + DepotList fDepots; CategoryRef fCategoryAudio; CategoryRef fCategoryVideo; diff --git a/src/apps/haiku-depot/PackageInfo.cpp b/src/apps/haiku-depot/PackageInfo.cpp index e338a9d..7f1fdde 100644 --- a/src/apps/haiku-depot/PackageInfo.cpp +++ b/src/apps/haiku-depot/PackageInfo.cpp @@ -584,15 +584,15 @@ PackageInfo::AddScreenshot(const BitmapRef& screenshot) DepotInfo::DepotInfo() : - fTitle(), + fName(), fPackages() { } -DepotInfo::DepotInfo(const BString& title) +DepotInfo::DepotInfo(const BString& name) : - fTitle(title), + fName(name), fPackages() { } @@ -600,7 +600,7 @@ DepotInfo::DepotInfo(const BString& title) DepotInfo::DepotInfo(const DepotInfo& other) : - fTitle(other.fTitle), + fName(other.fName), fPackages(other.fPackages) { } @@ -609,7 +609,7 @@ DepotInfo::DepotInfo(const DepotInfo& other) DepotInfo& DepotInfo::operator=(const DepotInfo& other) { - fTitle = other.fTitle; + fName = other.fName; fPackages = other.fPackages; return *this; } @@ -618,7 +618,7 @@ DepotInfo::operator=(const DepotInfo& other) bool DepotInfo::operator==(const DepotInfo& other) const { - return fTitle == other.fTitle + return fName == other.fName && fPackages == other.fPackages; } diff --git a/src/apps/haiku-depot/PackageInfo.h b/src/apps/haiku-depot/PackageInfo.h index 019fd1f..db9f1b7 100644 --- a/src/apps/haiku-depot/PackageInfo.h +++ b/src/apps/haiku-depot/PackageInfo.h @@ -238,15 +238,15 @@ typedef List<PackageInfo, false> PackageInfoList; class DepotInfo { public: DepotInfo(); - DepotInfo(const BString& title); + DepotInfo(const BString& name); DepotInfo(const DepotInfo& other); DepotInfo& operator=(const DepotInfo& other); bool operator==(const DepotInfo& other) const; bool operator!=(const DepotInfo& other) const; - const BString& Title() const - { return fTitle; } + const BString& Name() const + { return fName; } const PackageInfoList& PackageList() const { return fPackages; } @@ -254,12 +254,12 @@ public: bool AddPackage(const PackageInfo& package); private: - BString fTitle; + BString fName; PackageInfoList fPackages; }; -typedef List<DepotInfo, false> DepotInfoList; +typedef List<DepotInfo, false> DepotList; #endif // PACKAGE_INFO_H ############################################################################ Commit: 2c3e4eaa41cfd0d79ddd41d115f6f2f4febc0518 URL: http://cgit.haiku-os.org/haiku/commit/?id=2c3e4ea Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Aug 10 17:29:17 2013 UTC HaikuDepot: List.h: added IndexOf(), Contains() and Remove() * All of those take const ItemType& as argument. ---------------------------------------------------------------------------- diff --git a/src/apps/haiku-depot/List.h b/src/apps/haiku-depot/List.h index be46c2a..d60bfaf 100644 --- a/src/apps/haiku-depot/List.h +++ b/src/apps/haiku-depot/List.h @@ -142,6 +142,12 @@ public: fCount--; } + inline void Remove(const ItemType& item) + { + Remove(IndexOf(item)); + + } + inline const ItemType& ItemAt(int32 index) const { if (index >= (int32)fCount) @@ -159,6 +165,20 @@ public: return ItemAt((int32)fCount - 1); } + inline int32 IndexOf(const ItemType& item) const + { + for (uint32 i = 0; i < fCount; i++) { + if (ItemAtFast(i) == item) + return i; + } + return -1; + } + + inline bool Contains(const ItemType& item) const + { + return IndexOf(item) >= 0; + } + private: inline bool _Resize(uint32 count) { ############################################################################ Commit: 706edd805f055a2f2dc134a232082ae15f391529 URL: http://cgit.haiku-os.org/haiku/commit/?id=706edd8 Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Aug 10 17:30:49 2013 UTC HaikuDepot: PackageInfoList -> PackageList, added PackageState enum * Model has SetPackageState(). It adds or removes a PackageInfo to/from three internal lists, installed, activated and uninstalled packages. ---------------------------------------------------------------------------- diff --git a/src/apps/haiku-depot/MainWindow.h b/src/apps/haiku-depot/MainWindow.h index f7d12fe..694f32d 100644 --- a/src/apps/haiku-depot/MainWindow.h +++ b/src/apps/haiku-depot/MainWindow.h @@ -47,7 +47,7 @@ private: BSplitView* fSplitView; Model fModel; - PackageInfoList fVisiblePackages; + PackageList fVisiblePackages; PackageManager fPackageManager; }; diff --git a/src/apps/haiku-depot/Model.cpp b/src/apps/haiku-depot/Model.cpp index a2f8935..21bc600 100644 --- a/src/apps/haiku-depot/Model.cpp +++ b/src/apps/haiku-depot/Model.cpp @@ -47,9 +47,9 @@ public: // Also the PackageList could actually contain references to packages // instead of the packages as objects. The equal operator is quite // expensive as is. - const PackageInfoList& packageList = fDepot.PackageList(); - for (int i = packageList.CountItems() - 1; i >= 0; i--) { - if (packageList.ItemAtFast(i) == package) + const PackageList& packages = fDepot.Packages(); + for (int i = packages.CountItems() - 1; i >= 0; i--) { + if (packages.ItemAtFast(i) == package) return true; } return false; @@ -131,20 +131,19 @@ Model::Model() } -PackageInfoList +PackageList Model::CreatePackageList() const { // TODO: Allow to restrict depot, filter by search terms, ... // Return all packages from all depots. - PackageInfoList resultList; + PackageList resultList; for (int32 i = 0; i < fDepots.CountItems(); i++) { - const PackageInfoList& packageList - = fDepots.ItemAtFast(i).PackageList(); + const PackageList& packages = fDepots.ItemAtFast(i).Packages(); - for (int32 j = 0; j < packageList.CountItems(); j++) { - const PackageInfo& package = packageList.ItemAtFast(j); + for (int32 j = 0; j < packages.CountItems(); j++) { + const PackageInfo& package = packages.ItemAtFast(j); if (fCategoryFilter->AcceptsPackage(package) && fDepotFilter->AcceptsPackage(package) && fSearchTermsFilter->AcceptsPackage(package)) { @@ -165,6 +164,38 @@ Model::AddDepot(const DepotInfo& depot) void +Model::SetPackageState(const PackageInfo& package, PackageState state) +{ + switch (state) { + default: + case NONE: + fInstalledPackages.Remove(package); + fActivatedPackages.Remove(package); + fUninstalledPackages.Remove(package); + break; + case INSTALLED: + if (!fInstalledPackages.Contains(package)) + fInstalledPackages.Add(package); + fActivatedPackages.Remove(package); + fUninstalledPackages.Remove(package); + break; + case ACTIVATED: + if (!fInstalledPackages.Contains(package)) + fInstalledPackages.Add(package); + if (!fActivatedPackages.Contains(package)) + fActivatedPackages.Add(package); + fUninstalledPackages.Remove(package); + break; + case UNINSTALLED: + fInstalledPackages.Remove(package); + fActivatedPackages.Remove(package); + fUninstalledPackages.Add(package); + break; + } +} + + +void Model::SetCategory(const BString& category) { if (category.Length() == 0) diff --git a/src/apps/haiku-depot/Model.h b/src/apps/haiku-depot/Model.h index cdc0128..e455035 100644 --- a/src/apps/haiku-depot/Model.h +++ b/src/apps/haiku-depot/Model.h @@ -25,7 +25,7 @@ public: Model(); // !Returns new PackageInfoList from current parameters - PackageInfoList CreatePackageList() const; + PackageList CreatePackageList() const; bool AddDepot(const DepotInfo& depot); const DepotList& Depots() const @@ -50,6 +50,10 @@ public: const CategoryList& Categories() const { return fCategories; } + void SetPackageState( + const PackageInfo& package, + PackageState state); + // Configure PackageFilters void SetCategory(const BString& category); @@ -69,6 +73,10 @@ private: CategoryList fCategories; + PackageList fInstalledPackages; + PackageList fActivatedPackages; + PackageList fUninstalledPackages; + PackageFilterRef fCategoryFilter; PackageFilterRef fDepotFilter; PackageFilterRef fSearchTermsFilter; diff --git a/src/apps/haiku-depot/PackageInfo.h b/src/apps/haiku-depot/PackageInfo.h index db9f1b7..7461a07 100644 --- a/src/apps/haiku-depot/PackageInfo.h +++ b/src/apps/haiku-depot/PackageInfo.h @@ -232,7 +232,15 @@ private: }; -typedef List<PackageInfo, false> PackageInfoList; +typedef List<PackageInfo, false> PackageList; + + +enum PackageState { + NONE = 0, + INSTALLED = 1, + ACTIVATED = 2, + UNINSTALLED = 3, +}; class DepotInfo { @@ -248,14 +256,14 @@ public: const BString& Name() const { return fName; } - const PackageInfoList& PackageList() const + const PackageList& Packages() const { return fPackages; } bool AddPackage(const PackageInfo& package); private: BString fName; - PackageInfoList fPackages; + PackageList fPackages; }; ############################################################################ Revision: hrev45959 Commit: 3a6ccc85790389640be1c6b3a7046186f5f34a66 URL: http://cgit.haiku-os.org/haiku/commit/?id=3a6ccc8 Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Aug 10 18:36:04 2013 UTC HaikuDepot: Fleshed out the code to support the virtual categories ---------------------------------------------------------------------------- diff --git a/src/apps/haiku-depot/FilterView.cpp b/src/apps/haiku-depot/FilterView.cpp index df090f9..5f0e954 100644 --- a/src/apps/haiku-depot/FilterView.cpp +++ b/src/apps/haiku-depot/FilterView.cpp @@ -23,6 +23,19 @@ #define B_TRANSLATION_CONTEXT "FilterView" +static void +add_categories_to_menu(const CategoryList& categories, BMenu* menu) +{ + for (int i = 0; i < categories.CountItems(); i++) { + const CategoryRef& category = categories.ItemAtFast(i); + BMessage* message = new BMessage(MSG_CATEGORY_SELECTED); + message->AddString("name", category->Name()); + BMenuItem* item = new BMenuItem(category->Label(), message); + menu->AddItem(item); + } +} + + FilterView::FilterView(const Model& model) : BGroupView("filter view") @@ -32,29 +45,12 @@ FilterView::FilterView(const Model& model) categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All packages"), new BMessage(MSG_CATEGORY_SELECTED))); categoryMenu->AddItem(new BSeparatorItem()); - - const CategoryList& categories = model.Categories(); - for (int i = 0; i < categories.CountItems(); i++) { - const CategoryRef& category = categories.ItemAtFast(i); - BMessage* message = new BMessage(MSG_CATEGORY_SELECTED); - message->AddString("name", category->Name()); - BMenuItem* item = new BMenuItem(category->Label(), message); - categoryMenu->AddItem(item); - } - + add_categories_to_menu(model.Categories(), categoryMenu); categoryMenu->AddItem(new BSeparatorItem()); - - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Installed packages"), - NULL)); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Uninstalled packages"), - NULL)); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("User selected packages"), - NULL)); - + add_categories_to_menu(model.UserCategories(), categoryMenu); categoryMenu->AddItem(new BSeparatorItem()); + add_categories_to_menu(model.ProgressCategories(), categoryMenu); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Downloading"), NULL)); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("Update available"), NULL)); categoryMenu->ItemAt(0)->SetMarked(true); fShowField = new BMenuField("category", B_TRANSLATE("Show:"), diff --git a/src/apps/haiku-depot/MainWindow.cpp b/src/apps/haiku-depot/MainWindow.cpp index 40cbfd4..22ab128 100644 --- a/src/apps/haiku-depot/MainWindow.cpp +++ b/src/apps/haiku-depot/MainWindow.cpp @@ -228,4 +228,7 @@ MainWindow::_InitDummyModel() depot.AddPackage(paladin); fModel.AddDepot(depot); + + fModel.SetPackageState(wonderbrush, UNINSTALLED); + fModel.SetPackageState(paladin, ACTIVATED); } diff --git a/src/apps/haiku-depot/Model.cpp b/src/apps/haiku-depot/Model.cpp index 21bc600..d6bd927 100644 --- a/src/apps/haiku-depot/Model.cpp +++ b/src/apps/haiku-depot/Model.cpp @@ -86,6 +86,46 @@ private: }; +class ContainedInFilter : public PackageFilter { +public: + ContainedInFilter(const PackageList& packageList) + : + fPackageList(packageList) + { + } + + virtual bool AcceptsPackage(const PackageInfo& package) const + { + return fPackageList.Contains(package); + } + +private: + const PackageList& fPackageList; +}; + + +class ContainedInEitherFilter : public PackageFilter { +public: + ContainedInEitherFilter(const PackageList& packageListA, + const PackageList& packageListB) + : + fPackageListA(packageListA), + fPackageListB(packageListB) + { + } + + virtual bool AcceptsPackage(const PackageInfo& package) const + { + return fPackageListA.Contains(package) + || fPackageListB.Contains(package); + } + +private: + const PackageList& fPackageListA; + const PackageList& fPackageListB; +}; + + // #pragma mark - Model @@ -128,6 +168,34 @@ Model::Model() fCategories.Add(fCategoryDevelopment); fCategories.Add(fCategoryCommandLine); fCategories.Add(fCategoryGames); + + // A category for packages that the user installed. + fUserCategories.Add(CategoryRef(new PackageCategory( + BitmapRef(), + B_TRANSLATE("Installed packages"), "installed"), true)); + + // A category for packages that the user specifically uninstalled. + // For example, a user may have removed packages from a default + // Haiku installation + fUserCategories.Add(CategoryRef(new PackageCategory( + BitmapRef(), + B_TRANSLATE("Uninstalled packages"), "uninstalled"), true)); + + // A category for all packages that the user has installed or uninstalled. + // Those packages resemble what makes their system different from a + // fresh Haiku installation. + fUserCategories.Add(CategoryRef(new PackageCategory( + BitmapRef(), + B_TRANSLATE("User modified packages"), "modified"), true)); + + // Two categories to see just the packages which are downloading or + // have updates available + fProgressCategories.Add(CategoryRef(new PackageCategory( + BitmapRef(), + B_TRANSLATE("Downloading"), "downloading"), true)); + fProgressCategories.Add(CategoryRef(new PackageCategory( + BitmapRef(), + B_TRANSLATE("Update available"), "updates"), true)); } @@ -198,9 +266,24 @@ Model::SetPackageState(const PackageInfo& package, PackageState state) void Model::SetCategory(const BString& category) { + PackageFilter* filter; + if (category.Length() == 0) - fCategoryFilter.SetTo(new AnyFilter(), true); + filter = new AnyFilter(); + else if (category == "installed") + filter = new ContainedInFilter(fInstalledPackages); + else if (category == "uninstalled") + filter = new ContainedInFilter(fUninstalledPackages); + else if (category == "modified") { + filter = new ContainedInEitherFilter(fInstalledPackages, + fUninstalledPackages); + } else if (category == "downloading") + filter = new ContainedInFilter(fDownloadingPackages); + else if (category == "updates") + filter = new ContainedInFilter(fUpdateablePackages); else - fCategoryFilter.SetTo(new CategoryFilter(category), true); + filter = new CategoryFilter(category); + + fCategoryFilter.SetTo(filter, true); } diff --git a/src/apps/haiku-depot/Model.h b/src/apps/haiku-depot/Model.h index e455035..ebb3621 100644 --- a/src/apps/haiku-depot/Model.h +++ b/src/apps/haiku-depot/Model.h @@ -49,6 +49,10 @@ public: const CategoryList& Categories() const { return fCategories; } + const CategoryList& UserCategories() const + { return fUserCategories; } + const CategoryList& ProgressCategories() const + { return fProgressCategories; } void SetPackageState( const PackageInfo& package, @@ -72,10 +76,14 @@ private: // TODO: More categories CategoryList fCategories; + CategoryList fUserCategories; + CategoryList fProgressCategories; PackageList fInstalledPackages; PackageList fActivatedPackages; PackageList fUninstalledPackages; + PackageList fDownloadingPackages; + PackageList fUpdateablePackages; PackageFilterRef fCategoryFilter; PackageFilterRef fDepotFilter;