an example of using constexpr array for data

simplifies code and removes the need for a class.
This commit is contained in:
berniev
2023-02-23 03:34:30 +10:00
committed by wwmayer
parent 5e77365c0d
commit 0a5e59adae
8 changed files with 132 additions and 280 deletions

View File

@@ -166,7 +166,6 @@ SET(Document_CPP_SRCS
TextDocument.cpp
Link.cpp
LinkBaseExtensionPyImp.cpp
License.cpp
License.h
)

View File

@@ -779,8 +779,8 @@ void Document::setTransactionMode(int iMode)
//--------------------------------------------------------------------------
// constructor
//--------------------------------------------------------------------------
Document::Document(const char *name)
: myName(name)
Document::Document(const char* documentName)
: myName(documentName)
{
// Remark: In a constructor we should never increment a Python object as we cannot be sure
// if the Python interpreter gets a reference of it. E.g. if we increment but Python don't
@@ -795,15 +795,29 @@ Document::Document(const char *name)
Console().Log("+App::Document: %p\n", this);
#endif
std::string CreationDateString = Base::TimeInfo::currentDateTimeString();
std::string Author = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document")->GetASCII("prefAuthor", "");
std::string AuthorComp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document")->GetASCII("prefCompany", "");
std::string Author = App::GetApplication()
.GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document")
->GetASCII("prefAuthor", "");
std::string AuthorComp =
App::GetApplication()
.GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document")
->GetASCII("prefCompany", "");
ADD_PROPERTY_TYPE(Label, ("Unnamed"), 0, Prop_None, "The name of the document");
ADD_PROPERTY_TYPE(FileName, (""), 0, PropertyType(Prop_Transient | Prop_ReadOnly), "The path to the file where the document is saved to");
ADD_PROPERTY_TYPE(FileName,
(""),
0,
PropertyType(Prop_Transient | Prop_ReadOnly),
"The path to the file where the document is saved to");
ADD_PROPERTY_TYPE(CreatedBy, (Author.c_str()), 0, Prop_None, "The creator of the document");
ADD_PROPERTY_TYPE(CreationDate, (CreationDateString.c_str()), 0, Prop_ReadOnly, "Date of creation");
ADD_PROPERTY_TYPE(
CreationDate, (CreationDateString.c_str()), 0, Prop_ReadOnly, "Date of creation");
ADD_PROPERTY_TYPE(LastModifiedBy, (""), 0, Prop_None, 0);
ADD_PROPERTY_TYPE(LastModifiedDate, ("Unknown"), 0, Prop_ReadOnly, "Date of last modification");
ADD_PROPERTY_TYPE(Company, (AuthorComp.c_str()), 0, Prop_None, "Additional tag to save the name of the company");
ADD_PROPERTY_TYPE(Company,
(AuthorComp.c_str()),
0,
Prop_None,
"Additional tag to save the name of the company");
ADD_PROPERTY_TYPE(Comment, (""), 0, Prop_None, "Additional tag to save a comment");
ADD_PROPERTY_TYPE(Meta, (), 0, Prop_None, "Map with additional meta information");
ADD_PROPERTY_TYPE(Material, (), 0, Prop_None, "Map with material properties");
@@ -813,23 +827,34 @@ Document::Document(const char *name)
ADD_PROPERTY_TYPE(Uid, (id), 0, Prop_ReadOnly, "UUID of the document");
// license stuff
long licenseId = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document")->GetInt("prefLicenseType", 0);
App::License licenseType{licenseId};
std::string license = licenseType.getLicense();
std::string licenseUrl = licenseType.getUrl();
licenseUrl = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document")->GetASCII("prefLicenseUrl", licenseUrl.c_str());
auto paramGrp {App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Document")};
auto index = static_cast<int>(paramGrp->GetInt("prefLicenseType", 0));
const char* name = App::licenseItems.at(index).at(App::posnOfFullName);
const char* url = App::licenseItems.at(index).at(App::posnOfUrl);
std::string licenseUrl = (paramGrp->GetASCII("prefLicenseUrl", url));
ADD_PROPERTY_TYPE(License, (license.c_str()), 0, Prop_None, "License string of the Item");
ADD_PROPERTY_TYPE(LicenseURL, (licenseUrl.c_str()), 0, Prop_None, "URL to the license text/contract");
ADD_PROPERTY_TYPE(ShowHidden, (false), 0, PropertyType(Prop_None),
ADD_PROPERTY_TYPE(License, (name), 0, Prop_None, "License string of the Item");
ADD_PROPERTY_TYPE(
LicenseURL, (licenseUrl.c_str()), 0, Prop_None, "URL to the license text/contract");
ADD_PROPERTY_TYPE(ShowHidden,
(false),
0,
PropertyType(Prop_None),
"Whether to show hidden object items in the tree view");
// this creates and sets 'TransientDir' in onChanged()
ADD_PROPERTY_TYPE(TransientDir, (""), 0, PropertyType(Prop_Transient | Prop_ReadOnly),
ADD_PROPERTY_TYPE(TransientDir,
(""),
0,
PropertyType(Prop_Transient | Prop_ReadOnly),
"Transient directory, where the files live while the document is open");
ADD_PROPERTY_TYPE(Tip, (nullptr), 0, PropertyType(Prop_Transient),
"Link of the tip object of the document");
ADD_PROPERTY_TYPE(TipName, (""), 0, PropertyType(Prop_Hidden | Prop_ReadOnly),
ADD_PROPERTY_TYPE(
Tip, (nullptr), 0, PropertyType(Prop_Transient), "Link of the tip object of the document");
ADD_PROPERTY_TYPE(TipName,
(""),
0,
PropertyType(Prop_Hidden | Prop_ReadOnly),
"Link of the tip object of the document");
Uid.touch();
}

View File

@@ -98,10 +98,7 @@ public:
PropertyString Id;
/// unique identifier of the document
PropertyUUID Uid;
/** License string
* Holds the short license string for the Item, e.g. CC-BY
* for the Creative Commons license suit.
*/
/// Full name of the licence e.g. "Creative Commons Attribution". See https://spdx.org/licenses/
App::PropertyString License;
/// License description/contract URL
App::PropertyString LicenseURL;
@@ -520,7 +517,7 @@ public:
protected:
/// Construction
explicit Document(const char *name = "");
explicit Document(const char *documentName = "");
void _removeObject(DocumentObject* pcObject);
void _addObject(DocumentObject* pcObject, const char* pObjectName);

View File

@@ -1,115 +0,0 @@
/***************************************************************************
* Copyright (c) 2023 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <algorithm>
# include <iterator>
#endif
#include "License.h"
using namespace App;
std::map<License::Type, License::LicenseItem> License::licenseItems;
License::License(License::Type type)
: type{type}
{
init();
}
License::License(long id)
: type{static_cast<Type>(id)}
{
if (id < 0 || id > static_cast<long>(Type::Other)) {
type = Type::Other;
}
init();
}
License::License(int id)
: License(static_cast<long>(id))
{
}
void License::init()
{
static bool first = true;
if (!first)
return;
first = false;
licenseItems[Type::AllRightsReserved] = LicenseItem{"All rights reserved",
"https://en.wikipedia.org/wiki/All_rights_reserved"};
licenseItems[Type::CC_BY_40] = LicenseItem{"Creative Commons Attribution",
"https://creativecommons.org/licenses/by/4.0/"};
licenseItems[Type::CC_BY_SA_40] = LicenseItem{"Creative Commons Attribution-ShareAlike",
"https://creativecommons.org/licenses/by-sa/4.0/"};
licenseItems[Type::CC_BY_ND_40] = LicenseItem{"Creative Commons Attribution-NoDerivatives",
"https://creativecommons.org/licenses/by-nd/4.0/"};
licenseItems[Type::CC_BY_NC_40] = LicenseItem{"Creative Commons Attribution-NonCommercial",
"https://creativecommons.org/licenses/by-nc/4.0/"};
licenseItems[Type::CC_BY_NC_SA_40] = LicenseItem{"Creative Commons Attribution-NonCommercial-ShareAlike",
"https://creativecommons.org/licenses/by-nc-sa/4.0/"};
licenseItems[Type::CC_BY_NC_ND_40] = LicenseItem{"Creative Commons Attribution-NonCommercial-NoDerivatives",
"https://creativecommons.org/licenses/by-nc-nd/4.0/"};
licenseItems[Type::PublicDomain] = LicenseItem{"Public Domain",
"https://en.wikipedia.org/wiki/Public_domain"};
licenseItems[Type::FreeArt] = LicenseItem{"FreeArt", "https://artlibre.org/licence/lal"};
licenseItems[Type::CERN_OHS_S] = LicenseItem{"CERN Open Hardware Licence strongly-reciprocal",
"https://cern-ohl.web.cern.ch/"};
licenseItems[Type::CERN_OHS_W] = LicenseItem{"CERN Open Hardware Licence weakly-reciprocal",
"https://cern-ohl.web.cern.ch/"};
licenseItems[Type::CERN_OHS_P] = LicenseItem{"CERN Open Hardware Licence permissive",
"https://cern-ohl.web.cern.ch/"};
licenseItems[Type::Other] = LicenseItem{"Other", ""};
}
License::Type License::getType() const
{
return type;
}
std::string License::getLicense() const
{
return licenseItems.at(type).license;
}
std::string License::getUrl() const
{
return licenseItems.at(type).url;
}
std::vector<std::string> License::getLicenses()
{
init();
std::vector<std::string> output;
output.reserve(licenseItems.size());
using Value = std::pair<Type, LicenseItem>;
std::transform(licenseItems.cbegin(), licenseItems.cend(), std::back_inserter(output), [](const Value& val) {
return val.second.license;
});
return output;
}

View File

@@ -24,57 +24,48 @@
#define APP_LICENSE_H
#include <FCGlobal.h>
#include <array>
#include <string>
#include <map>
#include <vector>
namespace App {
/*!
* \brief The License class
* Handling of standard licenses.
*/
class License
namespace App
{
public:
enum class Type {
AllRightsReserved,
CC_BY_40,
CC_BY_SA_40,
CC_BY_ND_40,
CC_BY_NC_40,
CC_BY_NC_SA_40,
CC_BY_NC_ND_40,
PublicDomain,
FreeArt,
CERN_OHS_S,
CERN_OHS_W,
CERN_OHS_P,
Other
};
AppExport explicit License(Type);
AppExport explicit License(long);
AppExport explicit License(int);
AppExport Type getType() const;
AppExport std::string getLicense() const;
AppExport std::string getUrl() const;
AppExport static std::vector<std::string> getLicenses();
private:
static void init();
struct LicenseItem
{
std::string license;
std::string url;
};
Type type;
static std::map<Type, LicenseItem> licenseItems;
};
/**
* Licenses data [identifier, fullName, url]
* See also https://spdx.org/licenses/
*/
constexpr int colsInArray = 3;
using TLicenseArr = std::array<const char*, colsInArray>;
constexpr int posnOfIdentifier = 0;
constexpr int posnOfFullName = 1;
constexpr int posnOfUrl = 2;
constexpr int countOfLicenses {12};
// clang-format off
constexpr std::array<TLicenseArr, countOfLicenses> licenseItems {{
{ "AllRightsReserved", "All rights reserved", "https://en.wikipedia.org/wiki/All_rights_reserved" },
{ "CC_BY_40", "Creative Commons Attribution", "https://creativecommons.org/licenses/by/4.0/" },
{ "CC_BY_SA_40", "Creative Commons Attribution-ShareAlike", "https://creativecommons.org/licenses/by-sa/4.0/" },
{ "CC_BY_ND_40", "Creative Commons Attribution-NoDerivatives", "https://creativecommons.org/licenses/by-nd/4.0/" },
{ "CC_BY_NC_40", "Creative Commons Attribution-NonCommercial", "https://creativecommons.org/licenses/by-nc/4.0/" },
{ "CC_BY_NC_SA_40", "Creative Commons Attribution-NonCommercial-ShareAlike", "https://creativecommons.org/licenses/by-nc-sa/4.0/" },
{ "CC_BY_NC_ND_40", "Creative Commons Attribution-NonCommercial-NoDerivatives", "https://creativecommons.org/licenses/by-nc-nd/4.0/" },
{ "PublicDomain", "Public Domain", "https://en.wikipedia.org/wiki/Public_domain" },
{ "FreeArt", "FreeArt", "https://artlibre.org/licence/lal" },
{ "CERN_OHS_S", "CERN Open Hardware Licence strongly-reciprocal", "https://cern-ohl.web.cern.ch/" },
{ "CERN_OHS_W", "CERN Open Hardware Licence weakly-reciprocal", "https://cern-ohl.web.cern.ch/" },
{ "CERN_OHS_P", "CERN Open Hardware Licence permissive", "https://cern-ohl.web.cern.ch/" },
}};
// clang-format on
int constexpr findLicense(const char* identifier)
{
for (int i = 0; i < countOfLicenses; i++) {
if (licenseItems.at(i).at(posnOfIdentifier) == identifier) {
return i;
}
}
return -1;
}
}// namespace App
#endif // APP_LICENSE_H
#endif// APP_LICENSE_H

View File

@@ -76,12 +76,14 @@ DlgProjectInformationImp::DlgProjectInformationImp(App::Document* doc, QWidget*
ui->lineEditLastModDate->setText(QString::fromUtf8(doc->LastModifiedDate.getValue()));
ui->lineEditCompany->setText(QString::fromUtf8(doc->Company.getValue()));
auto rawLicenses = App::License::getLicenses();
for (const auto& it : rawLicenses) {
QString text = QApplication::translate("Gui::Dialog::DlgSettingsDocument", it.c_str());
ui->comboLicense->addItem(text, QByteArray(it.c_str()));
// load comboBox with license names
for (const auto& item : App::licenseItems) {
const char* name {item.at(App::posnOfFullName)};
QString translated = QApplication::translate("Gui::Dialog::DlgSettingsDocument", name);
ui->comboLicense->addItem(translated, QByteArray(name));
}
// set default position to match document
int index = ui->comboLicense->findData(QByteArray(doc->License.getValue()));
if (index >= 0) {
ui->comboLicense->setCurrentIndex(index);
@@ -128,10 +130,12 @@ void DlgProjectInformationImp::accept()
_doc->CreatedBy.setValue(ui->lineEditCreator->text().toUtf8());
_doc->LastModifiedBy.setValue(ui->lineEditCreator->text().toUtf8());
_doc->Company.setValue(ui->lineEditCompany->text().toUtf8());
QByteArray license = ui->comboLicense->itemData(ui->comboLicense->currentIndex()).toByteArray();
if (license.isEmpty())
license = ui->comboLicense->itemText(ui->comboLicense->currentIndex()).toUtf8();
_doc->License.setValue(license);
QByteArray licenseName {ui->comboLicense->currentData().toByteArray()};
// Is this really necessary?
if (licenseName.isEmpty()) {
licenseName = ui->comboLicense->currentText().toUtf8();
}
_doc->License.setValue(licenseName);
_doc->LicenseURL.setValue(ui->lineEditLicenseURL->text().toUtf8());
// Replace newline escape sequence through '\\n' string
@@ -149,13 +153,10 @@ void DlgProjectInformationImp::accept()
void DlgProjectInformationImp::onLicenseTypeChanged(int index)
{
App::License license{index};
std::string url = license.getUrl();
if (license.getType() == App::License::Type::Other) {
url = _doc->LicenseURL.getValue();
}
const char* url {index >= 0 && index < App::countOfLicenses ? App::licenseItems.at(index).at(App::posnOfUrl)
: _doc->LicenseURL.getValue()};
ui->lineEditLicenseURL->setText(QString::fromStdString(url));
ui->lineEditLicenseURL->setText(QString::fromLatin1(url));
}
/**

View File

@@ -151,28 +151,33 @@ void DlgSettingsDocumentImp::changeEvent(QEvent *e)
void DlgSettingsDocumentImp::addLicenseTypes()
{
auto add = [&](const char* what) {
ui->prefLicenseType->addItem(
QApplication::translate("Gui::Dialog::DlgSettingsDocument", what));
};
ui->prefLicenseType->clear();
auto rawLicenses = App::License::getLicenses();
for (const auto& it : rawLicenses) {
QString text = QApplication::translate("Gui::Dialog::DlgSettingsDocument", it.c_str());
ui->prefLicenseType->addItem(text);
for (const auto& licenseItem : App::licenseItems) {
add(licenseItem.at(App::posnOfFullName));
}
add("Other");
}
/**
* Set the correct URL depending on the license type
* Fix Url according to changed type
*/
void DlgSettingsDocumentImp::onLicenseTypeChanged(int index)
{
App::License license{index};
std::string url = license.getUrl();
if (license.getType() == App::License::Type::Other) {
ui->prefLicenseUrl->clear();
ui->prefLicenseUrl->setReadOnly(false);
if (index >= 0 && index < App::countOfLicenses) {
// existing license
const char* url {App::licenseItems.at(index).at(App::posnOfUrl)};
ui->prefLicenseUrl->setText(QString::fromLatin1(url));
ui->prefLicenseUrl->setReadOnly(true);
}
else {
ui->prefLicenseUrl->setReadOnly(true);
ui->prefLicenseUrl->setText(QString::fromStdString(url));
// Other
ui->prefLicenseUrl->clear();
ui->prefLicenseUrl->setReadOnly(false);
}
}

View File

@@ -2,83 +2,32 @@
#include "App/License.h"
TEST(License, AllRightsReserved)
TEST(License, isLicenseYesStr)
{
auto lic = App::License{App::License::Type::AllRightsReserved};
ASSERT_EQ(lic.getType(), App::License::Type::AllRightsReserved);
ASSERT_EQ(lic.getLicense(), "All rights reserved");
ASSERT_EQ(lic.getUrl(), "https://en.wikipedia.org/wiki/All_rights_reserved");
EXPECT_EQ(App::findLicense("CC_BY_40"), 1);
}
TEST(License, CC_BY_40)
TEST(License, UnknownIdentifier)
{
auto lic = App::License{App::License::Type::CC_BY_40};
ASSERT_EQ(lic.getType(), App::License::Type::CC_BY_40);
ASSERT_EQ(lic.getLicense(), "Creative Commons Attribution");
ASSERT_EQ(lic.getUrl(), "https://creativecommons.org/licenses/by/4.0/");
int index {App::findLicense("junk")};
EXPECT_EQ(index, -1);
}
TEST(License, CC_BY_SA_40)
TEST(License, direct)
{
auto lic = App::License{App::License::Type::CC_BY_SA_40};
ASSERT_EQ(lic.getType(), App::License::Type::CC_BY_SA_40);
ASSERT_EQ(lic.getLicense(), "Creative Commons Attribution-ShareAlike");
ASSERT_EQ(lic.getUrl(), "https://creativecommons.org/licenses/by-sa/4.0/");
int posn {App::findLicense("CC_BY_40")};
App::TLicenseArr tt {
"CC_BY_40", "Creative Commons Attribution", "https://creativecommons.org/licenses/by/4.0/"};
EXPECT_EQ(App::licenseItems.at(posn), tt);
}
TEST(License, PublicDomain)
TEST(License, findLicenseByIdent)
{
auto lic = App::License{App::License::Type::PublicDomain};
ASSERT_EQ(lic.getType(), App::License::Type::PublicDomain);
ASSERT_EQ(lic.getLicense(), "Public Domain");
ASSERT_EQ(lic.getUrl(), "https://en.wikipedia.org/wiki/Public_domain");
App::TLicenseArr arr {App::licenseItems.at(App::findLicense("CC_BY_40"))};
EXPECT_STREQ(arr.at(App::posnOfIdentifier), "CC_BY_40");
EXPECT_STREQ(arr.at(App::posnOfFullName), "Creative Commons Attribution");
EXPECT_STREQ(arr.at(App::posnOfUrl), "https://creativecommons.org/licenses/by/4.0/");
}
TEST(License, FreeArt)
{
auto lic = App::License{App::License::Type::FreeArt};
ASSERT_EQ(lic.getType(), App::License::Type::FreeArt);
ASSERT_EQ(lic.getLicense(), "FreeArt");
ASSERT_EQ(lic.getUrl(), "https://artlibre.org/licence/lal");
}
TEST(License, CERN_OHS_S)
{
auto lic = App::License{App::License::Type::CERN_OHS_S};
ASSERT_EQ(lic.getType(), App::License::Type::CERN_OHS_S);
ASSERT_EQ(lic.getLicense(), "CERN Open Hardware Licence strongly-reciprocal");
ASSERT_EQ(lic.getUrl(), "https://cern-ohl.web.cern.ch/");
}
TEST(License, Other)
{
auto lic = App::License{App::License::Type::Other};
ASSERT_EQ(lic.getType(), App::License::Type::Other);
ASSERT_EQ(lic.getLicense(), "Other");
ASSERT_EQ(lic.getUrl(), "");
}
TEST(License, CompareTypeWithInt)
{
auto lic1 = App::License{App::License::Type::Other};
auto lic2 = App::License{static_cast<int>(App::License::Type::Other)};
ASSERT_EQ(lic1.getType(), lic2.getType());
}
TEST(License, CompareTypeWithLong)
{
auto lic1 = App::License{App::License::Type::CC_BY_NC_ND_40};
auto lic2 = App::License{static_cast<long>(App::License::Type::CC_BY_NC_ND_40)};
ASSERT_EQ(lic1.getType(), lic2.getType());
}
TEST(License, All)
{
std::vector<std::string> all = App::License::getLicenses();
int num = static_cast<int>(all.size());
for (int index = 0; index < num; index++) {
auto lic = App::License{index};
auto text = all.at(index);
ASSERT_EQ(lic.getLicense(), text);
}
}