HaikuDepot: Load Languages from HDS

The HaikuDepot application has, thus far had its
own hard-coded list of languages that the user is
able to choose when (a) creating a new account or
(b) creating a user-rating.  This change will mean
that those languages are loaded from the HDS
server dynamically and in this way the user can
choose from the full list.  There have also been
improvements to the way in which the languages are
displayed in the menu as well.

Change-Id: If7cb7b87f348ca59d503d276a22444e72d0e6168
Reviewed-on: https://review.haiku-os.org/c/1425
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Andrew Lindesay
2019-05-15 19:03:48 +00:00
parent 9fe74faa61
commit f85e030047
25 changed files with 950 additions and 174 deletions
+8 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2018, Andrew Lindesay <[email protected]>. * Copyright 2018-2019, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef HAIKU_DEPOT_CONSTANTS_H #ifndef HAIKU_DEPOT_CONSTANTS_H
@@ -18,7 +18,8 @@ enum {
MSG_SERVER_DATA_CHANGED = 'svdc', MSG_SERVER_DATA_CHANGED = 'svdc',
MSG_ALERT_SIMPLE_ERROR = 'nser', MSG_ALERT_SIMPLE_ERROR = 'nser',
MSG_DID_ADD_USER_RATING = 'adur', MSG_DID_ADD_USER_RATING = 'adur',
MSG_DID_UPDATE_USER_RATING = 'upur' MSG_DID_UPDATE_USER_RATING = 'upur',
MSG_LANGUAGE_SELECTED = 'lngs'
}; };
@@ -54,4 +55,9 @@ enum {
RSRC_ARROW_RIGHT = 550, RSRC_ARROW_RIGHT = 550,
}; };
#define LANGUAGE_DEFAULT_CODE "en"
#define LANGUAGE_DEFAULT Language(LANGUAGE_DEFAULT_CODE, "English", true)
#endif // HAIKU_DEPOT_CONSTANTS_H #endif // HAIKU_DEPOT_CONSTANTS_H
+58 -4
View File
@@ -16,12 +16,19 @@ local dumpExportRepositoryBulkListerTargetDirectory =
local dumpExportPkgBulkListenerTargetDirectory = local dumpExportPkgBulkListenerTargetDirectory =
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY) [ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
dumpexportpkgbulklistener ] ; dumpexportpkgbulklistener ] ;
local dumpExportReferenceListenerTargetDirectory =
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
dumpexportreferencelistener ] ;
local dumpExportPkgModelTargetDirectory = local dumpExportPkgModelTargetDirectory =
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY) [ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
dumpexportpkgmodel ] ; dumpexportpkgmodel ] ;
local dumpExportRepositoryModelTargetDirectory = local dumpExportRepositoryModelTargetDirectory =
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY) [ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
dumpexportrepositorymodel ] ; dumpexportrepositorymodel ] ;
local dumpExportReferenceModelTargetDirectory =
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
dumpexportreferencemodel ] ;
# During the build process, some sources are generated into a directory. In # During the build process, some sources are generated into a directory. In
# order to maintain a timestamp on that generation process, a dummy file is # order to maintain a timestamp on that generation process, a dummy file is
@@ -34,10 +41,15 @@ local dumpExportRepositoryBulkListerTargetFile =
[ FDirName $(dumpExportRepositoryBulkListerTargetDirectory) $(dummyFile) ] ; [ FDirName $(dumpExportRepositoryBulkListerTargetDirectory) $(dummyFile) ] ;
local dumpExportPkgBulkListenerTargetFile = local dumpExportPkgBulkListenerTargetFile =
[ FDirName $(dumpExportPkgBulkListenerTargetDirectory) $(dummyFile) ] ; [ FDirName $(dumpExportPkgBulkListenerTargetDirectory) $(dummyFile) ] ;
local dumpExportReferenceListenerTargetFile =
[ FDirName $(dumpExportReferenceListenerTargetDirectory) $(dummyFile) ] ;
local dumpExportPkgModelTargetFile = local dumpExportPkgModelTargetFile =
[ FDirName $(dumpExportPkgModelTargetDirectory) $(dummyFile) ] ; [ FDirName $(dumpExportPkgModelTargetDirectory) $(dummyFile) ] ;
local dumpExportRepositoryModelTargetFile = local dumpExportRepositoryModelTargetFile =
[ FDirName $(dumpExportRepositoryModelTargetDirectory) $(dummyFile) ] ; [ FDirName $(dumpExportRepositoryModelTargetDirectory) $(dummyFile) ] ;
local dumpExportReferenceModelTargetFile =
[ FDirName $(dumpExportReferenceModelTargetDirectory) $(dummyFile) ] ;
# source directories # source directories
local sourceDirs = local sourceDirs =
@@ -57,10 +69,14 @@ for sourceDir in $(sourceDirs) {
} }
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src servers package ] ; SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src servers package ] ;
SEARCH_SOURCE += $(dumpExportRepositoryBulkListerTargetDirectory) ; SEARCH_SOURCE += $(dumpExportRepositoryBulkListerTargetDirectory) ;
SEARCH_SOURCE += $(dumpExportPkgBulkListenerTargetDirectory) ; SEARCH_SOURCE += $(dumpExportPkgBulkListenerTargetDirectory) ;
SEARCH_SOURCE += $(dumpExportReferenceListenerTargetDirectory) ;
SEARCH_SOURCE += $(dumpExportPkgModelTargetDirectory) ; SEARCH_SOURCE += $(dumpExportPkgModelTargetDirectory) ;
SEARCH_SOURCE += $(dumpExportRepositoryModelTargetDirectory) ; SEARCH_SOURCE += $(dumpExportRepositoryModelTargetDirectory) ;
SEARCH_SOURCE += $(dumpExportReferenceModelTargetDirectory) ;
local textDocumentSources = local textDocumentSources =
# edits_generic # edits_generic
@@ -101,6 +117,7 @@ local applicationSources =
FilterView.cpp FilterView.cpp
LocalIconStore.cpp LocalIconStore.cpp
JobStateListener.cpp JobStateListener.cpp
LanguageModel.cpp
LinkView.cpp LinkView.cpp
LinkedBitmapView.cpp LinkedBitmapView.cpp
Logger.cpp Logger.cpp
@@ -138,6 +155,7 @@ local applicationSources =
ServerHelper.cpp ServerHelper.cpp
ServerSettings.cpp ServerSettings.cpp
ServerPkgDataUpdateProcess.cpp ServerPkgDataUpdateProcess.cpp
ServerReferenceDataUpdateProcess.cpp
ServerRepositoryDataUpdateProcess.cpp ServerRepositoryDataUpdateProcess.cpp
ServerIconExportUpdateProcess.cpp ServerIconExportUpdateProcess.cpp
StandardMetaDataJsonEventListener.cpp StandardMetaDataJsonEventListener.cpp
@@ -151,6 +169,7 @@ local applicationSources =
# util # util
AppUtils.cpp AppUtils.cpp
DataIOUtils.cpp DataIOUtils.cpp
LanguageMenuUtils.cpp
RepositoryUrlUtils.cpp RepositoryUrlUtils.cpp
StorageUtils.cpp StorageUtils.cpp
ToFileUrlProtocolListener.cpp ToFileUrlProtocolListener.cpp
@@ -173,6 +192,14 @@ local generatedRepositoryModelSourceFiles =
DumpExportRepositorySourceMirror.cpp DumpExportRepositorySourceMirror.cpp
; ;
local generatedReferenceModelSourceFiles =
DumpExportReference.cpp
DumpExportReferenceNaturalLanguage.cpp
DumpExportReferencePkgCategory.cpp
DumpExportReferenceUserRatingStability.cpp
DumpExportReferenceCountry.cpp
;
local generatedPkgParserSourceFiles = local generatedPkgParserSourceFiles =
DumpExportPkgJsonListener.cpp DumpExportPkgJsonListener.cpp
; ;
@@ -181,10 +208,19 @@ local generatedRepositoryParserSourceFiles =
DumpExportRepositoryJsonListener.cpp DumpExportRepositoryJsonListener.cpp
; ;
local generatedReferenceParserSourceFiles =
DumpExportReferenceJsonListener.cpp
;
Application HaikuDepot Application HaikuDepot
: $(applicationSources) $(textDocumentSources) : $(applicationSources)
$(generatedPkgModelSourceFiles) $(generatedRepositoryModelSourceFiles) $(textDocumentSources)
$(generatedPkgParserSourceFiles) $(generatedRepositoryParserSourceFiles) $(generatedPkgModelSourceFiles)
$(generatedRepositoryModelSourceFiles)
$(generatedReferenceModelSourceFiles)
$(generatedPkgParserSourceFiles)
$(generatedRepositoryParserSourceFiles)
$(generatedReferenceParserSourceFiles)
: be package bnetapi translation libcolumnlistview.a shared : be package bnetapi translation libcolumnlistview.a shared
[ TargetLibstdc++ ] [ TargetLibsupc++ ] localestub [ TargetLibstdc++ ] [ TargetLibsupc++ ] localestub
: HaikuDepot.rdef : HaikuDepot.rdef
@@ -225,12 +261,18 @@ HdsSchemaGenModel $(dumpExportPkgModelTargetFile)
HdsSchemaGenModel $(dumpExportRepositoryModelTargetFile) HdsSchemaGenModel $(dumpExportRepositoryModelTargetFile)
: dumpexportrepository.json : jsonschema2cppmodel.py ; : dumpexportrepository.json : jsonschema2cppmodel.py ;
HdsSchemaGenModel $(dumpExportReferenceModelTargetFile)
: dumpexportreference.json : jsonschema2cppmodel.py ;
HdsSchemaGenBulkParser $(dumpExportRepositoryBulkListerTargetFile) HdsSchemaGenBulkParser $(dumpExportRepositoryBulkListerTargetFile)
: dumpexportrepository.json : jsonschema2cppparser.py ; : dumpexportrepository.json : jsonschema2cppparser.py ;
HdsSchemaGenBulkParser $(dumpExportPkgBulkListenerTargetFile) HdsSchemaGenBulkParser $(dumpExportPkgBulkListenerTargetFile)
: dumpexportpkg.json : jsonschema2cppparser.py ; : dumpexportpkg.json : jsonschema2cppparser.py ;
HdsSchemaGenParser $(dumpExportReferenceListenerTargetFile)
: dumpexportreference.json : jsonschema2cppparser.py ;
HdsSchemaGenAppSrcDependsOnGeneration HdsSchemaGenAppSrcDependsOnGeneration
[ FGristFiles $(generatedPkgParserSourceFiles) ] [ FGristFiles $(generatedPkgParserSourceFiles) ]
[ FGristFiles $(generatedPkgParserSourceFiles:S=.h) ] [ FGristFiles $(generatedPkgParserSourceFiles:S=.h) ]
@@ -241,6 +283,11 @@ HdsSchemaGenAppSrcDependsOnGeneration
[ FGristFiles $(generatedRepositoryParserSourceFiles:S=.h) ] [ FGristFiles $(generatedRepositoryParserSourceFiles:S=.h) ]
: $(dumpExportRepositoryBulkListerTargetFile) ; : $(dumpExportRepositoryBulkListerTargetFile) ;
HdsSchemaGenAppSrcDependsOnGeneration
[ FGristFiles $(generatedReferenceParserSourceFiles) ]
[ FGristFiles $(generatedReferenceParserSourceFiles:S=.h) ]
: $(dumpExportReferenceListenerTargetFile) ;
HdsSchemaGenAppSrcDependsOnGeneration HdsSchemaGenAppSrcDependsOnGeneration
[ FGristFiles $(generatedRepositoryModelSourceFiles) ] [ FGristFiles $(generatedRepositoryModelSourceFiles) ]
[ FGristFiles $(generatedRepositoryModelSourceFiles:S=.h) ] [ FGristFiles $(generatedRepositoryModelSourceFiles:S=.h) ]
@@ -251,13 +298,20 @@ HdsSchemaGenAppSrcDependsOnGeneration
[ FGristFiles $(generatedPkgModelSourceFiles:S=.h) ] [ FGristFiles $(generatedPkgModelSourceFiles:S=.h) ]
: $(dumpExportPkgModelTargetFile) ; : $(dumpExportPkgModelTargetFile) ;
HdsSchemaGenAppSrcDependsOnGeneration
[ FGristFiles $(generatedReferenceModelSourceFiles) ]
[ FGristFiles $(generatedReferenceModelSourceFiles:S=.h) ]
: $(dumpExportReferenceModelTargetFile) ;
# This will ensure that if any of the generated files' header files change, then # This will ensure that if any of the generated files' header files change, then
# the application should be re-built. # the application should be re-built.
Depends [ FGristFiles $(applicationSources:S=.o) ] Depends [ FGristFiles $(applicationSources:S=.o) ]
: :
[ FGristFiles $(generatedPkgParserSourceFiles:S=.h) ] [ FGristFiles $(generatedPkgParserSourceFiles:S=.h) ]
[ FGristFiles $(generatedPkgModelSourceFiles:S=.h) ]
[ FGristFiles $(generatedRepositoryParserSourceFiles:S=.h) ] [ FGristFiles $(generatedRepositoryParserSourceFiles:S=.h) ]
[ FGristFiles $(generatedRepositoryModelSourceFiles:S=.h) ] [ FGristFiles $(generatedRepositoryModelSourceFiles:S=.h) ]
[ FGristFiles $(generatedPkgModelSourceFiles:S=.h) ] [ FGristFiles $(generatedReferenceParserSourceFiles:S=.h) ]
[ FGristFiles $(generatedReferenceModelSourceFiles:S=.h) ]
; ;
@@ -72,6 +72,29 @@ actions HdsSchemaGenBulkParser1
touch $(1) touch $(1)
} }
# pragma mark - Non-Bulk Parsing Class Generation
# 1 : the dummy file in the class generation directory (target)
# 2 : the JSON schema file
# 3 : the Python script to use
rule HdsSchemaGenParser
{
SEARCH on $(2) = [ FDirName $(SUBDIR) server schema ] ;
SEARCH on $(3) = [ FDirName $(SUBDIR) build scripts ] ;
Clean $(1:D) ;
Depends $(1) : $(2) $(3) ;
HdsSchemaGenParser1 $(1) : $(2) $(3) $(1:D) ;
}
actions HdsSchemaGenParser1
{
mkdir -p $(2[3])
$(HOST_PYTHON) $(2[2]) -i $(2[1]) --outputdirectory $(2[3])
touch $(1)
}
# pragma mark - Registering Generated Classes # pragma mark - Registering Generated Classes
# Because a number of .cpp and .h files will be generated from a single python # Because a number of .cpp and .h files will be generated from a single python
@@ -152,7 +152,27 @@ def writescalaraccessors(outputfile, cppclassname, cppname, cppmembername, cppty
string.Template(""" string.Template("""
${cpptype} ${cpptype}
${cppclassname}::${cppname}() ${cppclassname}::${cppname}()
{ {""").substitute(dict))
if cpptype == jscom.CPP_TYPE_BOOLEAN:
outputfile.write(string.Template("""
if (${cppname}IsNull())
return false;
""").substitute(dict))
if cpptype == jscom.CPP_TYPE_INTEGER:
outputfile.write(string.Template("""
if (${cppname}IsNull())
return 0;
""").substitute(dict))
if cpptype == jscom.CPP_TYPE_NUMBER:
outputfile.write(string.Template("""
if (${cppname}IsNull())
return 0.0;
""").substitute(dict))
outputfile.write(string.Template("""
return *${cppmembername}; return *${cppmembername};
} }
+168
View File
@@ -0,0 +1,168 @@
/*
* Copyright 2019, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "LanguageModel.h"
#include <Collator.h>
#include <Locale.h>
#include <LocaleRoster.h>
#include "HaikuDepotConstants.h"
#include "Logger.h"
static int32
LanguagesCompareFn(const LanguageRef& l1, const LanguageRef& l2)
{
const BLocale* locale = BLocaleRoster::Default()->GetDefaultLocale();
BCollator collator;
if (B_OK != locale->GetCollator(&collator)) {
debugger("unable to get the locale's collator");
}
BString name1;
BString name2;
if (l1->GetName(name1) == B_OK && l2->GetName(name2) == B_OK)
return collator.Compare(name1.String(), name2.String());
return collator.Compare(l1->Code(), l2->Code());
}
LanguageModel::LanguageModel()
:
fSupportedLanguages(LanguagesCompareFn, NULL),
fPreferredLanguage(LANGUAGE_DEFAULT)
{
const Language defaultLanguage = _DeriveDefaultLanguage();
fSupportedLanguages.Add(LanguageRef(
new Language(defaultLanguage)));
_SetPreferredLanguage(defaultLanguage);
}
LanguageModel::~LanguageModel()
{
}
void
LanguageModel::AddSupportedLanguages(const LanguageList& languages)
{
for (int32 i = 0; i < languages.CountItems(); i++) {
const LanguageRef language = languages.ItemAt(i);
int32 index = IndexOfSupportedLanguage(language->Code());
if (index == -1)
fSupportedLanguages.Add(language);
else
fSupportedLanguages.Replace(index, language);
}
// it could be that the preferred language does not exist in the
// list. In this case it is necessary to choose one from the list.
_SetPreferredLanguage(_DeriveDefaultLanguage());
}
void
LanguageModel::_SetPreferredLanguage(const Language& language)
{
fPreferredLanguage = language;
if(Logger::IsDebugEnabled())
printf("set preferred language [%s]\n", language.Code());
}
int32
LanguageModel::IndexOfSupportedLanguage(const BString& languageCode) const
{
for (int32 i = 0; i < fSupportedLanguages.CountItems(); i++) {
if (fSupportedLanguages.ItemAt(i)->Code() == languageCode)
return i;
}
return -1;
}
/*! This will derive the default language. If there are no other
possible languages configured then the default language will be
assumed to exist. Otherwise if there is a set of possible languages
then this method will ensure that the default language is in that
set.
*/
Language
LanguageModel::_DeriveDefaultLanguage() const
{
Language defaultLanguage = _DeriveSystemDefaultLanguage();
if(Logger::IsDebugEnabled()) {
printf("derived system default language [%s]\n",
defaultLanguage.Code());
}
// if there are no supported languages; as is the case to start with as the
// application starts, the default language from the system is used anyway.
// The data queried in HDS will handle the case where the language is not
// 'known' at the HDS end so it doesn't matter if it is invalid.
if (fSupportedLanguages.IsEmpty())
return defaultLanguage;
// if there are supported languages defined then the preferred language
// needs to be one of the supported ones.
Language* foundSupportedLanguage = _FindSupportedLanguage(
defaultLanguage.Code());
if (foundSupportedLanguage == NULL) {
printf("unable to find the language [%s] - looking for app default",
defaultLanguage.Code());
foundSupportedLanguage = _FindSupportedLanguage(
LANGUAGE_DEFAULT.Code());
}
if (foundSupportedLanguage == NULL) {
printf("unable to find the app default language - using the first "
"supported language");
foundSupportedLanguage = fSupportedLanguages.ItemAt(0);
}
return Language(*foundSupportedLanguage);
}
/*static*/ Language
LanguageModel::_DeriveSystemDefaultLanguage()
{
BLocaleRoster* localeRoster = BLocaleRoster::Default();
if (localeRoster != NULL) {
BMessage preferredLanguages;
if (localeRoster->GetPreferredLanguages(&preferredLanguages) == B_OK) {
BString language;
BString languageIso;
if (preferredLanguages.FindString(
"language", 0, &language) == B_OK) {
language.CopyInto(languageIso, 0, 2);
return Language(languageIso, languageIso, true);
}
}
}
return LANGUAGE_DEFAULT;
}
Language*
LanguageModel::_FindSupportedLanguage(const BString& code) const
{
int32 index = IndexOfSupportedLanguage(code);
if (-1 == index)
return NULL;
return fSupportedLanguages.ItemAt(index);
}
+47
View File
@@ -0,0 +1,47 @@
/*
* Copyright 2019, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef LANGUAGE_MODEL_H
#define LANGUAGE_MODEL_H
#include <Referenceable.h>
#include "List.h"
#include "PackageInfo.h"
typedef BReference<Language> LanguageRef;
typedef List<LanguageRef, false> LanguageList;
class LanguageModel {
public:
LanguageModel();
virtual ~LanguageModel();
const LanguageList& SupportedLanguages() const
{ return fSupportedLanguages; }
void AddSupportedLanguages(
const LanguageList& languages);
int32 IndexOfSupportedLanguage(
const BString& languageCode) const;
const Language& PreferredLanguage() const
{ return fPreferredLanguage; }
private:
static Language _DeriveSystemDefaultLanguage();
Language _DeriveDefaultLanguage() const;
Language* _FindSupportedLanguage(
const BString& code) const;
void _SetPreferredLanguage(const Language& language);
private:
LanguageList fSupportedLanguages;
Language fPreferredLanguage;
};
#endif // LANGUAGE_MODEL_H
+44 -47
View File
@@ -1,7 +1,7 @@
/* /*
* Copyright 2013-2014, Stephan Aßmus <[email protected]>. * Copyright 2013-2014, Stephan Aßmus <[email protected]>.
* Copyright 2014, Axel Dörfler <[email protected]>. * Copyright 2014, Axel Dörfler <[email protected]>.
* Copyright 2016-2018, Andrew Lindesay <[email protected]>. * Copyright 2016-2019, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -353,7 +353,6 @@ Model::Model()
fDepotFilter(""), fDepotFilter(""),
fSearchTermsFilter(PackageFilterRef(new AnyFilter(), true)), fSearchTermsFilter(PackageFilterRef(new AnyFilter(), true)),
fIsFeaturedFilter(), fIsFeaturedFilter(),
fShowFeaturedPackages(true), fShowFeaturedPackages(true),
fShowAvailablePackages(true), fShowAvailablePackages(true),
fShowInstalledPackages(true), fShowInstalledPackages(true),
@@ -378,38 +377,6 @@ Model::Model()
// get the defined categories and their translated names. // get the defined categories and their translated names.
// This should then be used instead of hard-coded // This should then be used instead of hard-coded
// categories and translations in the app. // categories and translations in the app.
fPreferredLanguage = "en";
BLocaleRoster* localeRoster = BLocaleRoster::Default();
if (localeRoster != NULL) {
BMessage preferredLanguages;
if (localeRoster->GetPreferredLanguages(&preferredLanguages) == B_OK) {
BString language;
if (preferredLanguages.FindString("language", 0, &language) == B_OK)
language.CopyInto(fPreferredLanguage, 0, 2);
}
}
// TODO: Fetch this from the web-app.
fSupportedLanguages.Add("en");
fSupportedLanguages.Add("es");
fSupportedLanguages.Add("de");
fSupportedLanguages.Add("fr");
fSupportedLanguages.Add("it");
fSupportedLanguages.Add("ja");
fSupportedLanguages.Add("pt");
fSupportedLanguages.Add("ru");
fSupportedLanguages.Add("sk");
fSupportedLanguages.Add("zh");
if (!fSupportedLanguages.Contains(fPreferredLanguage)) {
// Force the preferred language to one of the currently supported
// ones, until the web application supports all ISO language codes.
printf("User preferred language '%s' not currently supported, "
"defaulting to 'en'.\n", fPreferredLanguage.String());
fPreferredLanguage = "en";
}
fWebAppInterface.SetPreferredLanguage(fPreferredLanguage);
} }
@@ -418,6 +385,13 @@ Model::~Model()
} }
LanguageModel&
Model::Language()
{
return fLanguageModel;
}
bool bool
Model::AddListener(const ModelListenerRef& listener) Model::AddListener(const ModelListenerRef& listener)
{ {
@@ -903,6 +877,30 @@ Model::SetAuthorization(const BString& username, const BString& password,
} }
status_t
Model::_LocalDataPath(const BString leaf, BPath& path) const
{
BString leafAssembled(leaf);
leafAssembled.ReplaceAll("%languageCode%",
LanguageModel().PreferredLanguage().Code());
BPath repoDataPath;
if (find_directory(B_USER_CACHE_DIRECTORY, &repoDataPath) == B_OK
&& repoDataPath.Append("HaikuDepot") == B_OK
&& create_directory(repoDataPath.Path(), 0777) == B_OK
&& repoDataPath.Append(leafAssembled) == B_OK) {
path.SetTo(repoDataPath.Path());
return B_OK;
}
path.Unset();
fprintf(stdout, "unable to find the user cache file for [%s] data",
leaf.String());
return B_ERROR;
}
/*! When bulk repository data comes down from the server, it will /*! When bulk repository data comes down from the server, it will
arrive as a json.gz payload. This is stored locally as a cache arrive as a json.gz payload. This is stored locally as a cache
and this method will provide the on-disk storage location for and this method will provide the on-disk storage location for
@@ -912,20 +910,19 @@ Model::SetAuthorization(const BString& username, const BString& password,
status_t status_t
Model::DumpExportRepositoryDataPath(BPath& path) const Model::DumpExportRepositoryDataPath(BPath& path) const
{ {
BPath repoDataPath; return _LocalDataPath("repository-all_%languageCode%.json.gz", path);
}
if (find_directory(B_USER_CACHE_DIRECTORY, &repoDataPath) == B_OK
&& repoDataPath.Append("HaikuDepot") == B_OK
&& create_directory(repoDataPath.Path(), 0777) == B_OK
&& repoDataPath.Append("repository-all_en.json.gz") == B_OK) {
path.SetTo(repoDataPath.Path());
return B_OK;
}
path.Unset(); /*! When the system downloads reference data (eg; categories) from the server
fprintf(stdout, "unable to find the user cache file for repositories'" then the downloaded data is stored and cached at the path defined by this
" data"); method.
return B_ERROR; */
status_t
Model::DumpExportReferenceDataPath(BPath& path) const
{
return _LocalDataPath("reference-all_%languageCode%.json.gz", path);
} }
@@ -956,7 +953,7 @@ Model::DumpExportPkgDataPath(BPath& path,
BString leafName; BString leafName;
leafName.SetToFormat("pkg-all-%s-%s.json.gz", repositorySourceCode.String(), leafName.SetToFormat("pkg-all-%s-%s.json.gz", repositorySourceCode.String(),
fPreferredLanguage.String()); LanguageModel().PreferredLanguage().Code());
if (find_directory(B_USER_CACHE_DIRECTORY, &repoDataPath) == B_OK if (find_directory(B_USER_CACHE_DIRECTORY, &repoDataPath) == B_OK
&& repoDataPath.Append("HaikuDepot") == B_OK && repoDataPath.Append("HaikuDepot") == B_OK
+9 -10
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright 2013-2014, Stephan Aßmus <[email protected]>. * Copyright 2013-2014, Stephan Aßmus <[email protected]>.
* Copyright 2016-2018, Andrew Lindesay <[email protected]>. * Copyright 2016-2019, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef MODEL_H #ifndef MODEL_H
@@ -10,6 +10,7 @@
#include <Locker.h> #include <Locker.h>
#include "AbstractProcess.h" #include "AbstractProcess.h"
#include "LanguageModel.h"
#include "LocalIconStore.h" #include "LocalIconStore.h"
#include "PackageInfo.h" #include "PackageInfo.h"
#include "WebAppInterface.h" #include "WebAppInterface.h"
@@ -63,6 +64,8 @@ public:
Model(); Model();
virtual ~Model(); virtual ~Model();
LanguageModel& Language();
BLocker* Lock() BLocker* Lock()
{ return &fLock; } { return &fLock; }
@@ -150,12 +153,6 @@ public:
void PopulatePackage(const PackageInfoRef& package, void PopulatePackage(const PackageInfoRef& package,
uint32 flags); uint32 flags);
const StringList& SupportedLanguages() const
{ return fSupportedLanguages; }
const BString& PreferredLanguage() const
{ return fPreferredLanguage; }
void SetUsername(BString username); void SetUsername(BString username);
const BString& Username() const; const BString& Username() const;
void SetAuthorization(const BString& username, void SetAuthorization(const BString& username,
@@ -171,6 +168,7 @@ public:
void* context); void* context);
status_t IconStoragePath(BPath& path) const; status_t IconStoragePath(BPath& path) const;
status_t DumpExportReferenceDataPath(BPath& path) const;
status_t DumpExportRepositoryDataPath(BPath& path) const; status_t DumpExportRepositoryDataPath(BPath& path) const;
status_t DumpExportPkgDataPath(BPath& path, status_t DumpExportPkgDataPath(BPath& path,
const BString& repositorySourceCode) const; const BString& repositorySourceCode) const;
@@ -178,6 +176,9 @@ public:
void LogDepotsWithNoWebAppRepositoryCode() const; void LogDepotsWithNoWebAppRepositoryCode() const;
private: private:
status_t _LocalDataPath(const BString leaf,
BPath& path) const;
void _MaybeLogJsonRpcError( void _MaybeLogJsonRpcError(
const BMessage &responsePayload, const BMessage &responsePayload,
const char *sourceDescription) const; const char *sourceDescription) const;
@@ -245,9 +246,7 @@ private:
bool fShowSourcePackages; bool fShowSourcePackages;
bool fShowDevelopPackages; bool fShowDevelopPackages;
StringList fSupportedLanguages; LanguageModel fLanguageModel;
BString fPreferredLanguage;
WebAppInterface fWebAppInterface; WebAppInterface fWebAppInterface;
ModelListenerList fListeners; ModelListenerList fListeners;
+36 -1
View File
@@ -1,7 +1,7 @@
/* /*
* Copyright 2013-2014, Stephan Aßmus <[email protected]>. * Copyright 2013-2014, Stephan Aßmus <[email protected]>.
* Copyright 2013, Rene Gollent <[email protected]>. * Copyright 2013, Rene Gollent <[email protected]>.
* Copyright 2016-2018, Andrew Lindesay <[email protected]>. * Copyright 2016-2019, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -15,6 +15,41 @@
#include <Path.h> #include <Path.h>
// #pragma mark - Language
Language::Language(const char* language, const BString& serverName,
bool isPopular)
:
BLanguage(language),
fServerName(serverName),
fIsPopular(isPopular)
{
}
Language::Language(const Language& other)
:
BLanguage(other.Code()),
fServerName(other.fServerName),
fIsPopular(other.fIsPopular)
{
}
status_t
Language::GetName(BString& name,
const BLanguage* displayLanguage) const
{
status_t result = BLanguage::GetName(name, displayLanguage);
if (result == B_OK && (name.IsEmpty() || name == Code()))
name.SetTo(fServerName);
return result;
}
// #pragma mark - UserInfo // #pragma mark - UserInfo
+26 -1
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2016-2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2016-2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef PACKAGE_INFO_H #ifndef PACKAGE_INFO_H
@@ -9,6 +9,7 @@
#include <set> #include <set>
#include <Language.h>
#include <Referenceable.h> #include <Referenceable.h>
#include <package/PackageInfo.h> #include <package/PackageInfo.h>
@@ -21,6 +22,30 @@
class BPath; class BPath;
/*! This class represents a language that is supported by the Haiku
Depot Server system. This may differ from the set of languages
that are supported in the platform itself.
*/
class Language : public BReferenceable, public BLanguage {
public:
Language(const char* language,
const BString& serverName,
bool isPopular);
Language(const Language& other);
status_t GetName(BString& name,
const BLanguage* displayLanguage = NULL
) const;
bool IsPopular() const
{ return fIsPopular; }
private:
BString fServerName;
bool fIsPopular;
};
class UserInfo { class UserInfo {
public: public:
UserInfo(); UserInfo();
@@ -1,5 +1,5 @@
/* /*
* Copyright 2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2018-2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -21,6 +21,7 @@
#include "ServerHelper.h" #include "ServerHelper.h"
#include "ServerIconExportUpdateProcess.h" #include "ServerIconExportUpdateProcess.h"
#include "ServerPkgDataUpdateProcess.h" #include "ServerPkgDataUpdateProcess.h"
#include "ServerReferenceDataUpdateProcess.h"
#include "ServerRepositoryDataUpdateProcess.h" #include "ServerRepositoryDataUpdateProcess.h"
#include "ServerSettings.h" #include "ServerSettings.h"
@@ -62,6 +63,11 @@ ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
serverRepositoryDataUpdate->AddPredecessor(localPkgDataLoad); serverRepositoryDataUpdate->AddPredecessor(localPkgDataLoad);
processCoordinator->AddNode(serverRepositoryDataUpdate); processCoordinator->AddNode(serverRepositoryDataUpdate);
ProcessNode *serverReferenceDataUpdate =
new ProcessNode(new ServerReferenceDataUpdateProcess(model,
serverProcessOptions));
processCoordinator->AddNode(serverReferenceDataUpdate);
// create a process for each of the repositories that are configured on the // create a process for each of the repositories that are configured on the
// local system. Later, only those that have a web-app repository server // local system. Later, only those that have a web-app repository server
// code will be actually processed, but this means that the creation of the // code will be actually processed, but this means that the creation of the
@@ -74,9 +80,11 @@ ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
if (repoNamesResult == B_OK) { if (repoNamesResult == B_OK) {
for (int32 i = 0; i < repoNames.CountStrings(); i++) { for (int32 i = 0; i < repoNames.CountStrings(); i++) {
ProcessNode* processNode = new ProcessNode( ProcessNode* processNode = new ProcessNode(
new ServerPkgDataUpdateProcess(model->PreferredLanguage(), new ServerPkgDataUpdateProcess(
model->Language().PreferredLanguage().Code(),
repoNames.StringAt(i), model, serverProcessOptions)); repoNames.StringAt(i), model, serverProcessOptions));
processNode->AddPredecessor(serverRepositoryDataUpdate); processNode->AddPredecessor(serverRepositoryDataUpdate);
processNode->AddPredecessor(serverReferenceDataUpdate);
processCoordinator->AddNode(processNode); processCoordinator->AddNode(processNode);
} }
} else { } else {
@@ -0,0 +1,152 @@
/*
* Copyright 2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "ServerReferenceDataUpdateProcess.h"
#include <stdio.h>
#include <sys/stat.h>
#include <time.h>
#include <AutoDeleter.h>
#include <Catalog.h>
#include <FileIO.h>
#include <Url.h>
#include "ServerSettings.h"
#include "StorageUtils.h"
#include "Logger.h"
#include "DumpExportReference.h"
#include "DumpExportReferenceNaturalLanguage.h"
#include "DumpExportReferencePkgCategory.h"
#include "DumpExportReferenceUserRatingStability.h"
#include "DumpExportReferenceCountry.h"
#include "DumpExportReferenceJsonListener.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "ServerReferenceDataUpdateProcess"
ServerReferenceDataUpdateProcess::ServerReferenceDataUpdateProcess(
Model* model,
uint32 serverProcessOptions)
:
AbstractSingleFileServerProcess(serverProcessOptions),
fModel(model)
{
}
ServerReferenceDataUpdateProcess::~ServerReferenceDataUpdateProcess()
{
}
const char*
ServerReferenceDataUpdateProcess::Name() const
{
return "ServerReferenceDataUpdateProcess";
}
const char*
ServerReferenceDataUpdateProcess::Description() const
{
return B_TRANSLATE("Synchronizing reference data from server");
}
BString
ServerReferenceDataUpdateProcess::UrlPathComponent()
{
BString result;
result.SetToFormat("/__reference/all-%s.json.gz",
fModel->Language().PreferredLanguage().Code());
return result;
}
status_t
ServerReferenceDataUpdateProcess::GetLocalPath(BPath& path) const
{
return fModel->DumpExportReferenceDataPath(path);
}
status_t
ServerReferenceDataUpdateProcess::ProcessLocalData()
{
SingleDumpExportReferenceJsonListener* listener =
new SingleDumpExportReferenceJsonListener();
BPath localPath;
status_t result = GetLocalPath(localPath);
if (result != B_OK)
return result;
result = ParseJsonFromFileWithListener(listener, localPath);
if (result != B_OK)
return result;
result = listener->ErrorStatus();
if (result != B_OK)
return result;
return _ProcessData(listener->Target());
}
status_t
ServerReferenceDataUpdateProcess::_ProcessData(DumpExportReference* data)
{
// more to come here later...
return _ProcessNaturalLanguages(data);
}
status_t
ServerReferenceDataUpdateProcess::_ProcessNaturalLanguages(
DumpExportReference* data)
{
printf("[%s] will populate %" B_PRId32 " natural languages\n",
Name(), data->CountNaturalLanguages());
LanguageList result;
for (int32 i = 0; i < data->CountNaturalLanguages(); i++) {
DumpExportReferenceNaturalLanguage* naturalLanguage =
data->NaturalLanguagesItemAt(i);
result.Add(LanguageRef(new Language(
*(naturalLanguage->Code()),
*(naturalLanguage->Name()),
naturalLanguage->IsPopular())));
}
fModel->Language().AddSupportedLanguages(result);
printf("[%s] did add %" B_PRId32 " supported languages\n",
Name(), result.CountItems());
return B_OK;
}
status_t
ServerReferenceDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const
{
return GetLocalPath(path);
}
void
ServerReferenceDataUpdateProcess::GetStandardMetaDataJsonPath(
BString& jsonPath) const
{
jsonPath.SetTo("$.info");
}
@@ -0,0 +1,55 @@
/*
* Copyright 2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef SERVER_REFERENCE_DATA_UPDATE_PROCESS_H
#define SERVER_REFERENCE_DATA_UPDATE_PROCESS_H
#include "AbstractSingleFileServerProcess.h"
#include <File.h>
#include <Path.h>
#include <String.h>
#include <Url.h>
#include "Model.h"
#include "PackageInfo.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "ServerReferenceDataUpdateProcess"
class DumpExportReference;
class ServerReferenceDataUpdateProcess : public AbstractSingleFileServerProcess
{
public:
ServerReferenceDataUpdateProcess(
Model* model, uint32 serverProcessOptions);
virtual ~ServerReferenceDataUpdateProcess();
const char* Name() const;
const char* Description() const;
protected:
status_t GetStandardMetaDataPath(BPath& path) const;
void GetStandardMetaDataJsonPath(
BString& jsonPath) const;
BString UrlPathComponent();
status_t ProcessLocalData();
status_t GetLocalPath(BPath& path) const;
private:
status_t _ProcessData(DumpExportReference* data);
status_t _ProcessNaturalLanguages(
DumpExportReference* data);
private:
Model* fModel;
};
#endif // SERVER_REFERENCE_DATA_UPDATE_PROCESS_H
@@ -1,5 +1,5 @@
/* /*
* Copyright 2017-2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2017-2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -177,7 +177,10 @@ ServerRepositoryDataUpdateProcess::Description() const
BString BString
ServerRepositoryDataUpdateProcess::UrlPathComponent() ServerRepositoryDataUpdateProcess::UrlPathComponent()
{ {
return BString("/__repository/all-en.json.gz"); BString result;
result.SetToFormat("/__repository/all-%s.json.gz",
fModel->Language().PreferredLanguage().Code());
return result;
} }
+2 -15
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2016-2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2016-2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -271,8 +271,6 @@ enum {
WebAppInterface::WebAppInterface() WebAppInterface::WebAppInterface()
:
fLanguage("en")
{ {
} }
@@ -280,8 +278,7 @@ WebAppInterface::WebAppInterface()
WebAppInterface::WebAppInterface(const WebAppInterface& other) WebAppInterface::WebAppInterface(const WebAppInterface& other)
: :
fUsername(other.fUsername), fUsername(other.fUsername),
fPassword(other.fPassword), fPassword(other.fPassword)
fLanguage(other.fLanguage)
{ {
} }
@@ -296,11 +293,8 @@ WebAppInterface::operator=(const WebAppInterface& other)
{ {
if (this == &other) if (this == &other)
return *this; return *this;
fUsername = other.fUsername; fUsername = other.fUsername;
fPassword = other.fPassword; fPassword = other.fPassword;
fLanguage = other.fLanguage;
return *this; return *this;
} }
@@ -314,13 +308,6 @@ WebAppInterface::SetAuthorization(const BString& username,
} }
void
WebAppInterface::SetPreferredLanguage(const BString& language)
{
fLanguage = language;
}
status_t status_t
WebAppInterface::GetChangelog(const BString& packageName, BMessage& message) WebAppInterface::GetChangelog(const BString& packageName, BMessage& message)
{ {
+1 -5
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2016-2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2016-2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef WEB_APP_INTERFACE_H #ifndef WEB_APP_INTERFACE_H
@@ -51,9 +51,6 @@ public:
const BString& Username() const const BString& Username() const
{ return fUsername; } { return fUsername; }
void SetPreferredLanguage(const BString& language);
void SetArchitecture(const BString& architecture);
status_t GetChangelog( status_t GetChangelog(
const BString& packageName, const BString& packageName,
BMessage& message); BMessage& message);
@@ -130,7 +127,6 @@ private:
private: private:
BString fUsername; BString fUsername;
BString fPassword; BString fPassword;
BString fLanguage;
static int fRequestIndex; static int fRequestIndex;
}; };
@@ -0,0 +1,72 @@
{
"$schema": "http://json-schema.org/schema#",
"id": "http://depot.haiku-os.org/schema/reference/dumpreference.json",
"title": "Reference",
"javaType": "org.haiku.haikudepotserver.reference.model.dumpexport.DumpExportReference",
"type": "object",
"properties": {
"naturalLanguages": {
"type": "array",
"items": {
"type": "object",
"javaType": "org.haiku.haikudepotserver.reference.model.dumpexport.DumpExportReferenceNaturalLanguage",
"properties": {
"code": {
"type": "string"
},
"name": {
"type": "string"
},
"isPopular": {
"type": "boolean"
}
}
}
},
"pkgCategories": {
"type": "array",
"items": {
"type": "object",
"javaType": "org.haiku.haikudepotserver.reference.model.dumpexport.DumpExportReferencePkgCategory",
"properties": {
"code": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
},
"userRatingStabilities": {
"type": "array",
"items": {
"type": "object",
"javaType": "org.haiku.haikudepotserver.reference.model.dumpexport.DumpExportReferenceUserRatingStability",
"properties": {
"code": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
},
"countries": {
"type": "array",
"items": {
"type": "object",
"javaType": "org.haiku.haikudepotserver.reference.model.dumpexport.DumpExportReferenceCountry",
"properties": {
"code": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
}
}
}
+1 -27
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2018-2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -1050,8 +1050,6 @@ public:
.Add(scrollView, 1.0f) .Add(scrollView, 1.0f)
.SetInsets(B_USE_DEFAULT_SPACING, -1.0f, -1.0f, -1.0f) .SetInsets(B_USE_DEFAULT_SPACING, -1.0f, -1.0f, -1.0f)
; ;
_InitPreferredLanguages();
} }
virtual ~UserRatingsView() virtual ~UserRatingsView()
@@ -1113,33 +1111,9 @@ public:
} }
} }
private:
void _InitPreferredLanguages()
{
fPreferredLanguages.Clear();
BLocaleRoster* localeRoster = BLocaleRoster::Default();
if (localeRoster == NULL)
return;
BMessage preferredLanguages;
if (localeRoster->GetPreferredLanguages(&preferredLanguages) != B_OK)
return;
BString language;
int32 index = 0;
while (preferredLanguages.FindString("language", index++,
&language) == B_OK) {
BString languageCode;
language.CopyInto(languageCode, 0, 2);
fPreferredLanguages.Add(languageCode);
}
}
private: private:
BGroupLayout* fRatingContainerLayout; BGroupLayout* fRatingContainerLayout;
RatingSummaryView* fRatingSummaryView; RatingSummaryView* fRatingSummaryView;
StringList fPreferredLanguages;
}; };
+13 -29
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2016-2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2016-2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -22,6 +22,7 @@
#include <StringView.h> #include <StringView.h>
#include "HaikuDepotConstants.h" #include "HaikuDepotConstants.h"
#include "LanguageMenuUtils.h"
#include "MarkupParser.h" #include "MarkupParser.h"
#include "RatingView.h" #include "RatingView.h"
#include "ServerHelper.h" #include "ServerHelper.h"
@@ -37,7 +38,6 @@ enum {
MSG_SEND = 'send', MSG_SEND = 'send',
MSG_PACKAGE_RATED = 'rpkg', MSG_PACKAGE_RATED = 'rpkg',
MSG_STABILITY_SELECTED = 'stbl', MSG_STABILITY_SELECTED = 'stbl',
MSG_LANGUAGE_SELECTED = 'lngs',
MSG_RATING_ACTIVE_CHANGED = 'rtac', MSG_RATING_ACTIVE_CHANGED = 'rtac',
MSG_RATING_DETERMINATE_CHANGED = 'rdch' MSG_RATING_DETERMINATE_CHANGED = 'rdch'
}; };
@@ -180,19 +180,6 @@ add_stabilities_to_menu(const StabilityRatingList& stabilities, BMenu* menu)
} }
static void
add_languages_to_menu(const StringList& languages, BMenu* menu)
{
for (int i = 0; i < languages.CountItems(); i++) {
const BString& language = languages.ItemAtFast(i);
BMessage* message = new BMessage(MSG_LANGUAGE_SELECTED);
message->AddString("code", language);
BMenuItem* item = new BMenuItem(language, message);
menu->AddItem(item);
}
}
RatePackageWindow::RatePackageWindow(BWindow* parent, BRect frame, RatePackageWindow::RatePackageWindow(BWindow* parent, BRect frame,
Model& model) Model& model)
: :
@@ -204,7 +191,7 @@ RatePackageWindow::RatePackageWindow(BWindow* parent, BRect frame,
fTextEditor(new TextEditor(), true), fTextEditor(new TextEditor(), true),
fRating(RATING_NONE), fRating(RATING_NONE),
fRatingDeterminate(false), fRatingDeterminate(false),
fCommentLanguage(fModel.PreferredLanguage()), fCommentLanguageCode(fModel.Language().PreferredLanguage().Code()),
fWorkerThread(-1) fWorkerThread(-1)
{ {
AddToSubset(parent); AddToSubset(parent);
@@ -260,13 +247,12 @@ RatePackageWindow::RatePackageWindow(BWindow* parent, BRect frame,
fCommentLanguageField = new BMenuField("language", fCommentLanguageField = new BMenuField("language",
B_TRANSLATE("Comment language:"), languagesMenu); B_TRANSLATE("Comment language:"), languagesMenu);
add_languages_to_menu(fModel.SupportedLanguages(), languagesMenu); LanguageMenuUtils::AddLanguagesToMenu(
fModel.Language().SupportedLanguages(),
languagesMenu);
languagesMenu->SetTargetForItems(this); languagesMenu->SetTargetForItems(this);
LanguageMenuUtils::MarkLanguageInMenu(fCommentLanguageCode,
BMenuItem* defaultItem = languagesMenu->ItemAt( languagesMenu);
fModel.SupportedLanguages().IndexOf(fCommentLanguage));
if (defaultItem != NULL)
defaultItem->SetMarked(true);
fRatingActiveCheckBox = new BCheckBox("rating active", fRatingActiveCheckBox = new BCheckBox("rating active",
B_TRANSLATE("Other users can see this rating"), B_TRANSLATE("Other users can see this rating"),
@@ -348,7 +334,7 @@ RatePackageWindow::MessageReceived(BMessage* message)
break; break;
case MSG_LANGUAGE_SELECTED: case MSG_LANGUAGE_SELECTED:
message->FindString("code", &fCommentLanguage); message->FindString("code", &fCommentLanguageCode);
break; break;
case MSG_RATING_DETERMINATE_CHANGED: case MSG_RATING_DETERMINATE_CHANGED:
@@ -514,11 +500,9 @@ RatePackageWindow::_RelayServerDataToUI(BMessage& response)
item->SetMarked(true); item->SetMarked(true);
} }
if (response.FindString("naturalLanguageCode", if (response.FindString("naturalLanguageCode",
&fCommentLanguage) == B_OK) { &fCommentLanguageCode) == B_OK) {
BMenuItem* item = fCommentLanguageField->Menu()->ItemAt( LanguageMenuUtils::MarkLanguageInMenu(
fModel.SupportedLanguages().IndexOf(fCommentLanguage)); fCommentLanguageCode, fCommentLanguageField->Menu());
if (item != NULL)
item->SetMarked(true);
} }
double rating; double rating;
if (response.FindDouble("rating", &rating) == B_OK) { if (response.FindDouble("rating", &rating) == B_OK) {
@@ -649,7 +633,7 @@ RatePackageWindow::_SendRatingThread()
int rating = (int)fRating; int rating = (int)fRating;
BString stability = fStability; BString stability = fStability;
BString comment = fRatingText->Text(); BString comment = fRatingText->Text();
BString languageCode = fCommentLanguage; BString languageCode = fCommentLanguageCode;
BString ratingID = fRatingID; BString ratingID = fRatingID;
bool active = fRatingActive; bool active = fRatingActive;
+2 -2
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2018-2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef RATE_PACKAGE_WINDOW_H #ifndef RATE_PACKAGE_WINDOW_H
@@ -56,7 +56,7 @@ private:
bool fRatingDeterminate; bool fRatingDeterminate;
BString fStability; BString fStability;
StabilityRatingList fStabilityCodes; StabilityRatingList fStabilityCodes;
BString fCommentLanguage; BString fCommentLanguageCode;
BString fRatingID; BString fRatingID;
bool fRatingActive; bool fRatingActive;
PackageInfoRef fPackage; PackageInfoRef fPackage;
+14 -24
View File
@@ -1,5 +1,6 @@
/* /*
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -21,6 +22,8 @@
#include <UnicodeChar.h> #include <UnicodeChar.h>
#include "BitmapView.h" #include "BitmapView.h"
#include "HaikuDepotConstants.h"
#include "LanguageMenuUtils.h"
#include "Model.h" #include "Model.h"
#include "TabView.h" #include "TabView.h"
#include "WebAppInterface.h" #include "WebAppInterface.h"
@@ -34,31 +37,17 @@ enum {
MSG_SEND = 'send', MSG_SEND = 'send',
MSG_TAB_SELECTED = 'tbsl', MSG_TAB_SELECTED = 'tbsl',
MSG_CAPTCHA_OBTAINED = 'cpob', MSG_CAPTCHA_OBTAINED = 'cpob',
MSG_VALIDATE_FIELDS = 'vldt', MSG_VALIDATE_FIELDS = 'vldt'
MSG_LANGUAGE_SELECTED = 'lngs',
}; };
static void
add_languages_to_menu(const StringList& languages, BMenu* menu)
{
for (int i = 0; i < languages.CountItems(); i++) {
const BString& language = languages.ItemAtFast(i);
BMessage* message = new BMessage(MSG_LANGUAGE_SELECTED);
message->AddString("code", language);
BMenuItem* item = new BMenuItem(language, message);
menu->AddItem(item);
}
}
UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model) UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model)
: :
BWindow(frame, B_TRANSLATE("Log in"), BWindow(frame, B_TRANSLATE("Log in"),
B_FLOATING_WINDOW_LOOK, B_FLOATING_SUBSET_WINDOW_FEEL, B_FLOATING_WINDOW_LOOK, B_FLOATING_SUBSET_WINDOW_FEEL,
B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS
| B_NOT_RESIZABLE | B_NOT_ZOOMABLE), | B_NOT_RESIZABLE | B_NOT_ZOOMABLE),
fPreferredLanguage(model.PreferredLanguage()), fPreferredLanguageCode(model.Language().PreferredLanguage().Code()),
fModel(model), fModel(model),
fMode(NONE), fMode(NONE),
fWorkerThread(-1) fWorkerThread(-1)
@@ -83,14 +72,15 @@ UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model)
fLanguageCodeField = new BMenuField("language", fLanguageCodeField = new BMenuField("language",
B_TRANSLATE("Preferred language:"), languagesMenu); B_TRANSLATE("Preferred language:"), languagesMenu);
add_languages_to_menu(fModel.SupportedLanguages(), languagesMenu); LanguageMenuUtils::AddLanguagesToMenu(
fModel.Language().SupportedLanguages(),
languagesMenu);
languagesMenu->SetTargetForItems(this); languagesMenu->SetTargetForItems(this);
BMenuItem* defaultItem = languagesMenu->ItemAt( printf("using preferred language code [%s]\n",
fModel.SupportedLanguages().IndexOf(fPreferredLanguage)); fPreferredLanguageCode.String());
if (defaultItem != NULL) LanguageMenuUtils::MarkLanguageInMenu(fPreferredLanguageCode,
defaultItem->SetMarked(true); languagesMenu);
fEmailField = new BTextControl(B_TRANSLATE("Email address:"), "", NULL); fEmailField = new BTextControl(B_TRANSLATE("Email address:"), "", NULL);
fCaptchaView = new BitmapView("captcha view"); fCaptchaView = new BitmapView("captcha view");
@@ -218,7 +208,7 @@ UserLoginWindow::MessageReceived(BMessage* message)
break; break;
case MSG_LANGUAGE_SELECTED: case MSG_LANGUAGE_SELECTED:
message->FindString("code", &fPreferredLanguage); message->FindString("code", &fPreferredLanguageCode);
break; break;
default: default:
@@ -623,7 +613,7 @@ UserLoginWindow::_CreateAccountThread()
BString email(fEmailField->Text()); BString email(fEmailField->Text());
BString captchaToken(fCaptchaToken); BString captchaToken(fCaptchaToken);
BString captchaResponse(fCaptchaResultField->Text()); BString captchaResponse(fCaptchaResultField->Text());
BString languageCode(fPreferredLanguage); BString languageCode(fPreferredLanguageCode);
Unlock(); Unlock();
+2 -1
View File
@@ -1,5 +1,6 @@
/* /*
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef USER_LOGIN_WINDOW_H #ifndef USER_LOGIN_WINDOW_H
@@ -84,7 +85,7 @@ private:
BString fCaptchaToken; BString fCaptchaToken;
BitmapRef fCaptchaImage; BitmapRef fCaptchaImage;
BString fPreferredLanguage; BString fPreferredLanguageCode;
Model& fModel; Model& fModel;
+1 -1
View File
@@ -9,10 +9,10 @@
#include <string.h> #include <string.h>
#include <Application.h> #include <Application.h>
#include <Messenger.h>
#include "HaikuDepotConstants.h" #include "HaikuDepotConstants.h"
/*! This method can be called to pop up an error in the user interface; /*! This method can be called to pop up an error in the user interface;
typically in a background thread. typically in a background thread.
*/ */
@@ -0,0 +1,137 @@
/*
* Copyright 2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "LanguageMenuUtils.h"
#include <string.h>
#include <Application.h>
#include <MenuItem.h>
#include <Messenger.h>
#include "HaikuDepotConstants.h"
#include "Logger.h"
/*! This method will add the supplied languages to the menu. It will
add first the popular languages, followed by a separator and then
other less popular languages.
*/
/* static */ void
LanguageMenuUtils::AddLanguagesToMenu(
const LanguageList& languages, BMenu* menu)
{
if (languages.IsEmpty())
printf("there are no languages defined\n");
int32 addedPopular = LanguageMenuUtils::_AddLanguagesToMenu(
languages, menu, true);
if (addedPopular > 0)
menu->AddSeparatorItem();
int32 addedNonPopular = LanguageMenuUtils::_AddLanguagesToMenu(
languages, menu, false);
if (Logger::IsDebugEnabled()) {
printf("did add %" B_PRId32 " popular languages and %" B_PRId32
" non-popular languages to a menu\n", addedPopular,
addedNonPopular);
}
}
/* static */ void
LanguageMenuUtils::MarkLanguageInMenu(
const BString& languageCode, BMenu* menu) {
if (menu->CountItems() == 0) {
debugger("menu contains no items; not able to set the "
"language");
return;
}
int32 index = LanguageMenuUtils::_IndexOfLanguageInMenu(
languageCode, menu);
if (index == -1) {
printf("unable to find the language [%s] in the menu\n",
languageCode.String());
menu->ItemAt(0)->SetMarked(true);
}
else
menu->ItemAt(index)->SetMarked(true);
}
/* static */ void
LanguageMenuUtils::_AddLanguageToMenu(
const BString& code, const BString& name, BMenu* menu)
{
BMessage* message = new BMessage(MSG_LANGUAGE_SELECTED);
message->AddString("code", code);
BMenuItem* item = new BMenuItem(name, message);
menu->AddItem(item);
}
/* static */ void
LanguageMenuUtils::_AddLanguageToMenu(
const LanguageRef& language, BMenu* menu)
{
BString name;
if (language->GetName(name) != B_OK || name.IsEmpty())
name.SetTo("???");
LanguageMenuUtils::_AddLanguageToMenu(language->Code(), name, menu);
}
/* static */ int32
LanguageMenuUtils::_AddLanguagesToMenu(const LanguageList& languages,
BMenu* menu, bool isPopular)
{
int32 count = 0;
for (int32 i = 0; i < languages.CountItems(); i++) {
const LanguageRef language = languages.ItemAtFast(i);
if (language->IsPopular() == isPopular) {
LanguageMenuUtils::_AddLanguageToMenu(language, menu);
count++;
}
}
return count;
}
/* static */ status_t
LanguageMenuUtils::_GetLanguageAtIndexInMenu(BMenu* menu, int32 index,
BString* result)
{
BMessage *itemMessage = menu->ItemAt(index)->Message();
if (itemMessage == NULL)
return B_ERROR;
return itemMessage->FindString("code", result);
}
/* static */ int32
LanguageMenuUtils::_IndexOfLanguageInMenu(
const BString& languageCode, BMenu* menu)
{
BString itemLanguageCode;
for (int32 i = 0; i < menu->CountItems(); i++) {
if (_GetLanguageAtIndexInMenu(
menu, i, &itemLanguageCode) == B_OK) {
if (itemLanguageCode == languageCode) {
return i;
}
}
}
return -1;
}
@@ -0,0 +1,43 @@
/*
* Copyright 2019, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef LANGUAGE_MENU_UTILS_H
#define LANGUAGE_MENU_UTILS_H
#include <Menu.h>
#include "Model.h"
#include "PackageInfo.h"
class LanguageMenuUtils {
public:
static void AddLanguagesToMenu(
const LanguageList& languages,
BMenu* menu);
static void MarkLanguageInMenu(
const BString& languageCode,
BMenu* menu);
private:
static int32 _IndexOfLanguageInMenu(
const BString& languageCode,
BMenu* menu);
static status_t _GetLanguageAtIndexInMenu(BMenu* menu,
int32 index, BString* result);
static int32 _AddLanguagesToMenu(
const LanguageList& languages,
BMenu* menu, bool isPopular);
static void _AddLanguageToMenu(
const LanguageRef& language,
BMenu* menu);
static void _AddLanguageToMenu(
const BString& code,
const BString& name, BMenu* menu);
};
#endif // LANGUAGE_MENU_UTILS_H