Object-Oriented Design in CAx Systems
CAx applications require robust management of domain-specific data and associated business logic. Following object-oriented principles, data is modeled as objects with properties, organized hierarchically through a data object model. User interfaces interact with these objects by presenting them and responding to user events.
Core Property Management Components
Property Abstraction
FreeCAD implements property management using the Observer patttern as part of its reflection mechanism. The base property class notifies containers of value changes:
void DataProperty::updateValue()
{
PropertyLock guard(this);
if (container) {
container->handleChange(this);
if (!isUpdating()) {
UpdateLock updateLock(statusFlags);
emitChangeSignal(*this);
}
}
markAsModified();
}
void DataProperty::prepareValueChange()
{
if (container)
container->preChangeHandler(this);
}
Property Implementations
Concrete properties encapsulate primitive types using proxy patterns. For example, the integer property implementation:
void IntProperty::assign(int newValue)
{
prepareValueChange();
storedValue = newValue;
updateValue();
}
int IntProperty::value() const
{
return storedValue;
}
Property Container Interface
The container interface provides methods to respond to property change notifications.
Selection Handling
SelectionSingleton provides a unified interface for selection operations. SelectionObserver monitors changes through the observer pattern to synchronize with UI elements.
Property Display Architecture
View Components
The property view contains editors for both model data (App::DocumentObject) and display data (Gui::ViewProviderDocumentObject).
Tree View Implementation
The property editor extends QTreeView to display properties hierarchically:
void PropertyBrowser::refresh(PropertyModel::ItemList &&items, bool verifyDoc)
{
documentCheck = verifyDoc;
if (inTransaction) {
qWarning("Selection changed during property commit");
refreshPending = true;
return;
}
QModelIndex current = currentIndex();
QStringList path = model->getPathFromIndex(current);
if (!path.isEmpty())
currentSelection = path;
model->rebuild(std::move(items));
if (!currentSelection.isEmpty()) {
QModelIndex idx = model->getIndexFromPath(currentSelection);
setCurrentIndex(idx);
}
displayedItems = std::move(items);
propertyOwners.clear();
for (auto &entry : displayedItems) {
for (auto prop : entry.properties) {
auto owner = prop->owner();
if (!owner) continue;
if (documentCheck && owner->isDocumentObjectType())
propertyOwners.insert(static_cast<:documentobject>(owner)->document());
propertyOwners.insert(owner);
}
}
if (autoExpand)
expandAll();
}</:documentobject>
Model-Item Mapping
The property model maps application properties to view items:
PropertyItem* createViewItem(App::Property* property)
{
const char* editorType = property->editorType();
if (!editorType || !*editorType) {
if (PropertyView::displayAll())
editorType = "Gui::PropertyEditor::PropertyItem";
else
return nullptr;
}
auto item = static_cast<propertyitem>(
PropertyItemFactory::instance().createItem(editorType));
if (!item) {
qWarning("Missing property editor for type %s", editorType);
}
return item;
}</propertyitem>
Item Factory Initialization
Property items are registered through factory initialization:
void initializePropertyItems()
{
PropertyItem::registerClass();
PropertySeparatorItem::registerClass();
PropertyStringItem::registerClass();
PropertyIntegerItem::registerClass();
// Additional item registrations...
}
Factory Registration Macros
#define PROPERTY_ITEM_DECLARE \
public: \
static void* createInstance(); \
static void registerClass();
#define PROPERTY_ITEM_DEFINE(_ClassName_) \
void* _ClassName_::createInstance() { \
return new _ClassName_(); \
} \
void _ClassName_::registerClass() { \
new PropertyItemFactory::Producer<_ClassName_>(#_ClassName_); \
}
Property Interaction Flow
When objects are selected in tree or 3D views, property editors display associated attributes. Property modifications in editors trigger value updates through property setters, which notify containers of changes. Property changes propagate through the system to update visual representations.