Merge branch 'master' into path_custom_source

This commit is contained in:
Morgan 'ARR!' Allen
2023-03-15 01:17:35 -07:00
committed by GitHub
36 changed files with 1488 additions and 413 deletions

View File

@@ -261,6 +261,7 @@ SET(FreeCADApp_CPP_SRCS
ComplexGeoData.cpp
ComplexGeoDataPyImp.cpp
Enumeration.cpp
IndexedName.cpp
Material.cpp
MaterialPyImp.cpp
Metadata.cpp
@@ -277,6 +278,7 @@ SET(FreeCADApp_HPP_SRCS
ColorModel.h
ComplexGeoData.h
Enumeration.h
IndexedName.h
Material.h
Metadata.h
)

122
src/App/IndexedName.cpp Normal file
View File

@@ -0,0 +1,122 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* Copyright (c) 2022 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
* Copyright (c) 2023 FreeCAD Project Association *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
// NOLINTNEXTLINE
#include "PreCompiled.h"
#ifndef _PreComp_
# include <cstdlib>
# include <unordered_set>
#endif
#include "IndexedName.h"
using namespace Data;
/// Check whether the input character is an underscore or an ASCII letter a-Z or A-Z
inline bool isInvalidChar(char test)
{
return test != '_' && (test < 'a' || test > 'z' ) && (test < 'A' || test > 'Z');
}
/// Get the integer suffix of name. Returns a tuple of (suffix, suffixPosition). Calling code
/// should check to ensure that suffixPosition is not equal to nameLength (in which case there was no
/// suffix).
///
/// \param name The name to check
/// \param nameLength The length of the string in name
/// \returns An integer pair of the suffix itself and the position of that suffix in name
std::pair<int,int> getIntegerSuffix(const char *name, int nameLength)
{
int suffixPosition {nameLength - 1};
for (; suffixPosition >= 0; --suffixPosition) {
// When we support C++20 we can use std::span<> to eliminate the clang-tidy warning
// NOLINTNEXTLINE cppcoreguidelines-pro-bounds-pointer-arithmetic
if (!isdigit(name[suffixPosition])) {
break;
}
}
++suffixPosition;
int suffix {0};
if (suffixPosition < nameLength) {
// When we support C++20 we can use std::span<> to eliminate the clang-tidy warning
// NOLINTNEXTLINE cppcoreguidelines-pro-bounds-pointer-arithmetic
suffix = std::atoi(name + suffixPosition);
}
return std::make_pair(suffix, suffixPosition);
}
void IndexedName::set(
const char* name,
int length,
const std::vector<const char*>& allowedNames,
bool allowOthers)
{
// Storage for names that we weren't given external storage for
static std::unordered_set<ByteArray, ByteArrayHasher> NameSet;
if (length < 0) {
length = static_cast<int>(std::strlen(name));
}
// Name typically ends with an integer: find that integer
auto [suffix, suffixPosition] = getIntegerSuffix(name, length);
if (suffixPosition < length) {
this->index = suffix;
}
// Make sure that every character is either an ASCII letter (upper or lowercase), or an
// underscore. If any other character appears, reject the entire string.
// When we support C++20 we can use std::span<> to eliminate the clang-tidy warning
// NOLINTNEXTLINE cppcoreguidelines-pro-bounds-pointer-arithmetic
if (std::any_of(name, name+suffixPosition, isInvalidChar)) {
this->type = "";
return;
}
// If a list of allowedNames was provided, see if our set name matches one of those allowedNames: if it
// does, reference that memory location and return.
for (const auto *typeName : allowedNames) {
if (std::strncmp(name, typeName, suffixPosition) == 0) {
this->type = typeName;
return;
}
}
// If the type was NOT in the list of allowedNames, but the caller has set the allowOthers flag to
// true, then add the new type to the static NameSet (if it is not already there).
if (allowOthers) {
auto res = NameSet.insert(ByteArray(QByteArray::fromRawData(name, suffixPosition)));
if (res.second /*The insert succeeded (the type was new)*/) {
// Make sure that the data in the set is a unique (unshared) copy of the text
res.first->ensureUnshared();
}
this->type = res.first->bytes.constData();
}
else {
// The passed-in type is not in the allowed list, and allowOthers was not true, so don't
// store the type
this->type = "";
}
}

338
src/App/IndexedName.h Normal file
View File

@@ -0,0 +1,338 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* Copyright (c) 2022 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
* Copyright (c) 2023 FreeCAD Project Association *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef APP_INDEXEDNAME_H
#define APP_INDEXEDNAME_H
#include <cassert>
#include <cstring>
#include <ostream>
#include <string>
#include <vector>
#include <QByteArray>
#include <QHash>
#include "FCGlobal.h"
namespace Data
{
/// The IndexedName class provides a very memory-efficient data structure to hold a name and an index
/// value, and to perform various comparisons and validations of those values. The name must only
/// consist of upper- and lower-case ASCII characters and the underscore ('_') character. The index
/// must be a positive integer. The string representation of this IndexedName is the name followed by
/// the index, with no spaces between: an IndexedName may be constructed from this string. For
/// example "EDGE1" or "FACE345" might be the names of elements that use an IndexedName. If there is
/// then an "EDGE2", only a pointer to the original stored name "EDGE" is retained.
///
/// The memory efficiency of the class comes from re-using the same character storage for names that
/// match, while retaining their differing indices. This is achieved by either using user-provided
/// const char * names (provided as a list of typeNames and presumed to never be deallocated), or by
/// maintaining an internal list of names that have been used before, and can be re-used later.
class AppExport IndexedName {
public:
/// Construct from a name and an optional index. If the name contains an index it is read, but
/// is used as the index *only* if _index parameter is unset. If the _index parameter is given
/// it overrides any trailing integer in the name. Index must be positive, and name must contain
/// only ASCII letters and the underscore character. If these conditions are not met, name is
/// set to the empty string, and isNull() will return true.
///
/// \param name The new name - ASCII letters and underscores only, with optional integer suffix.
/// This memory will be copied into a new internal storage location and need not be persistent.
/// \param _index The new index - if provided, it overrides any suffix provided by name
explicit IndexedName(const char *name = nullptr, int _index = 0)
: index(0)
{
assert(_index >= 0);
if (!name) {
this->type = "";
}
else {
set(name);
if (_index > 0) {
this->index = _index;
}
}
}
/// Create an indexed name that is restricted to a list of preset type names. If it appears in
/// that list, only a pointer to the character storage in the list is retained: the memory
/// locations pointed at by the list must never be destroyed once they have been used to create
/// names. If allowOthers is true (the default) then a requested name that is not in the list
/// will be added to a static internal storage table, and its memory then re-used for later
/// objects with the same name. If allowOthers is false, then the name request is rejected, and
/// the name is treated as null.
///
/// \param name The new name - ASCII letters and underscores only, with optional integer suffix
/// \param allowedTypeNames A vector of allowed names. Storage locations must persist for the
/// entire run of the program.
/// \param allowOthers Whether a name not in allowedTypeNames is permitted. If true (the
/// default) then a name not in allowedTypeNames is added to a static internal storage vector
/// so that it can be re-used later without additional memory allocation.
IndexedName(const char *name,
const std::vector<const char*> & allowedTypeNames,
bool allowOthers=true) : type(""), index(0)
{
set(name, -1, allowedTypeNames, allowOthers);
}
/// Construct from a QByteArray, but explicitly making a copy of the name on its first
/// occurrence. If this is a name that has already been stored internally, no additional copy
/// is made.
///
/// \param data The QByteArray to copy the data from
explicit IndexedName(const QByteArray & data) : type(""), index(0)
{
set(data.constData(), data.size());
}
/// Given constant name and an index, re-use the existing memory for the name, not making a copy
/// of it, or scanning any existing storage for it. The name must never become invalid for the
/// lifetime of the object it names. This memory will never be re-used by another object.
///
/// \param name The name of the object. This memory is NOT copied and must be persistent.
/// \param index A positive, non-zero integer
/// \return An IndexedName with the given name and index, re-using the existing memory for name
static IndexedName fromConst(const char *name, int index) {
assert (index >= 0);
IndexedName res;
res.type = name;
res.index = index;
return res;
}
/// Given an existing std::string, *append* this name to it. If index is not zero, this will
/// include the index.
///
/// \param buffer A (possibly non-empty) string buffer to append the name to.
void appendToStringBuffer(std::string & buffer) const
{
buffer += this->type;
if (this->index > 0) {
buffer += std::to_string(this->index);
}
}
/// Create and return a new std::string with this name in it.
///
/// \return A newly-created string with the IndexedName in it (e.g. "EDGE42")
std::string toString() const
{
std::string result;
this->appendToStringBuffer(result);
return result;
}
/// An indexedName is represented as the simple concatenation of the name and its index, e.g.
/// "EDGE1" or "FACE42".
friend std::ostream & operator<<(std::ostream & stream, const IndexedName & indexedName)
{
stream << indexedName.type;
if (indexedName.index > 0) {
stream << indexedName.index;
}
return stream;
}
/// True only if both the name and index compare exactly equal.
bool operator==(const IndexedName & other) const
{
return this->index == other.index
&& (this->type == other.type
|| std::strcmp(this->type, other.type)==0);
}
/// Increments the index by the given offset. Does not affect the text part of the name.
IndexedName & operator+=(int offset)
{
this->index += offset;
assert(this->index >= 0);
return *this;
}
/// Pre-increment operator: increases the index of this element by one.
IndexedName & operator++()
{
++this->index;
return *this;
}
/// Pre-decrement operator: decreases the index of this element by one. Must not make the index
/// negative (only checked when compiled in debug mode).
IndexedName & operator--()
{
--this->index;
assert(this->index >= 0);
return *this;
}
/// True if either the name or the index compare not equal.
bool operator!=(const IndexedName & other) const
{
return !(this->operator==(other));
}
/// Equivalent to C++20's operator <=>
int compare(const IndexedName & other) const
{
int res = std::strcmp(this->type, other.type);
if (res != 0) {
return res;
}
if (this->index < other.index) {
return -1;
}
if (this->index > other.index) {
return 1;
}
return 0;
}
/// Provided to enable sorting operations: the comparison is first lexicographical for the text
/// element of the names, then numerical for the indices.
bool operator<(const IndexedName & other) const
{
return compare(other) < 0;
}
/// Allow direct memory access to the individual characters of the text portion of the name.
/// NOTE: input is not range-checked when compiled in release mode.
char operator[](int input) const
{
assert(input >= 0);
assert(input < static_cast<int>(std::strlen(this->type)));
// When we support C++20 we can use std::span<> to eliminate the clang-tidy warning
// NOLINTNEXTLINE cppcoreguidelines-pro-bounds-pointer-arithmetic
return this->type[input];
}
/// Get a pointer to text part of the name - does NOT make a copy, returns direct memory access
const char * getType() const { return this->type; }
/// Get the numerical part of the name
int getIndex() const { return this->index; }
/// Set the numerical part of the name (note that there is no equivalent function to allow
/// changing the text part of the name, which is immutable once created).
///
/// \param input The new index. Must be a positive non-zero integer
void setIndex(int input) { assert(input>=0); this->index = input; }
/// A name is considered "null" if its text component is an empty string.
// When we support C++20 we can use std::span<> to eliminate the clang-tidy warning
// NOLINTNEXTLINE cppcoreguidelines-pro-bounds-pointer-arithmetic
bool isNull() const { return this->type[0] == '\0'; }
/// Boolean conversion provides the opposite of isNull(), yielding true when the text part of
/// the name is NOT the empty string.
explicit operator bool() const { return !isNull(); }
protected:
/// Apply the IndexedName rules and either store the characters of a new type or a reference to
/// the characters in a type named in types, or stored statically within this function. If len
/// is not set, or set to -1 (the default), then the provided string in name is scanned for its
/// length using strlen (e.g. it must be null-terminated).
///
/// \param name The new name. If necessary a copy is made, this char * need not be persistent
/// \param length The length of name
/// \param allowedNames A vector of storage locations of allowed names. These storage locations
/// must be persistent for the duration of the program run.
/// \param allowOthers If true (the default), then if name is not in allowedNames it is allowed,
/// and it is added to internal storage (making a copy of the name if this is its first
/// occurrence).
void set(const char *name,
int length = -1,
const std::vector<const char *> & allowedNames = {},
bool allowOthers = true);
private:
const char * type;
int index;
};
/// A thin wrapper around a QByteArray providing the ability to force a copy of the data at any
/// time, even if it isn't being written to. The standard assignment operator for this class *does*
/// make a copy of the data, unlike the standard assignment operator for QByteArray.
struct ByteArray
{
explicit ByteArray(QByteArray other)
:bytes(std::move(other))
{}
ByteArray(const ByteArray& other) = default;
ByteArray(ByteArray&& other) noexcept
:bytes(std::move(other.bytes))
{}
~ByteArray() = default;
/// Guarantee that the stored QByteArray does not share its memory with another instance.
void ensureUnshared() const
{
QByteArray copy;
copy.append(bytes.constData(), bytes.size());
bytes = copy;
}
bool operator==(const ByteArray& other) const {
return bytes == other.bytes;
}
ByteArray &operator=(const ByteArray & other) {
bytes.clear();
bytes.append(other.bytes.constData(), other.bytes.size());
return *this;
}
ByteArray &operator= (ByteArray&& other) noexcept
{
bytes = std::move(other.bytes);
return *this;
}
mutable QByteArray bytes;
};
struct ByteArrayHasher
{
std::size_t operator()(const ByteArray& bytes) const
{
return qHash(bytes.bytes);
}
std::size_t operator()(const QByteArray& bytes) const
{
return qHash(bytes);
}
};
}
#endif // APP_INDEXEDNAME_H

View File

@@ -49,8 +49,8 @@ public:
/** Base class of all factories
* This class has the purpose to produce a runtime instance
* of classes unknown at compile time. It holds a map of so called
* This class has the purpose to produce instances of classes at runtime
* that are unknown at compile time. It holds a map of so called
* producers which are able to produce an instance of a special class.
* Producer can be registered at runtime through e.g. application modules
*/

View File

@@ -43,6 +43,21 @@ void ProgressIndicatorPy::init_type()
add_varargs_method("stop",&ProgressIndicatorPy::stop,"stop()");
}
Py::PythonType& ProgressIndicatorPy::behaviors()
{
return Py::PythonExtension<ProgressIndicatorPy>::behaviors();
}
PyTypeObject* ProgressIndicatorPy::type_object()
{
return Py::PythonExtension<ProgressIndicatorPy>::type_object();
}
bool ProgressIndicatorPy::check(PyObject* p)
{
return Py::PythonExtension<ProgressIndicatorPy>::check(p);
}
PyObject *ProgressIndicatorPy::PyMake(struct _typeobject *, PyObject *, PyObject *)
{
return new ProgressIndicatorPy();

View File

@@ -35,6 +35,9 @@ class BaseExport ProgressIndicatorPy : public Py::PythonExtension<ProgressIndica
{
public:
static void init_type(); // announce properties and methods
static Py::PythonType& behaviors();
static PyTypeObject* type_object();
static bool check(PyObject* p);
ProgressIndicatorPy();
~ProgressIndicatorPy() override;

View File

@@ -1648,6 +1648,33 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #65A2E5, stop:1 #65A2E5);
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: #D2D8E1;
background: #232932;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
Radio button

View File

@@ -1615,6 +1615,33 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #3874f2, stop:1 #5e90fa);
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: #e0e0e0;
background-color: #5a5a5a;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
Radio button

View File

@@ -1615,6 +1615,33 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1b3774, stop:1 #2053c0);
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: #fefefe;
background-color: #111111;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
QComboBox inside Task Panel content

View File

@@ -1614,6 +1614,33 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #819c0c, stop:1 #94b30f);
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: #e0e0e0;
background-color: #5a5a5a;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
Radio button

View File

@@ -1615,6 +1615,33 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #d0970c, stop:1 #daa116);
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: #e0e0e0;
background-color: #5a5a5a;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
Radio button

View File

@@ -1615,6 +1615,33 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1b3774, stop:1 #2053c0);
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: #f5f5f5;
background: #2a2a2a;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
QComboBox inside Task Panel content

View File

@@ -1615,6 +1615,33 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #566214, stop:1 #74831d);
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: #f5f5f5;
background: #2a2a2a;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
QComboBox inside Task Panel content

View File

@@ -1609,6 +1609,33 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #624b14, stop:1 #b28416);
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: #f5f5f5;
background-color: #2a2a2a;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
QComboBox inside Task Panel content

View File

@@ -1612,6 +1612,33 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #3874f2, stop:1 #5e90fa);
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: black;
background: #f5f5f5;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
Radio button

View File

@@ -1612,6 +1612,33 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #819c0c, stop:1 #94b30f);
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: black;
background: #f5f5f5;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
Radio button

View File

@@ -1612,6 +1612,33 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #d0970c, stop:1 #daa116);
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: black;
background: #f5f5f5;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
Radio button

View File

@@ -1624,20 +1624,6 @@ QWidget#Form QPushButton:pressed {
background-color: #557BB6;
}
/* Sketcher Manual Update Button */
QPushButton#manualUpdate {
padding: 4px;
margin: 0px;
border: 1px solid #494949;
}
QPushButton:pressed#manualUpdate {
color: #ffffff;
border: 1px solid #3c3c3c;
background-color: #48699a;
}
/* Addon Manager */
QDialog#Dialog QPushButton {
@@ -1815,6 +1801,32 @@ QSint--ActionGroup QFrame[class="content"] QToolButton:pressed {
background-color: #557BB6;
}
/* QToolButtons with a menu found in Sketcher task panel*/
QSint--ActionGroup QToolButton::menu-button {
border: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 2px;
width: 16px; /* 16px width + 4px for border = 20px allocated above */
outline: none;
background-color: transparent;
}
QSint--ActionGroup QToolButton#settingsButton,
QSint--ActionGroup QToolButton#filterButton,
QSint--ActionGroup QToolButton#manualUpdate {
padding: 2px;
padding-right: 20px; /* make way for the popup button */
margin: 0px;
}
/* to give widget inside the menu same look as regular menu */
QSint--ActionGroup QToolButton#filterButton QListWidget {
color: #f5f5f5;
background: #2a2a2a;
padding: 0px;
margin: 0px;
}
/*==================================================================================================
QComboBox inside Task Panel content
@@ -1824,7 +1836,7 @@ QComboBox inside Task Panel content
/* TODO: external border not working, in the rest of GUI works setting up Qmenu background color but inside Task Panel it doesn't... */
QSint--ActionGroup QFrame[class="content"] QMenu,
QSint--ActionGroup QFrame[class="content"] QMenu::item {
background-color: #696969;
background-color: #2a2a2a;
}
QSint--ActionGroup QFrame[class="content"] QComboBox QAbstractItemView {

View File

@@ -42,16 +42,17 @@ translate = FreeCAD.Qt.translate
class UpdaterFactory:
"""A factory class for generating updaters. Mainly exists to allow eaily mocking those
updaters during testing. A replacement class need only provide a "get_updater" function
that returns mock updater objects. Those objects must be QObjects with a run() function
and a finished signal."""
"""A factory class for generating updaters. Mainly exists to allow easily mocking
those updaters during testing. A replacement class need only provide a
"get_updater" function that returns mock updater objects. Those objects must be
QObjects with a run() function and a finished signal."""
def __init__(self, addons):
self.addons = addons
def get_updater(self, addon):
"""Get an updater for this addon (either a MacroInstaller or an AddonInstaller)"""
"""Get an updater for this addon (either a MacroInstaller or an
AddonInstaller)"""
if addon.macro is not None:
return MacroInstaller(addon)
return AddonInstaller(addon, self.addons)
@@ -101,7 +102,8 @@ class UpdateAllGUI(QtCore.QObject):
self.cancelled = False
def run(self):
"""Run the Update All process. Blocks until updates are complete or cancelled."""
"""Run the Update All process. Blocks until updates are complete or
cancelled."""
self.running = True
self._setup_dialog()
self.dialog.show()
@@ -194,14 +196,16 @@ class UpdateAllGUI(QtCore.QObject):
text = translate("Addons installer", "Finished updating the following addons")
self._set_dialog_to_final_state(text)
self.running = False
self.finished.emit()
def _setup_cancelled_state(self):
text1 = translate("AddonsInstaller", "Update was cancelled")
text2 = translate("AddonsInstaller", "some addons may have been updated")
self._set_dialog_to_final_state(text1 + ": " + text2)
self.running = False
self.finished.emit()
def _set_dialog_to_final_state(self,new_content):
def _set_dialog_to_final_state(self, new_content):
self.dialog.buttonBox.clear()
self.dialog.buttonBox.addButton(QtWidgets.QDialogButtonBox.Close)
self.dialog.label.setText(new_content)

View File

@@ -49,8 +49,6 @@ PyMOD_INIT_FUNC(Import)
// add mesh elements
Base::Interpreter().addType(&Import::StepShapePy ::Type, importModule, "StepShape");
// init Type system
//Import::StepShape ::init();
Base::Console().Log("Loading Import module... done\n");
PyMOD_Return(importModule);

View File

@@ -104,9 +104,6 @@ public:
add_keyword_method("insert",&Module::importer,
"insert(string,string) -- Insert the file into the given document."
);
// add_varargs_method("openAssembly",&Module::importAssembly,
// "openAssembly(string) -- Open the assembly file and create a new document."
// );
add_keyword_method("export",&Module::exporter,
"export(list,string) -- Export a list of objects into a single file."
);
@@ -144,7 +141,6 @@ private:
std::string name8bit = Part::encodeFilename(Utf8Name);
try {
//Base::Console().Log("Insert in Part with %s",Name);
Base::FileInfo file(Utf8Name.c_str());
App::Document *pcDoc = nullptr;
@@ -231,7 +227,6 @@ private:
throw Py::Exception(PyExc_IOError, "no supported file format");
}
#if 1
ImportOCAFExt ocaf(hDoc, pcDoc, file.fileNamePure());
ocaf.setImportOptions(ImportOCAFExt::customImportOptions());
if (merge != Py_None)
@@ -243,14 +238,7 @@ private:
if (mode >= 0)
ocaf.setMode(mode);
ocaf.loadShapes();
#elif 1
Import::ImportOCAFCmd ocaf(hDoc, pcDoc, file.fileNamePure());
ocaf.loadShapes();
#else
Import::ImportXCAF xcaf(hDoc, pcDoc, file.fileNamePure());
xcaf.loadShapes();
pcDoc->recompute();
#endif
hApp->Close(hDoc);
if (!ocaf.partColors.empty()) {
@@ -326,7 +314,6 @@ private:
ocaf.exportObjects(objs);
}
else {
//bool keepExplicitPlacement = objs.size() > 1;
bool keepExplicitPlacement = Standard_True;
ExportOCAF ocaf(hDoc, keepExplicitPlacement);
// That stuff is exporting a list of selected objects into FreeCAD Tree
@@ -340,26 +327,22 @@ private:
std::vector <TDF_Label> FreeLabels;
std::vector <int> part_id;
ocaf.getFreeLabels(hierarchical_label,FreeLabels, part_id);
#if OCC_VERSION_HEX >= 0x070200
// Update is not performed automatically anymore: https://tracker.dev.opencascade.org/view.php?id=28055
XCAFDoc_DocumentTool::ShapeTool(hDoc->Main())->UpdateAssemblies();
#endif
}
Base::FileInfo file(Utf8Name.c_str());
if (file.hasExtension("stp") || file.hasExtension("step")) {
//Interface_Static::SetCVal("write.step.schema", "AP214IS");
STEPCAFControl_Writer writer;
Part::Interface::writeStepAssembly(Part::Interface::Assembly::On);
// writer.SetColorMode(Standard_False);
writer.Transfer(hDoc, STEPControl_AsIs);
APIHeaderSection_MakeHeader makeHeader(writer.ChangeWriter().Model());
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part")->GetGroup("STEP");
// Don't set name because STEP doesn't support UTF-8
// https://forum.freecadweb.org/viewtopic.php?f=8&t=52967
//makeHeader.SetName(new TCollection_HAsciiString((Standard_CString)Utf8Name.c_str()));
makeHeader.SetAuthorValue (1, new TCollection_HAsciiString(hGrp->GetASCII("Author", "Author").c_str()));
makeHeader.SetOrganizationValue (1, new TCollection_HAsciiString(hGrp->GetASCII("Company").c_str()));
makeHeader.SetOriginatingSystem(new TCollection_HAsciiString(App::Application::getExecutableName().c_str()));
@@ -690,111 +673,7 @@ private:
throw Py::TypeError("expected ([DocObject],path");
}
};
/*
static PyObject * importAssembly(PyObject *self, PyObject *args)
{
char* Name;
PyObject* TargetObjectPy=0;
if (!PyArg_ParseTuple(args, "et|O!","utf-8",&Name,&(App::DocumentObjectPy::Type),&TargetObjectPy))
return 0;
std::string Utf8Name = std::string(Name);
PyMem_Free(Name);
std::string name8bit = Part::encodeFilename(Utf8Name);
PY_TRY {
//Base::Console().Log("Insert in Part with %s",Name);
Base::FileInfo file(name8bit);
App::DocumentObject* target = nullptr;
if(TargetObjectPy)
target = static_cast<App::DocumentObjectPy*>(TargetObjectPy)->getDocumentObjectPtr();
App::Document *pcDoc = 0;
pcDoc = App::GetApplication().getActiveDocument();
if (!pcDoc)
pcDoc = App::GetApplication().newDocument("ImportedAssembly");
Handle(XCAFApp_Application) hApp = XCAFApp_Application::GetApplication();
Handle(TDocStd_Document) hDoc;
hApp->NewDocument(TCollection_ExtendedString("MDTV-CAF"), hDoc);
if (file.hasExtension("stp") || file.hasExtension("step")) {
try {
STEPCAFControl_Reader aReader;
aReader.SetColorMode(true);
aReader.SetNameMode(true);
aReader.SetLayerMode(true);
if (aReader.ReadFile((Standard_CString)(name8bit.c_str())) != IFSelect_RetDone) {
PyErr_SetString(PyExc_IOError, "cannot read STEP file");
return 0;
}
Handle(Message_ProgressIndicator) pi = new Part::ProgressIndicator(100);
aReader.Reader().WS()->MapReader()->SetProgress(pi);
pi->NewScope(100, "Reading STEP file...");
pi->Show();
aReader.Transfer(hDoc);
pi->EndScope();
}
catch (OSD_Exception& e) {
Base::Console().Error("%s\n", e.GetMessageString());
Base::Console().Message("Try to load STEP file without colors...\n");
Part::ImportStepParts(pcDoc,Name);
pcDoc->recompute();
}
}
else if (file.hasExtension("igs") || file.hasExtension("iges")) {
try {
IGESControl_Controller::Init();
Interface_Static::SetIVal("read.surfacecurve.mode",3);
IGESCAFControl_Reader aReader;
aReader.SetColorMode(true);
aReader.SetNameMode(true);
aReader.SetLayerMode(true);
if (aReader.ReadFile((Standard_CString)(name8bit.c_str())) != IFSelect_RetDone) {
PyErr_SetString(PyExc_IOError, "cannot read IGES file");
return 0;
}
Handle(Message_ProgressIndicator) pi = new Part::ProgressIndicator(100);
aReader.WS()->MapReader()->SetProgress(pi);
pi->NewScope(100, "Reading IGES file...");
pi->Show();
aReader.Transfer(hDoc);
pi->EndScope();
}
catch (OSD_Exception& e) {
Base::Console().Error("%s\n", e.GetMessageString());
Base::Console().Message("Try to load IGES file without colors...\n");
Part::ImportIgesParts(pcDoc,Name);
pcDoc->recompute();
}
}
else {
PyErr_SetString(PyExc_RuntimeError, "no supported file format");
return 0;
}
Import::ImportOCAFAssembly ocaf(hDoc, pcDoc, file.fileNamePure(),target);
ocaf.loadAssembly();
pcDoc->recompute();
}
catch (Standard_Failure& e) {
PyErr_SetString(PyExc_RuntimeError, e.GetMessageString());
return 0;
}
PY_CATCH
Py_Return;
}*/
PyObject* initModule()
{

View File

@@ -41,24 +41,11 @@ void FeatureImportIges::InitLabel(const TDF_Label &rcLabel)
addProperty("String","FileName");
}
/*
bool FeaturePartImportStep::MustExecute(void)
{
Base::Console().Log("PartBoxFeature::MustExecute()\n");
return false;
}
*/
Standard_Integer FeatureImportIges::Execute(void)
{
Base::Console().Log("FeaturePartImportIges::Execute()\n");
/* cout << GetFloatProperty("x") << endl;
cout << GetFloatProperty("y") << endl;
cout << GetFloatProperty("z") << endl;
cout << GetFloatProperty("l") << endl;
cout << GetFloatProperty("h") << endl;
cout << GetFloatProperty("w") << endl;*/
try{
IGESControl_Reader aReader;
@@ -83,10 +70,6 @@ Standard_Integer FeatureImportIges::Execute(void)
if (aReader.ReadFile((const Standard_CString)FileName.c_str()) != IFSelect_RetDone)
throw Base::FileException("IGES read failed (load file)");
// check iges-file (memory)
//if (!aReader.Check(Standard_True))
// Base::Console().Warning( "IGES model contains errors! try loading anyway....\n" );
// make brep
aReader.TransferRoots();
// one shape, who contain's all subshapes
@@ -104,17 +87,3 @@ Standard_Integer FeatureImportIges::Execute(void)
return 0;
}
/*
void FeatureImportIges::Validate(void)
{
Base::Console().Log("FeaturePartImportStep::Validate()\n");
// We validate the object label ( Label() ), all the arguments and the results of the object:
log.SetValid(Label(), Standard_True);
}
*/

View File

@@ -36,21 +36,12 @@ public:
virtual void InitLabel(const TDF_Label &rcLabel);
// virtual bool MustExecute(void);
virtual Standard_Integer Execute(void);
// virtual void Validate(void);
/// Returns the Name/Type of the feature
virtual const char *Type(void){return "PartImportIges";}
/// Returns the Name/Type of the feature
virtual const char *Type(void){return "PartImportIges";}
};
}
#endif // __FeaturePartImportIges_H__

View File

@@ -42,24 +42,11 @@ void FeatureImportStep::InitLabel(const TDF_Label &rcLabel)
}
/*
bool FeaturePartImportStep::MustExecute(void)
{
Base::Console().Log("PartBoxFeature::MustExecute()\n");
return false;
}
*/
Standard_Integer FeatureImportStep::Execute(void)
{
Base::Console().Log("FeaturePartImportStep::Execute()\n");
/* cout << GetFloatProperty("x") << endl;
cout << GetFloatProperty("y") << endl;
cout << GetFloatProperty("z") << endl;
cout << GetFloatProperty("l") << endl;
cout << GetFloatProperty("h") << endl;
cout << GetFloatProperty("w") << endl;*/
try{
STEPControl_Reader aReader;
@@ -92,7 +79,7 @@ Standard_Integer FeatureImportStep::Execute(void)
// Root transfers
Standard_Integer nbr = aReader.NbRootsForTransfer();
//aReader.PrintCheckTransfer (failsonly, IFSelect_ItemsByEntity);
for ( Standard_Integer n = 1; n<= nbr; n++)
{
printf("STEP: Transferring Root %d\n",n);
@@ -124,16 +111,3 @@ Standard_Integer FeatureImportStep::Execute(void)
return 0;
}
/*
void FeatureImportStep::Validate(void)
{
Base::Console().Log("FeaturePartImportStep::Validate()\n");
// We validate the object label ( Label() ), all the arguments and the results of the object:
log.SetValid(Label(), Standard_True);
}
*/

View File

@@ -37,17 +37,12 @@ public:
virtual Standard_Integer Execute(void);
// virtual void Validate(void);
/// Returns the Name/Type of the feature
virtual const char *Type(void){return "PartImportStep";}
/// Returns the Name/Type of the feature
virtual const char *Type(void){return "PartImportStep";}
};
}
#endif // __FeatureImportStep_H__

View File

@@ -560,9 +560,7 @@ bool ImportOCAF2::createGroup(App::Document *doc, Info &info, const TopoDS_Shape
link->Placement.setValue(pla->getValue());
child = link;
}
// child->Visibility.setValue(false);
}
// group->Visibility.setValue(false);
group->ElementList.setValues(children);
group->VisibilityList.setValue(visibilities);
info.obj = group;
@@ -627,7 +625,6 @@ App::DocumentObject* ImportOCAF2::loadShapes()
ret = info.obj;
}
if(ret) {
// ret->Visibility.setValue(true);
ret->recomputeFeature(true);
}
if(options.merge && ret && !ret->isDerivedFrom(Part::Feature::getClassTypeId())) {
@@ -766,7 +763,6 @@ App::DocumentObject *ImportOCAF2::loadShape(App::Document *doc,
}
auto link = static_cast<App::Link*>(doc->addObject("App::Link","Link"));
// link->Visibility.setValue(false);
link->setLink(-1,info.obj);
setPlacement(&link->Placement,shape);
info.obj = link;
@@ -861,7 +857,6 @@ bool ImportOCAF2::createAssembly(App::Document *_doc,
// Okay, we are creating a link array
auto link = static_cast<App::Link*>(doc->addObject("App::Link","Link"));
// link->Visibility.setValue(false);
link->setLink(-1,child);
link->ShowElement.setValue(false);
link->ElementCount.setValue(childInfo.plas.size());
@@ -1180,13 +1175,12 @@ void ExportOCAF2::exportObjects(std::vector<App::DocumentObject*> &objs, const c
setName(label,nullptr,name);
}
if(FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG))
if(FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
dumpLabels(pDoc->Main(),aShapeTool,aColorTool);
}
#if OCC_VERSION_HEX >= 0x070200
// Update is not performed automatically anymore: https://tracker.dev.opencascade.org/view.php?id=28055
aShapeTool->UpdateAssemblies();
#endif
}
TDF_Label ExportOCAF2::exportObject(App::DocumentObject* parentObj,

View File

@@ -91,21 +91,6 @@ std::string ImportOCAFAssembly::getName(const TDF_Label& label)
part_name = str;
delete [] str;
return part_name;
//if (part_name.empty()) {
// return "";
//}
//else {
// bool ws=true;
// for (std::string::iterator it = part_name.begin(); it != part_name.end(); ++it) {
// if (*it != ' ') {
// ws = false;
// break;
// }
// }
// if (ws)
// part_name = defaultname;
//}
}
return "";
@@ -255,15 +240,6 @@ void ImportOCAFAssembly::createShape(const TopoDS_Shape& aShape, const TopLoc_Lo
std::vector<App::Color> colors;
colors.push_back(color);
applyColors(part, colors);
#if 0//TODO
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part);
if (vp && vp->isDerivedFrom(PartGui::ViewProviderPart::getClassTypeId())) {
color.r = aColor.Red();
color.g = aColor.Green();
color.b = aColor.Blue();
static_cast<PartGui::ViewProviderPart*>(vp)->ShapeColor.setValue(color);
}
#endif
}
TopTools_IndexedMapOfShape faces;

View File

@@ -65,25 +65,13 @@ int StepShape::read(const char* fileName)
throw Base::FileException("Cannot open STEP file");
}
//Standard_Integer ic = Interface_Static::IVal("read.precision.mode");
//Standard_Real rp = Interface_Static::RVal("read.maxprecision.val");
//Standard_Integer ic = Interface_Static::IVal("read.maxprecision.mode");
//Standard_Integer mv = Interface_Static::IVal("read.stdsameparameter.mode");
//Standard_Integer rp = Interface_Static::IVal("read.surfacecurve.mode");
//Standard_Real era = Interface_Static::RVal("read.encoderegularity.angle");
//Standard_Integer ic = Interface_Static::IVal("read.step.product.mode");
//Standard_Integer ic = Interface_Static::IVal("read.step.product.context");
//Standard_Integer ic = Interface_Static::IVal("read.step.shape.repr");
//Standard_Integer ic = Interface_Static::IVal("read.step.assembly.level");
//Standard_Integer ic = Interface_Static::IVal("read.step.shape.relationship");
//Standard_Integer ic = Interface_Static::IVal("read.step.shape.aspect");
Handle(TColStd_HSequenceOfTransient) list = aReader.GiveList();
//Use method StepData_StepModel::NextNumberForLabel to find its rank with the following:
//Standard_CString label = "#...";
Handle(StepData_StepModel) model = aReader.StepModel();
//rank = model->NextNumberForLabe(label, 0, Standard_False);
std::cout << "dump of step header:" << std::endl;
#if OCC_VERSION_HEX < 0x070401

View File

@@ -180,15 +180,12 @@ void OCAFBrowser::load(const TDF_Label& label, QTreeWidgetItem* item, const QStr
item->setText(0, text);
}
#if 0
TDF_IDList localList = myList;
#else
TDF_IDList localList;
TDF_AttributeIterator itr (label);
for ( ; itr.More(); itr.Next()) {
localList.Append(itr.Value()->ID());
}
#endif
for (TDF_ListIteratorOfIDList it(localList); it.More(); it.Next()) {
Handle(TDF_Attribute) attr;
@@ -260,15 +257,6 @@ void OCAFBrowser::load(const TDF_Label& label, QTreeWidgetItem* item, const QStr
}
}
//TDF_ChildIDIterator nodeIterator(label, XCAFDoc::ShapeRefGUID());
//for (; nodeIterator.More(); nodeIterator.Next()) {
// Handle(TDataStd_TreeNode) node = Handle(TDataStd_TreeNode)::DownCast(nodeIterator.Value());
// //if (node->HasFather())
// // ;
// QTreeWidgetItem* child = new QTreeWidgetItem();
// child->setText(0, QString::fromLatin1("TDataStd_TreeNode"));
// item->addChild(child);
//}
int i=1;
for (TDF_ChildIterator it(label); it.More(); it.Next(),i++) {
@@ -295,12 +283,9 @@ private:
if (!vp)
return;
if(colors.empty()) {
// vp->MapFaceColor.setValue(true);
// vp->MapLineColor.setValue(true);
// vp->updateColors(0,true);
return;
}
// vp->MapFaceColor.setValue(false);
if(colors.size() == 1) {
vp->ShapeColor.setValue(colors.front());
vp->Transparency.setValue(100 * colors.front().a);
@@ -313,7 +298,6 @@ private:
auto vp = dynamic_cast<PartGui::ViewProviderPartExt*>(Gui::Application::Instance->getViewProvider(part));
if (!vp)
return;
// vp->MapLineColor.setValue(false);
if(colors.size() == 1)
vp->LineColor.setValue(colors.front());
else
@@ -344,7 +328,6 @@ private:
if(!vp)
return;
(void)colors;
// vp->setElementColors(colors);
}
};
@@ -411,7 +394,6 @@ private:
std::string name8bit = Part::encodeFilename(Utf8Name);
try {
//Base::Console().Log("Insert in Part with %s",Name);
Base::FileInfo file(Utf8Name.c_str());
App::Document *pcDoc = nullptr;
@@ -666,10 +648,7 @@ private:
ocaf.getPartColors(hierarchical_part,FreeLabels,part_id,Colors);
ocaf.reallocateFreeShape(hierarchical_part,FreeLabels,part_id,Colors);
#if OCC_VERSION_HEX >= 0x070200
// Update is not performed automatically anymore: https://tracker.dev.opencascade.org/view.php?id=28055
XCAFDoc_DocumentTool::ShapeTool(hDoc->Main())->UpdateAssemblies();
#endif
}
Base::FileInfo file(Utf8Name.c_str());
@@ -682,7 +661,6 @@ private:
STEPCAFControl_Writer writer;
Part::Interface::writeStepAssembly(Part::Interface::Assembly::On);
// writer.SetColorMode(Standard_False);
writer.Transfer(hDoc, STEPControl_AsIs);
// edit STEP header
@@ -691,8 +669,8 @@ private:
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part")->GetGroup("STEP");
// Don't set name because STEP doesn't support UTF-8
// https://forum.freecadweb.org/viewtopic.php?f=8&t=52967
//makeHeader.SetName(new TCollection_HAsciiString((Standard_CString)Utf8Name.c_str()));
makeHeader.SetAuthorValue (1, new TCollection_HAsciiString(hGrp->GetASCII("Author", "Author").c_str()));
makeHeader.SetOrganizationValue (1, new TCollection_HAsciiString(hGrp->GetASCII("Company").c_str()));
makeHeader.SetOriginatingSystem(new TCollection_HAsciiString(App::Application::getExecutableName().c_str()));
@@ -758,7 +736,6 @@ private:
throw Py::Exception();
try {
//Base::Console().Log("Insert in Part with %s",Name);
Base::FileInfo file(Name);
Handle(XCAFApp_Application) hApp = XCAFApp_Application::GetApplication();

View File

@@ -952,8 +952,8 @@ void TopoShape::exportStep(const char *filename) const
throw Base::FileException("Error in transferring STEP");
APIHeaderSection_MakeHeader makeHeader(aWriter.Model());
// Don't set name because STEP doesn't support UTF-8
// https://forum.freecadweb.org/viewtopic.php?f=8&t=52967
//makeHeader.SetName(new TCollection_HAsciiString((Standard_CString)(encodeFilename(filename).c_str())));
makeHeader.SetAuthorValue (1, new TCollection_HAsciiString("FreeCAD"));
makeHeader.SetOrganizationValue (1, new TCollection_HAsciiString("FreeCAD"));
makeHeader.SetOriginatingSystem(new TCollection_HAsciiString("FreeCAD"));

View File

@@ -21,6 +21,9 @@
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QAction>
#endif
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
@@ -52,14 +55,6 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView) :
ui->labelConstrainStatus->setOpenExternalLinks(false);
ui->autoUpdate->onRestore();
ui->autoRemoveRedundants->onRestore();
if(ui->autoUpdate->isChecked())
sketchView->getSketchObject()->noRecomputes=false;
else
sketchView->getSketchObject()->noRecomputes=true;
// Set up the possible state values for the status label
ui->labelConstrainStatus->setParameterGroup("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
ui->labelConstrainStatus->registerState(QString::fromUtf8("empty_sketch"), QColor("black"), std::string("EmptySketchMessageColor"));
@@ -77,14 +72,27 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView) :
connect(ui->labelConstrainStatusLink, &Gui::UrlLabel::linkClicked,
this, &TaskSketcherMessages::on_labelConstrainStatusLink_linkClicked);
//Set Auto Update in the 'Manual Update' button menu.
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
bool state = hGrp->GetBool("AutoRecompute", false);
sketchView->getSketchObject()->noRecomputes = !state;
QAction* action = new QAction(tr("Auto update"), this);
action->setToolTip(tr("Executes a recomputation of active document after every sketch action"));
action->setCheckable(true);
action->setChecked(state);
ui->manualUpdate->addAction(action);
QObject::connect(
qAsConst(ui->manualUpdate)->actions()[0], &QAction::changed,
this, &TaskSketcherMessages::onAutoUpdateStateChanged
);
/*QObject::connect(
ui->labelConstrainStatus, SIGNAL(linkActivated(const QString &)),
this , SLOT (on_labelConstrainStatus_linkActivated(const QString &))
);
QObject::connect(
ui->autoUpdate, SIGNAL(stateChanged(int)),
this , SLOT (on_autoUpdate_stateChanged(int))
);
QObject::connect(
ui->manualUpdate, SIGNAL(clicked(bool)),
this , SLOT (on_manualUpdate_clicked(bool))
@@ -123,22 +131,13 @@ void TaskSketcherMessages::on_labelConstrainStatusLink_linkClicked(const QString
}
void TaskSketcherMessages::on_autoUpdate_stateChanged(int state)
void TaskSketcherMessages::onAutoUpdateStateChanged()
{
if(state==Qt::Checked) {
sketchView->getSketchObject()->noRecomputes=false;
ui->autoUpdate->onSave();
}
else if (state==Qt::Unchecked) {
sketchView->getSketchObject()->noRecomputes=true;
ui->autoUpdate->onSave();
}
}
bool state = qAsConst(ui->manualUpdate)->actions()[0]->isChecked();
void TaskSketcherMessages::on_autoRemoveRedundants_stateChanged(int state)
{
Q_UNUSED(state);
ui->autoRemoveRedundants->onSave();
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
hGrp->SetBool("AutoRecompute", state);
sketchView->getSketchObject()->noRecomputes = !state;
}
void TaskSketcherMessages::on_manualUpdate_clicked(bool checked)

View File

@@ -47,12 +47,11 @@ public:
explicit TaskSketcherMessages(ViewProviderSketch *sketchView);
~TaskSketcherMessages() override;
void slotSetUp(const QString &state, const QString &msg, const QString& link, const QString& linkText);
void slotSetUp(const QString& state, const QString& msg, const QString& link, const QString& linkText);
private Q_SLOTS:
void on_labelConstrainStatusLink_linkClicked(const QString &);
void on_autoUpdate_stateChanged(int state);
void on_autoRemoveRedundants_stateChanged(int state);
void onAutoUpdateStateChanged();
void on_manualUpdate_clicked(bool checked);
protected:

View File

@@ -7,104 +7,53 @@
<x>0</x>
<y>0</y>
<width>253</width>
<height>108</height>
<height>48</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="Gui::StatefulLabel" name="labelConstrainStatus">
<property name="text">
<string>DOF</string>
</property>
</widget>
</item>
<item>
<widget class="Gui::UrlLabel" name="labelConstrainStatusLink">
<property name="text">
<string>Link</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="Gui::PrefCheckBox" name="autoRemoveRedundants">
<property name="toolTip">
<string>New constraints that would be redundant will automatically be removed</string>
</property>
<widget class="Gui::StatefulLabel" name="labelConstrainStatus">
<property name="text">
<string>Auto remove redundants</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>AutoRemoveRedundants</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Sketcher</cstring>
<string>DOF</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="Gui::PrefCheckBox" name="autoUpdate">
<property name="toolTip">
<string>Executes a recomputation of active document after every sketch action</string>
</property>
<property name="text">
<string>Auto update</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>AutoRecompute</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Sketcher</cstring>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="manualUpdate">
<property name="toolTip">
<string>Forces recomputation of active document</string>
</property>
<property name="text">
<string>Update</string>
</property>
</widget>
</item>
</layout>
<widget class="Gui::UrlLabel" name="labelConstrainStatusLink">
<property name="text">
<string>Link</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="manualUpdate">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Forces recomputation of active document</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>:/icons/view-refresh.svg</normaloff>:/icons/view-refresh.svg</iconset>
</property>
<property name="popupMode">
<enum>QToolButton::MenuButtonPopup</enum>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::PrefCheckBox</class>
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::StatefulLabel</class>
<extends>QLabel</extends>

View File

@@ -3,6 +3,7 @@ target_sources(
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/Branding.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Expression.cpp
${CMAKE_CURRENT_SOURCE_DIR}/IndexedName.cpp
${CMAKE_CURRENT_SOURCE_DIR}/License.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Metadata.cpp
)

View File

@@ -0,0 +1,595 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "gtest/gtest.h"
#include "App/IndexedName.h"
#include <sstream>
// NOLINTBEGIN(readability-magic-numbers)
class IndexedNameTest : public ::testing::Test {
protected:
// void SetUp() override {}
// void TearDown() override {}
// Create and return a list of invalid IndexedNames
static std::vector<Data::IndexedName> givenInvalidIndexedNames() {
return std::vector<Data::IndexedName> {
Data::IndexedName(),
Data::IndexedName("",1),
Data::IndexedName("INVALID42NAME",1),
Data::IndexedName(".EDGE",1)
};
}
// Create and return a list of valid IndexedNames
static std::vector<Data::IndexedName> givenValidIndexedNames() {
return std::vector<Data::IndexedName> {
Data::IndexedName("NAME"),
Data::IndexedName("NAME1"),
Data::IndexedName("NAME",1),
Data::IndexedName("NAME_WITH_UNDERSCORES12345")
};
}
// An arbitrary list of C strings used for testing some types of construction
// NOLINTNEXTLINE cppcoreguidelines-non-private-member-variables-in-classes
std::vector<const char *> allowedTypes {
"VERTEX",
"EDGE",
"FACE",
"WIRE"
};
};
TEST_F(IndexedNameTest, defaultConstruction)
{
// Act
auto indexedName = Data::IndexedName();
// Assert
EXPECT_STREQ(indexedName.getType(), "");
EXPECT_EQ(indexedName.getIndex(), 0);
}
TEST_F(IndexedNameTest, nameOnlyConstruction)
{
// Act
auto indexedName = Data::IndexedName("TestName");
// Assert
EXPECT_STREQ(indexedName.getType(), "TestName");
EXPECT_EQ(indexedName.getIndex(), 0);
}
TEST_F(IndexedNameTest, nameAndIndexConstruction)
{
// Arrange
const int testIndex {42};
// Act
auto indexedName = Data::IndexedName("TestName", testIndex);
// Assert
EXPECT_STREQ(indexedName.getType(), "TestName");
EXPECT_EQ(indexedName.getIndex(), testIndex);
}
TEST_F(IndexedNameTest, nameAndIndexConstructionWithOverride)
{
// Arrange
const int testIndex {42};
// Act
auto indexedName = Data::IndexedName("TestName17", testIndex);
// Assert
EXPECT_STREQ(indexedName.getType(), "TestName");
EXPECT_EQ(indexedName.getIndex(), testIndex);
}
// Names must only contain ASCII letters and underscores (but may end with a number)
TEST_F(IndexedNameTest, constructionInvalidCharInName)
{
// Arrange
constexpr int lastASCIICode{127};
std::vector<char> illegalCharacters = {};
for (int code = 1; code <= lastASCIICode; ++code) {
if ((std::isalnum(code) == 0) && code != '_') {
illegalCharacters.push_back(char(code));
}
}
for (auto illegalChar : illegalCharacters) {
std::string testName {"TestName"};
testName += illegalChar;
// Act
auto indexedName = Data::IndexedName(testName.c_str(), 1);
// Assert
EXPECT_STREQ(indexedName.getType(), "") << "Expected empty name when given " << testName;
}
}
// Names must not contain numbers in the middle:
TEST_F(IndexedNameTest, constructionNumberInName)
{
// Arrange
const int testIndex {42};
std::string testName;
testName += "Test" + std::to_string(testIndex) + "Name";
// Act
auto indexedName = Data::IndexedName(testName.c_str(), testIndex);
// Assert
EXPECT_STREQ(indexedName.getType(), "");
}
TEST_F(IndexedNameTest, nameAndTypeListConstructionWithoutAllowOthers)
{
// Act
auto indexedName = Data::IndexedName("EDGE19", allowedTypes, false);
// Assert
EXPECT_STREQ(indexedName.getType(), "EDGE");
EXPECT_EQ(indexedName.getIndex(), 19);
// Act
indexedName = Data::IndexedName("EDGES_ARE_REALLY_GREAT19", allowedTypes, false);
// Assert
EXPECT_STREQ(indexedName.getType(), "");
EXPECT_EQ(indexedName.getIndex(), 19);
// Act
indexedName = Data::IndexedName("NOT_IN_THE_LIST42", allowedTypes, false);
// Assert
EXPECT_STREQ(indexedName.getType(), "");
}
TEST_F(IndexedNameTest, nameAndTypeListConstructionWithAllowOthers)
{
// Act
auto indexedName = Data::IndexedName("NOT_IN_THE_LIST42", allowedTypes, true);
// Assert
EXPECT_STREQ(indexedName.getType(), "NOT_IN_THE_LIST");
EXPECT_EQ(indexedName.getIndex(), 42);
}
// Check that the same memory location is used for two names that are not in the allowedTypes list
TEST_F(IndexedNameTest, nameAndTypeListConstructionReusedMemoryCheck)
{
// Arrange
auto indexedName1 = Data::IndexedName("NOT_IN_THE_LIST42", allowedTypes, true);
auto indexedName2 = Data::IndexedName("NOT_IN_THE_LIST43", allowedTypes, true);
// Act & Assert
EXPECT_EQ(indexedName1.getType(), indexedName2.getType());
}
TEST_F(IndexedNameTest, byteArrayConstruction)
{
// Arrange
QByteArray qba{"EDGE42"};
// Act
auto indexedName = Data::IndexedName(qba);
// Assert
EXPECT_STREQ(indexedName.getType(), "EDGE");
EXPECT_EQ(indexedName.getIndex(), 42);
}
TEST_F(IndexedNameTest, copyConstruction)
{
// Arrange
auto indexedName = Data::IndexedName("EDGE42");
// Act
auto indexedNameCopy {indexedName};
// Assert
EXPECT_EQ(indexedName, indexedNameCopy);
}
TEST_F(IndexedNameTest, streamInsertionOperator)
{
// Arrange
auto indexedName = Data::IndexedName("EDGE42");
std::stringstream ss;
// Act
ss << indexedName;
// Assert
EXPECT_EQ(ss.str(), std::string{"EDGE42"});
}
TEST_F(IndexedNameTest, compoundAssignmentOperator)
{
// NOTE: Only += is defined for this class
// Arrange
constexpr int base{42};
constexpr int offset{10};
auto indexedName = Data::IndexedName("EDGE",base);
// Act
indexedName += offset;
// Assert
EXPECT_EQ(indexedName.getIndex(), 52);
}
TEST_F(IndexedNameTest, preincrementOperator)
{
// Arrange
auto indexedName = Data::IndexedName("EDGE42");
// Act
++indexedName;
// Assert
EXPECT_EQ(indexedName.getIndex(), 43);
}
TEST_F(IndexedNameTest, predecrementOperator)
{
// Arrange
auto indexedName = Data::IndexedName("EDGE42");
// Act
--indexedName;
// Assert
EXPECT_EQ(indexedName.getIndex(), 41);
}
TEST_F(IndexedNameTest, comparisonOperators)
{
// Arrange
auto indexedName1 = Data::IndexedName("EDGE42");
auto indexedName2 = Data::IndexedName("EDGE42");
// Act & Assert
EXPECT_EQ(indexedName1.compare(indexedName2), 0);
EXPECT_TRUE(indexedName1 == indexedName2);
EXPECT_FALSE(indexedName1 != indexedName2);
EXPECT_FALSE(indexedName1 < indexedName2);
// Arrange
auto indexedName3 = Data::IndexedName("EDGE42");
auto indexedName4 = Data::IndexedName("FACE42");
// Act & Assert
EXPECT_EQ(indexedName3.compare(indexedName4), -1);
EXPECT_FALSE(indexedName3 == indexedName4);
EXPECT_TRUE(indexedName3 != indexedName4);
EXPECT_TRUE(indexedName3 < indexedName4);
// Arrange
auto indexedName5 = Data::IndexedName("FACE42");
auto indexedName6 = Data::IndexedName("EDGE42");
// Act & Assert
EXPECT_EQ(indexedName5.compare(indexedName6), 1);
EXPECT_FALSE(indexedName5 == indexedName6);
EXPECT_TRUE(indexedName5 != indexedName6);
EXPECT_FALSE(indexedName5 < indexedName6);
// Arrange
auto indexedName7 = Data::IndexedName("EDGE41");
auto indexedName8 = Data::IndexedName("EDGE42");
// Act & Assert
EXPECT_EQ(indexedName7.compare(indexedName8), -1);
EXPECT_FALSE(indexedName7 == indexedName8);
EXPECT_TRUE(indexedName7 != indexedName8);
EXPECT_TRUE(indexedName7 < indexedName8);
// Arrange
auto indexedName9 = Data::IndexedName("EDGE43");
auto indexedName10 = Data::IndexedName("EDGE42");
// Act & Assert
EXPECT_EQ(indexedName9.compare(indexedName10), 1);
EXPECT_FALSE(indexedName9 == indexedName10);
EXPECT_TRUE(indexedName9 != indexedName10);
EXPECT_FALSE(indexedName9 < indexedName10);
}
TEST_F(IndexedNameTest, subscriptOperator)
{
// Arrange
auto indexedName = Data::IndexedName("EDGE42");
// Act & Assert
EXPECT_EQ(indexedName[0], 'E');
EXPECT_EQ(indexedName[1], 'D');
EXPECT_EQ(indexedName[2], 'G');
EXPECT_EQ(indexedName[3], 'E');
}
TEST_F(IndexedNameTest, getType)
{
// Arrange
auto indexedName = Data::IndexedName("EDGE42");
// Act & Assert
EXPECT_STREQ(indexedName.getType(), "EDGE");
}
TEST_F(IndexedNameTest, setIndex)
{
// Arrange
auto indexedName = Data::IndexedName("EDGE42");
EXPECT_EQ(indexedName.getIndex(), 42);
// Act
indexedName.setIndex(1);
// Assert
EXPECT_EQ(indexedName.getIndex(), 1);
}
TEST_F(IndexedNameTest, isNullTrue)
{
// Arrange
auto invalidNames = givenInvalidIndexedNames();
for (const auto &name : invalidNames) {
// Act & Assert
EXPECT_TRUE(name.isNull());
}
}
TEST_F(IndexedNameTest, isNullFalse)
{
// Arrange
auto validNames = givenValidIndexedNames();
for (const auto &name : validNames) {
// Act & Assert
EXPECT_FALSE(name.isNull());
}
}
TEST_F(IndexedNameTest, booleanConversionFalse)
{
// Arrange
auto invalidNames = givenInvalidIndexedNames();
for (const auto &name : invalidNames) {
// Act & Assert
EXPECT_FALSE(static_cast<bool>(name));
}
// Usage example:
auto indexedName = Data::IndexedName(".EDGE",1); // Invalid name
if (indexedName) {
FAIL() << "indexedName as a boolean should have been false for an invalid name";
}
}
TEST_F(IndexedNameTest, booleanConversionTrue)
{
// Arrange
auto validNames = givenValidIndexedNames();
for (const auto& name : validNames) {
// Act & Assert
EXPECT_TRUE(static_cast<bool>(name));
}
}
TEST_F(IndexedNameTest, fromConst)
{
// Arrange
const int testIndex {42};
// Act
auto indexedName = Data::IndexedName::fromConst("TestName", testIndex);
// Assert
EXPECT_STREQ(indexedName.getType(), "TestName");
EXPECT_EQ(indexedName.getIndex(), testIndex);
}
TEST_F(IndexedNameTest, appendToStringBufferEmptyBuffer)
{
// Arrange
std::string bufferStartedEmpty;
Data::IndexedName testName("TEST_NAME", 1);
// Act
testName.appendToStringBuffer(bufferStartedEmpty);
// Assert
EXPECT_EQ(bufferStartedEmpty, "TEST_NAME1");
}
TEST_F(IndexedNameTest, appendToStringBufferNonEmptyBuffer)
{
// Arrange
std::string bufferWithData {"DATA"};
Data::IndexedName testName("TEST_NAME", 1);
// Act
testName.appendToStringBuffer(bufferWithData);
// Assert
EXPECT_EQ(bufferWithData, "DATATEST_NAME1");
}
TEST_F(IndexedNameTest, appendToStringBufferZeroIndex)
{
// Arrange
std::string bufferStartedEmpty;
Data::IndexedName testName("TEST_NAME", 0);
// Act
testName.appendToStringBuffer(bufferStartedEmpty);
// Assert
EXPECT_EQ(bufferStartedEmpty, "TEST_NAME");
}
TEST_F(IndexedNameTest, toString)
{
// Arrange
Data::IndexedName testName("TEST_NAME", 1);
// Act
auto result = testName.toString();
// Assert
EXPECT_EQ(result, "TEST_NAME1");
}
TEST_F(IndexedNameTest, toStringNoIndex)
{
// Arrange
Data::IndexedName testName("TEST_NAME", 0);
// Act
auto result = testName.toString();
// Assert
EXPECT_EQ(result, "TEST_NAME");
}
TEST_F(IndexedNameTest, assignmentOperator)
{
// Arrange
const int testIndex1 {42};
const int testIndex2 {24};
auto indexedName1 = Data::IndexedName::fromConst("TestName", testIndex1);
auto indexedName2 = Data::IndexedName::fromConst("TestName2", testIndex2);
EXPECT_NE(indexedName1, indexedName2); // Ensure the test is set up correctly
// Act
indexedName1 = indexedName2;
// Assert
EXPECT_EQ(indexedName1, indexedName2);
}
class ByteArrayTest : public ::testing::Test {
protected:
// void SetUp() override {}
// void TearDown() override {}
};
TEST_F(ByteArrayTest, QByteArrayConstruction)
{
// Arrange
QByteArray testQBA("Data in a QByteArray");
// Act
Data::ByteArray testByteArray (testQBA);
// Assert
EXPECT_EQ(testQBA, testByteArray.bytes);
}
TEST_F(ByteArrayTest, CopyConstruction)
{
// Arrange
QByteArray testQBA("Data in a QByteArray");
Data::ByteArray originalByteArray (testQBA);
// Act
// NOLINTNEXTLINE performance-unnecessary-copy-initialization
Data::ByteArray copiedByteArray (originalByteArray);
// Assert
EXPECT_EQ(originalByteArray, copiedByteArray);
}
TEST_F(ByteArrayTest, MoveConstruction)
{
// Arrange
QByteArray testQBA("Data in a QByteArray");
Data::ByteArray originalByteArray (testQBA);
const auto *originalDataLocation = originalByteArray.bytes.constData();
// Act
Data::ByteArray copiedByteArray (std::move(originalByteArray));
// Assert
EXPECT_EQ(testQBA, copiedByteArray.bytes);
EXPECT_EQ(originalDataLocation, copiedByteArray.bytes.constData());
}
TEST_F(ByteArrayTest, ensureUnshared)
{
// Arrange
QByteArray testQBA("Data in a QByteArray");
Data::ByteArray originalByteArray (testQBA);
const auto *originalDataLocation = originalByteArray.bytes.constData();
Data::ByteArray copiedByteArray (originalByteArray);
// Act
copiedByteArray.ensureUnshared();
// Assert
EXPECT_EQ(testQBA, copiedByteArray.bytes);
EXPECT_NE(originalDataLocation, copiedByteArray.bytes.constData());
}
TEST_F(ByteArrayTest, equalityOperator)
{
// Arrange
QByteArray testQBA1("Data in a QByteArray");
QByteArray testQBA2("Data in a QByteArray");
QByteArray testQBA3("Not the same data in a QByteArray");
Data::ByteArray byteArray1 (testQBA1);
Data::ByteArray byteArray2 (testQBA2);
Data::ByteArray byteArray3 (testQBA3);
// Act & Assert
EXPECT_TRUE(byteArray1 == byteArray2);
EXPECT_FALSE(byteArray1 == byteArray3);
}
TEST_F(ByteArrayTest, assignmentOperator)
{
// Arrange
QByteArray testQBA1("Data in a QByteArray");
QByteArray testQBA2("Different data in a QByteArray");
Data::ByteArray originalByteArray (testQBA1);
Data::ByteArray newByteArray (testQBA2);
ASSERT_FALSE(originalByteArray == newByteArray);
// Act
newByteArray = originalByteArray;
// Assert
EXPECT_TRUE(originalByteArray == newByteArray);
}
TEST_F(ByteArrayTest, moveAssignmentOperator)
{
// Arrange
QByteArray testQBA1("Data in a QByteArray");
QByteArray testQBA2("Different data in a QByteArray");
Data::ByteArray originalByteArray (testQBA1);
const auto *originalByteArrayLocation = originalByteArray.bytes.constData();
Data::ByteArray newByteArray (testQBA2);
ASSERT_FALSE(originalByteArray == newByteArray);
// Act
newByteArray = std::move(originalByteArray);
// Assert
EXPECT_EQ(originalByteArrayLocation, newByteArray.bytes.constData());
}
// NOLINTEND(readability-magic-numbers)

View File

@@ -1,7 +1,5 @@
target_sources(
Tests_run
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/test1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test2.cpp
${CMAKE_CURRENT_SOURCE_DIR}/fmt.cpp
)