hrev47854 adds 2 changesets to branch 'master' old head: 8bfb30ceb34798ab2d51a700ffe56b9a26528421 new head: e0881f2139195cfcb90251b5595f22e2faa5e5e4 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=e0881f2+%5E8bfb30c ---------------------------------------------------------------------------- ab17280: HaikuDepot: Improve filter UI, fix pkg translations * The categories and other filter options are orthogonal. Don't force the user to choose between real categories and for example "installed" or "available" in the same drop-down. I've removed (for now) the Options main menu. There are now four small check-marks below the filtering drop-downs: Available, Installed, Development and Source Code. These enable showing the respective packages in the list view. Only "Available" is checked by default. This changes the default behavior to show only not-yet-installed packages. This change puts the filtering options in one place, the showing of development or source code packages is not "hidden somewhere else" anymore. I am not so happy with the additional row, however, I am also thinking about using icons instead of the checkmarks. * Fixed finding the suitable package translation for summary and description. For example, WonderBrush now has a German translation. e0881f2: HaikuDepot: Fixed reading bigger screenshots * Increase the RAM limit to 128K per screenshot * Reduce retrieved size to 320 pixel wide * Don't expect to be able to read the stream in one call, read it in 4K chunks. * Print some errors in this code-path to stderr. [ Stephan Aßmus <superstippi@xxxxxx> ] ---------------------------------------------------------------------------- 6 files changed, 222 insertions(+), 123 deletions(-) src/apps/haikudepot/FilterView.cpp | 92 ++++++++++++++++++------ src/apps/haikudepot/FilterView.h | 8 +++ src/apps/haikudepot/MainWindow.cpp | 75 ++++++++++++++----- src/apps/haikudepot/Model.cpp | 123 ++++++++++++++------------------ src/apps/haikudepot/Model.h | 15 ++-- src/apps/haikudepot/PackageInfo.cpp | 32 ++++++--- ############################################################################ Commit: ab172803ff54c394b2edc729b05a3dd39a2193ee URL: http://cgit.haiku-os.org/haiku/commit/?id=ab17280 Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Sep 13 20:27:59 2014 UTC HaikuDepot: Improve filter UI, fix pkg translations * The categories and other filter options are orthogonal. Don't force the user to choose between real categories and for example "installed" or "available" in the same drop-down. I've removed (for now) the Options main menu. There are now four small check-marks below the filtering drop-downs: Available, Installed, Development and Source Code. These enable showing the respective packages in the list view. Only "Available" is checked by default. This changes the default behavior to show only not-yet-installed packages. This change puts the filtering options in one place, the showing of development or source code packages is not "hidden somewhere else" anymore. I am not so happy with the additional row, however, I am also thinking about using icons instead of the checkmarks. * Fixed finding the suitable package translation for summary and description. For example, WonderBrush now has a German translation. ---------------------------------------------------------------------------- diff --git a/src/apps/haikudepot/FilterView.cpp b/src/apps/haikudepot/FilterView.cpp index d85d0dd..b57264b 100644 --- a/src/apps/haikudepot/FilterView.cpp +++ b/src/apps/haikudepot/FilterView.cpp @@ -9,6 +9,7 @@ #include <stdio.h> #include <Catalog.h> +#include <CheckBox.h> #include <LayoutBuilder.h> #include <MenuField.h> #include <MenuItem.h> @@ -36,15 +37,27 @@ add_categories_to_menu(const CategoryList& categories, BMenu* menu) } +static BCheckBox* +create_check_box(const char* label, const char* name) +{ + BMessage* message = new BMessage(MSG_FILTER_SELECTED); + message->AddString("name", name); + BCheckBox* checkBox = new BCheckBox(label, message); + BFont font; + checkBox->GetFont(&font); + font.SetSize(ceilf(font.Size() * 0.75)); + checkBox->SetFont(&font); + return checkBox; +} + + FilterView::FilterView() : - BGroupView("filter view") + BGroupView("filter view", B_VERTICAL) { // Contruct category popup - BPopUpMenu* categoryMenu = new BPopUpMenu(B_TRANSLATE("Show")); - - fShowField = new BMenuField("category", B_TRANSLATE("Show:"), - categoryMenu); + BPopUpMenu* showMenu = new BPopUpMenu(B_TRANSLATE("Category")); + fShowField = new BMenuField("category", B_TRANSLATE("Category:"), showMenu); // Construct repository popup BPopUpMenu* repositoryMenu = new BPopUpMenu(B_TRANSLATE("Depot")); @@ -67,15 +80,34 @@ FilterView::FilterView() float maxSearchWidth = minSearchWidth * 2; fSearchTermsText->SetExplicitMaxSize(BSize(maxSearchWidth, B_SIZE_UNSET)); + // Construct check boxen + fAvailableCheckBox = create_check_box( + B_TRANSLATE("Available"), "available"); + fInstalledCheckBox = create_check_box( + B_TRANSLATE("Installed"), "installed"); + fDevelopmentCheckBox = create_check_box( + B_TRANSLATE("Development"), "development"); + fSourceCodeCheckBox = create_check_box( + B_TRANSLATE("Source code"), "source code"); + // Build layout BLayoutBuilder::Group<>(this) - .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1.2f) - .Add(fShowField, 0.0f) - .Add(fRepositoryField, 0.0f) - .SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)) + .AddGroup(B_HORIZONTAL) + .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1.2f) + .Add(fShowField, 0.0f) + .Add(fRepositoryField, 0.0f) + .SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)) + .End() + .AddGlue(0.5f) + .Add(fSearchTermsText, 1.0f) + .End() + .AddGroup(B_HORIZONTAL) + .Add(fAvailableCheckBox) + .Add(fInstalledCheckBox) + .Add(fDevelopmentCheckBox) + .Add(fSourceCodeCheckBox) + .AddGlue(0.5f) .End() - .AddGlue(0.5f) - .Add(fSearchTermsText, 1.0f) .SetInsets(B_USE_DEFAULT_SPACING) ; @@ -95,6 +127,11 @@ FilterView::AttachedToWindow() fSearchTermsText->SetTarget(this); fSearchTermsText->MakeFocus(); + + fAvailableCheckBox->SetTarget(Window()); + fInstalledCheckBox->SetTarget(Window()); + fDevelopmentCheckBox->SetTarget(Window()); + fSourceCodeCheckBox->SetTarget(Window()); } @@ -138,17 +175,28 @@ FilterView::AdoptModel(const Model& model) repositoryMenu->AddItem(item); } - BMenu* categoryMenu = fShowField->Menu(); - categoryMenu->RemoveItems(0, categoryMenu->CountItems(), true); + BMenu* showMenu = fShowField->Menu(); + showMenu->RemoveItems(0, showMenu->CountItems(), true); - categoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All packages"), + showMenu->AddItem(new BMenuItem(B_TRANSLATE("All categories"), new BMessage(MSG_CATEGORY_SELECTED))); - categoryMenu->AddItem(new BSeparatorItem()); - add_categories_to_menu(model.Categories(), categoryMenu); - categoryMenu->AddItem(new BSeparatorItem()); - add_categories_to_menu(model.UserCategories(), categoryMenu); - categoryMenu->AddItem(new BSeparatorItem()); - add_categories_to_menu(model.ProgressCategories(), categoryMenu); - - categoryMenu->ItemAt(0)->SetMarked(true); + + showMenu->AddItem(new BSeparatorItem()); + + add_categories_to_menu(model.Categories(), showMenu); + + showMenu->ItemAt(0)->SetMarked(true); + + AdoptCheckmarks(model); } + + +void +FilterView::AdoptCheckmarks(const Model& model) +{ + fAvailableCheckBox->SetValue(model.ShowAvailablePackages()); + fInstalledCheckBox->SetValue(model.ShowInstalledPackages()); + fDevelopmentCheckBox->SetValue(model.ShowDevelopPackages()); + fSourceCodeCheckBox->SetValue(model.ShowSourcePackages()); +} + diff --git a/src/apps/haikudepot/FilterView.h b/src/apps/haikudepot/FilterView.h index d6baf4e..78ae76a 100644 --- a/src/apps/haikudepot/FilterView.h +++ b/src/apps/haikudepot/FilterView.h @@ -8,6 +8,7 @@ #include <GroupView.h> +class BCheckBox; class BMenuField; class BTextControl; class Model; @@ -15,6 +16,7 @@ class Model; enum { MSG_CATEGORY_SELECTED = 'ctsl', + MSG_FILTER_SELECTED = 'ftsl', MSG_DEPOT_SELECTED = 'dpsl', MSG_SEARCH_TERMS_MODIFIED = 'stmd', }; @@ -29,11 +31,17 @@ public: virtual void MessageReceived(BMessage* message); virtual void AdoptModel(const Model& model); + virtual void AdoptCheckmarks(const Model& model); private: BMenuField* fShowField; BMenuField* fRepositoryField; BTextControl* fSearchTermsText; + + BCheckBox* fAvailableCheckBox; + BCheckBox* fInstalledCheckBox; + BCheckBox* fDevelopmentCheckBox; + BCheckBox* fSourceCodeCheckBox; }; #endif // FILTER_VIEW_H diff --git a/src/apps/haikudepot/MainWindow.cpp b/src/apps/haikudepot/MainWindow.cpp index a2b9051..7f2ab16 100644 --- a/src/apps/haikudepot/MainWindow.cpp +++ b/src/apps/haikudepot/MainWindow.cpp @@ -246,7 +246,40 @@ MainWindow::MessageReceived(BMessage* message) BString name; if (message->FindString("name", &name) != B_OK) name = ""; - fModel.SetCategory(name); + { + BAutolock locker(fModel.Lock()); + fModel.SetCategory(name); + } + _AdoptModel(); + break; + } + + case MSG_FILTER_SELECTED: + { + BString name; + int32 value; + if (message->FindString("name", &name) != B_OK + || message->FindInt32("be:value", &value) != B_OK) { + break; + } + { + BAutolock locker(fModel.Lock()); + if (name == "available") { + fModel.SetShowAvailablePackages( + value == B_CONTROL_ON); + } else if (name == "installed") { + fModel.SetShowInstalledPackages( + value == B_CONTROL_ON); + } else if (name == "development") { + fModel.SetShowDevelopPackages( + value == B_CONTROL_ON); + } else if (name == "source code") { + fModel.SetShowSourcePackages( + value == B_CONTROL_ON); + } else { + break; + } + } _AdoptModel(); break; } @@ -256,7 +289,10 @@ MainWindow::MessageReceived(BMessage* message) BString name; if (message->FindString("name", &name) != B_OK) name = ""; - fModel.SetDepot(name); + { + BAutolock locker(fModel.Lock()); + fModel.SetDepot(name); + } _AdoptModel(); break; } @@ -267,7 +303,10 @@ MainWindow::MessageReceived(BMessage* message) BString searchTerms; if (message->FindString("search terms", &searchTerms) != B_OK) searchTerms = ""; - fModel.SetSearchTerms(searchTerms); + { + BAutolock locker(fModel.Lock()); + fModel.SetSearchTerms(searchTerms); + } _AdoptModel(); break; } @@ -277,6 +316,7 @@ MainWindow::MessageReceived(BMessage* message) PackageInfo* info; if (message->FindPointer("package", (void**)&info) == B_OK) { PackageInfoRef ref(info, true); + BAutolock locker(fModel.Lock()); fModel.SetPackageState(ref, ref->State()); } break; @@ -356,18 +396,18 @@ MainWindow::_BuildMenu(BMenuBar* menuBar) new BMessage(MSG_REFRESH_DEPOTS))); menuBar->AddItem(menu); - menu = new BMenu(B_TRANSLATE("Options")); - - fShowDevelopPackagesItem = new BMenuItem( - B_TRANSLATE("Show develop packages"), - new BMessage(MSG_SHOW_DEVELOP_PACKAGES)); - menu->AddItem(fShowDevelopPackagesItem); - - fShowSourcePackagesItem = new BMenuItem(B_TRANSLATE("Show source packages"), - new BMessage(MSG_SHOW_SOURCE_PACKAGES)); - menu->AddItem(fShowSourcePackagesItem); - - menuBar->AddItem(menu); +// menu = new BMenu(B_TRANSLATE("Options")); +// +// fShowDevelopPackagesItem = new BMenuItem( +// B_TRANSLATE("Show develop packages"), +// new BMessage(MSG_SHOW_DEVELOP_PACKAGES)); +// menu->AddItem(fShowDevelopPackagesItem); +// +// fShowSourcePackagesItem = new BMenuItem(B_TRANSLATE("Show source packages"), +// new BMessage(MSG_SHOW_SOURCE_PACKAGES)); +// menu->AddItem(fShowSourcePackagesItem); +// +// menuBar->AddItem(menu); } @@ -383,8 +423,9 @@ MainWindow::_AdoptModel() } BAutolock locker(fModel.Lock()); - fShowSourcePackagesItem->SetMarked(fModel.ShowSourcePackages()); - fShowDevelopPackagesItem->SetMarked(fModel.ShowDevelopPackages()); +// fShowSourcePackagesItem->SetMarked(fModel.ShowSourcePackages()); +// fShowDevelopPackagesItem->SetMarked(fModel.ShowDevelopPackages()); + fFilterView->AdoptCheckmarks(fModel); } diff --git a/src/apps/haikudepot/Model.cpp b/src/apps/haikudepot/Model.cpp index 9462c93..8307f6c 100644 --- a/src/apps/haikudepot/Model.cpp +++ b/src/apps/haikudepot/Model.cpp @@ -303,6 +303,8 @@ Model::Model() fDepotFilter(""), fSearchTermsFilter(PackageFilterRef(new AnyFilter(), true)), + fShowAvailablePackages(true), + fShowInstalledPackages(false), fShowSourcePackages(false), fShowDevelopPackages(false), @@ -325,39 +327,6 @@ Model::Model() // get the defined categories and their translated names. // This should then be used instead of hard-coded // categories and translations in the app. - - // 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 not yet installed. - fUserCategories.Add(CategoryRef(new PackageCategory( - BitmapRef(), - B_TRANSLATE("Available packages"), "available"), 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)); } @@ -370,9 +339,8 @@ Model::~Model() PackageList Model::CreatePackageList() const { - // TODO: Allow to restrict depot, filter by search terms, ... - - // Return all packages from all depots. + // Iterate all packages from all depots. + // If configured, restrict depot, filter by search terms, status, name ... PackageList resultList; for (int32 i = 0; i < fDepots.CountItems(); i++) { @@ -387,6 +355,8 @@ Model::CreatePackageList() const const PackageInfoRef& package = packages.ItemAtFast(j); if (fCategoryFilter->AcceptsPackage(package) && fSearchTermsFilter->AcceptsPackage(package) + && (fShowAvailablePackages || package->State() != NONE) + && (fShowInstalledPackages || package->State() != ACTIVATED) && (fShowSourcePackages || !is_source_package(package)) && (fShowDevelopPackages || !is_develop_package(package))) { resultList.Add(package); @@ -439,7 +409,8 @@ Model::SetPackageState(const PackageInfoRef& package, PackageState state) case UNINSTALLED: fInstalledPackages.Remove(package); fActivatedPackages.Remove(package); - fUninstalledPackages.Add(package); + if (!fUninstalledPackages.Contains(package)) + fUninstalledPackages.Add(package); break; } @@ -457,22 +428,6 @@ Model::SetCategory(const BString& category) if (category.Length() == 0) filter = new AnyFilter(); - else if (category == "installed") - filter = new ContainedInFilter(fInstalledPackages); - else if (category == "uninstalled") - filter = new ContainedInFilter(fUninstalledPackages); - else if (category == "available") { - filter = new StateFilter(NONE); -// filter = new NotContainedInFilter(&fInstalledPackages, -// &fUninstalledPackages, &fDownloadingPackages, &fUpdateablePackages, -// NULL); - } 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 filter = new CategoryFilter(category); @@ -502,6 +457,20 @@ Model::SetSearchTerms(const BString& searchTerms) void +Model::SetShowAvailablePackages(bool show) +{ + fShowAvailablePackages = show; +} + + +void +Model::SetShowInstalledPackages(bool show) +{ + fShowInstalledPackages = show; +} + + +void Model::SetShowSourcePackages(bool show) { fShowSourcePackages = show; @@ -883,23 +852,33 @@ Model::_PopulatePackageInfo(const PackageInfoRef& package, const BMessage& data) BString foundInfo; BMessage versions; - BMessage version; - if (data.FindMessage("versions", &versions) == B_OK - && versions.FindMessage("0", &version)) { - BString languageCode; - if (version.FindString("naturalLanguageCode", &languageCode) == B_OK) { - if (languageCode == fPreferredLanguage) { - BString summary; - if (version.FindString("summary", &summary) == B_OK) { - package->SetShortDescription(summary); - append_word_list(foundInfo, "summary"); - } - BString description; - if (version.FindString("description", &description) == B_OK) { - package->SetFullDescription(description); - append_word_list(foundInfo, "description"); - } + if (data.FindMessage("versions", &versions) == B_OK) { + // Search a summary and description in the preferred language + int32 index = 0; + while (true) { + BString name; + name << index++; + BMessage version; + if (versions.FindMessage(name, &version) != B_OK) + break; + BString languageCode; + if (version.FindString("naturalLanguageCode", + &languageCode) != B_OK + || languageCode != fPreferredLanguage) { + continue; } + + BString summary; + if (version.FindString("summary", &summary) == B_OK) { + package->SetShortDescription(summary); + append_word_list(foundInfo, "summary"); + } + BString description; + if (version.FindString("description", &description) == B_OK) { + package->SetFullDescription(description); + append_word_list(foundInfo, "description"); + } + break; } } diff --git a/src/apps/haikudepot/Model.h b/src/apps/haikudepot/Model.h index 09b94cd..543492c 100644 --- a/src/apps/haikudepot/Model.h +++ b/src/apps/haikudepot/Model.h @@ -66,10 +66,6 @@ public: const CategoryList& Categories() const { return fCategories; } - const CategoryList& UserCategories() const - { return fUserCategories; } - const CategoryList& ProgressCategories() const - { return fProgressCategories; } void SetPackageState( const PackageInfoRef& package, @@ -79,6 +75,13 @@ public: void SetCategory(const BString& category); void SetDepot(const BString& depot); void SetSearchTerms(const BString& searchTerms); + + void SetShowAvailablePackages(bool show); + bool ShowAvailablePackages() const + { return fShowAvailablePackages; } + void SetShowInstalledPackages(bool show); + bool ShowInstalledPackages() const + { return fShowInstalledPackages; } void SetShowSourcePackages(bool show); bool ShowSourcePackages() const { return fShowSourcePackages; } @@ -142,8 +145,6 @@ private: // TODO: Dynamic categories retrieved from web-app CategoryList fCategories; - CategoryList fUserCategories; - CategoryList fProgressCategories; PackageList fInstalledPackages; PackageList fActivatedPackages; @@ -156,6 +157,8 @@ private: BString fDepotFilter; PackageFilterRef fSearchTermsFilter; + bool fShowAvailablePackages; + bool fShowInstalledPackages; bool fShowSourcePackages; bool fShowDevelopPackages; ############################################################################ Revision: hrev47854 Commit: e0881f2139195cfcb90251b5595f22e2faa5e5e4 URL: http://cgit.haiku-os.org/haiku/commit/?id=e0881f2 Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Sep 13 21:01:01 2014 UTC HaikuDepot: Fixed reading bigger screenshots * Increase the RAM limit to 128K per screenshot * Reduce retrieved size to 320 pixel wide * Don't expect to be able to read the stream in one call, read it in 4K chunks. * Print some errors in this code-path to stderr. ---------------------------------------------------------------------------- diff --git a/src/apps/haikudepot/Model.cpp b/src/apps/haikudepot/Model.cpp index 8307f6c..ae81f13 100644 --- a/src/apps/haikudepot/Model.cpp +++ b/src/apps/haikudepot/Model.cpp @@ -598,7 +598,7 @@ Model::PopulatePackage(const PackageInfoRef& package, uint32 flags) } for (int i = 0; i < screenshotInfos.CountItems(); i++) { const ScreenshotInfo& info = screenshotInfos.ItemAtFast(i); - _PopulatePackageScreenshot(package, info, 400, false); + _PopulatePackageScreenshot(package, info, 320, false); } } } @@ -1070,6 +1070,10 @@ Model::_PopulatePackageScreenshot(const PackageInfoRef& package, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) == B_OK) { screenshotFile.Write(buffer.Buffer(), buffer.BufferLength()); } + } else { + fprintf(stderr, "Failed to retrieve screenshot for code '%s' " + "at %" B_PRIi32 "x%" B_PRIi32 ".\n", info.Code().String(), + scaledWidth, scaledHeight); } } diff --git a/src/apps/haikudepot/PackageInfo.cpp b/src/apps/haikudepot/PackageInfo.cpp index b63447d..aaf67ea 100644 --- a/src/apps/haikudepot/PackageInfo.cpp +++ b/src/apps/haikudepot/PackageInfo.cpp @@ -74,16 +74,32 @@ SharedBitmap::SharedBitmap(BPositionIO& data) fMimeType() { status_t status = data.GetSize(&fSize); - if (status == B_OK && fSize > 0 && fSize <= 64 * 1024) { + const off_t kMaxSize = 128 * 1024; + if (status == B_OK && fSize > 0 && fSize <= kMaxSize) { fBuffer = new(std::nothrow) uint8[fSize]; - - data.Seek(0, SEEK_SET); - ssize_t read = data.Read(fBuffer, fSize); - if (read != fSize) { - delete[] fBuffer; - fBuffer = NULL; + if (fBuffer != NULL) { + data.Seek(0, SEEK_SET); + + size_t bytesRead = 0; + size_t chunkSize = std::min((off_t)4096, fSize); + while (bytesRead < fSize) { + ssize_t read = data.Read(fBuffer + bytesRead, chunkSize); + if (read > 0) + bytesRead += read; + else + break; + } + + if (bytesRead != fSize) { + delete[] fBuffer; + fBuffer = NULL; + fSize = 0; + } + } else fSize = 0; - } + } else { + fprintf(stderr, "SharedBitmap(): Stream too large: %" B_PRIi64 + ", max: %" B_PRIi64 "\n", fSize, kMaxSize); } fBitmap[0] = NULL;