Merge pull request #9521 from AgCaliva/User/Document/Feature_level_units_selection_#7746

Adding "ProjectUnitSystem" support to project files.
This commit is contained in:
sliptonic
2023-10-06 07:56:59 -05:00
committed by GitHub
90 changed files with 2022 additions and 251 deletions

View File

@@ -54,6 +54,8 @@
#include <Base/Stream.h>
#include <Base/Tools.h>
#include <Base/UnitsApi.h>
#include <Language/Translator.h>
#include <Quarter/Quarter.h>
@@ -929,6 +931,19 @@ void Application::slotActiveDocument(const App::Document& Doc)
Py::Module("FreeCADGui").setAttr(std::string("ActiveDocument"),Py::None());
}
}
//Set Unit System.
int projectUnitSystemIndex = doc->second->getProjectUnitSystem();
int ignore = doc->second->getProjectUnitSystemIgnore();
if( projectUnitSystemIndex >= 0 && !ignore ){//is valid
Base::UnitsApi::setSchema(static_cast<Base::UnitSystem>(projectUnitSystemIndex));
}else{// set up Unit system default
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Units");
Base::UnitsApi::setSchema((Base::UnitSystem)hGrp->GetInt("UserSchema",0));
Base::UnitsApi::setDecimals(hGrp->GetInt("Decimals", Base::UnitsApi::getDecimals()));
}
signalActiveDocument(*doc->second);
updateActions();
}

View File

@@ -33,6 +33,7 @@
# include <QStatusBar>
# include <Inventor/actions/SoSearchAction.h>
# include <Inventor/nodes/SoSeparator.h>
# include <xercesc/dom/DOM.hpp>
#endif
#include <App/AutoTransaction.h>
@@ -45,6 +46,7 @@
#include <Base/Exception.h>
#include <Base/Matrix.h>
#include <Base/Reader.h>
#include <Base/DocumentReader.h>
#include <Base/Writer.h>
#include <Base/Tools.h>
@@ -66,7 +68,6 @@
#include "ViewProviderDocumentObjectGroup.h"
#include "WaitCursor.h"
FC_LOG_LEVEL_INIT("Gui", true, true)
using namespace Gui;
@@ -105,6 +106,9 @@ struct DocumentP
std::map<SoSeparator *,ViewProviderDocumentObject*> _CoinMap;
std::map<std::string,ViewProvider*> _ViewProviderMapAnnotation;
std::list<ViewProviderDocumentObject*> _redoViewProviders;
int projectUnitSystem=-1;
bool projectUnitSystemIgnore;
using Connection = boost::signals2::connection;
Connection connectNewObject;
@@ -648,6 +652,30 @@ void Document::setPos(const char* name, const Base::Matrix4D& rclMtrx)
}
void Document::setProjectUnitSystem(int pUS)
{
if(pUS != d->projectUnitSystem && pUS >= 0){
d->projectUnitSystem = pUS;
setModified(true);
}
}
int Document::getProjectUnitSystem() const
{
return d->projectUnitSystem;
}
void Document::setProjectUnitSystemIgnore(bool ignore)
{
d->projectUnitSystemIgnore = ignore;
setModified(true);
}
bool Document::getProjectUnitSystemIgnore() const
{
return d->projectUnitSystemIgnore;
}
//*****************************************************************************************************
// Document
//*****************************************************************************************************
@@ -655,7 +683,6 @@ void Document::slotNewObject(const App::DocumentObject& Obj)
{
auto pcProvider = static_cast<ViewProviderDocumentObject*>(getViewProvider(&Obj));
if (!pcProvider) {
//Base::Console().Log("Document::slotNewObject() called\n");
std::string cName = Obj.getViewProviderNameStored();
for(;;) {
if (cName.empty()) {
@@ -738,7 +765,6 @@ void Document::slotDeletedObject(const App::DocumentObject& Obj)
{
std::list<Gui::BaseView*>::iterator vIt;
setModified(true);
//Base::Console().Log("Document::slotDeleteObject() called\n");
// cycling to all views of the document
ViewProvider* viewProvider = getViewProvider(&Obj);
@@ -1377,6 +1403,7 @@ void Document::Save (Base::Writer &writer) const
void Document::Restore(Base::XMLReader &reader)
{
reader.addFile("GuiDocument.xml",this);
// hide all elements to avoid to update the 3d view when loading data files
// RestoreDocFile then restores the visibility status again
std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::iterator it;
@@ -1391,13 +1418,20 @@ void Document::Restore(Base::XMLReader &reader)
*/
void Document::RestoreDocFile(Base::Reader &reader)
{
readUsing_DocumentReader(reader);
//readUsing_XMLReader(reader);
setModified(false);
}
void Document::readUsing_XMLReader(Base::Reader &reader){
// We must create an XML parser to read from the input stream
std::shared_ptr<Base::XMLReader> localreader = std::make_shared<Base::XMLReader>("GuiDocument.xml", reader);
localreader->FileVersion = reader.getFileVersion();
//localreader->FileVersion = reader.getFileVersion();
localreader->readElement("Document");
long scheme = localreader->getAttributeAsInteger("SchemaVersion");
localreader->DocumentSchema = scheme;
//localreader->DocumentSchema = scheme;
bool hasExpansion = localreader->hasAttribute("HasExpansion");
if(hasExpansion) {
@@ -1414,29 +1448,37 @@ void Document::RestoreDocFile(Base::Reader &reader)
//
// SchemeVersion "1"
if (scheme == 1) {
// read the viewproviders itself
localreader->readElement("ViewProviderData");
int Cnt = localreader->getAttributeAsInteger("Count");
for (int i=0; i<Cnt; i++) {
localreader->readElement("ViewProvider");
std::string name = localreader->getAttribute("name");
bool expanded = false;
if (!hasExpansion && localreader->hasAttribute("expanded")) {
const char* attr = localreader->getAttribute("expanded");
if (strcmp(attr,"1") == 0) {
expanded = true;
}
}
ViewProvider* pObj = getViewProviderByName(name.c_str());
if (pObj) // check if this feature has been registered
if (pObj){// check if this feature has been registered
pObj->Restore(*localreader);
}
if (pObj && expanded) {
auto vp = static_cast<Gui::ViewProviderDocumentObject*>(pObj);
this->signalExpandObject(*vp, TreeItemMode::ExpandItem,0,0);
}
localreader->readEndElement("ViewProvider");
}
localreader->readEndElement("ViewProviderData");
// read camera settings
localreader->readElement("Camera");
@@ -1452,17 +1494,119 @@ void Document::RestoreDocFile(Base::Reader &reader)
it->onMsg(cameraSettings.c_str(), pReturnIgnore);
}
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
}
}
}
localreader->readEndElement("Document");
// reset modified flag
reader.initLocalReader(localreader);
setModified(false);
}
void Document::readUsing_DocumentReader(Base::Reader &reader){
std::shared_ptr<Base::DocumentReader> docReader = std::make_shared<Base::DocumentReader>();
docReader->LoadDocument(reader);
//docReader->GetRootElement()//can be used to get Document XMLElement, but not needed.
const char* SchemaVersion_cstr = docReader->GetAttribute("SchemaVersion");
long SchemaVersion = docReader->ContentToInt( SchemaVersion_cstr );
const char* HasExpansion_cstr = docReader->GetAttribute("HasExpansion");
if(HasExpansion_cstr){
auto tree = TreeWidget::instance();
if(tree) {
auto docItem = tree->getDocumentItem(this);
if(docItem)
docItem->Restore(*docReader);
}
}
// At this stage all the document objects and their associated view providers exist.
// Now we must restore the properties of the view providers only.
if (SchemaVersion == 1) {
auto VProviderDataDOM = docReader->FindElement("ViewProviderData");
if(VProviderDataDOM){
const char* vpd_count_cstr = docReader->GetAttribute(VProviderDataDOM,"Count");
if(vpd_count_cstr){
long Cnt = docReader->ContentToInt( vpd_count_cstr );
auto prev_ViewProviderDOM = docReader->FindElement(VProviderDataDOM,"ViewProvider");
if(prev_ViewProviderDOM){
const char* name_cstr = docReader->GetAttribute(prev_ViewProviderDOM,"name");
const char* expanded_cstr = docReader->GetAttribute(prev_ViewProviderDOM,"expanded");
bool expanded = false;
if (!HasExpansion_cstr && expanded_cstr) {
if (strcmp(expanded_cstr,"1") == 0) {
expanded = true;
}
}
ViewProvider* pObj = getViewProviderByName(name_cstr);
if (pObj){
pObj->Restore(*docReader,prev_ViewProviderDOM);
}
if (pObj && expanded) {
auto vp = static_cast<Gui::ViewProviderDocumentObject*>(pObj);
this->signalExpandObject(*vp, TreeItemMode::ExpandItem,0,0);
}
for (int i=1; i<Cnt; i++) {
auto ViewProviderDOM_i = docReader->FindNextElement(prev_ViewProviderDOM,"ViewProvider");
if(ViewProviderDOM_i){
const char* name_cstr_i = docReader->GetAttribute(ViewProviderDOM_i,"name");
const char* expanded_cstr_i = docReader->GetAttribute(ViewProviderDOM_i,"expanded");
bool expanded = false;
if (!HasExpansion_cstr && expanded_cstr_i) {
if (strcmp(expanded_cstr_i,"1") == 0) {
expanded = true;
}
}
ViewProvider* pObj = getViewProviderByName(name_cstr_i);
if (pObj){
pObj->Restore(*docReader,ViewProviderDOM_i);
}
if (pObj && expanded) {
auto vp = static_cast<Gui::ViewProviderDocumentObject*>(pObj);
this->signalExpandObject(*vp, TreeItemMode::ExpandItem,0,0);
}
prev_ViewProviderDOM = ViewProviderDOM_i;
}
}
}
}
}
// read camera settings
auto CameraDOM = docReader->FindElement("Camera");
if(CameraDOM){
const char* ppReturn = docReader->GetAttribute(CameraDOM,"settings");
cameraSettings.clear();
if(ppReturn && ppReturn[0]) {
saveCameraSettings(ppReturn);
try {
const char** pReturnIgnore=nullptr;
std::list<MDIView*> mdi = getMDIViews();
for (const auto & it : mdi) {
if (it->onHasMsg("SetCamera"))
it->onMsg(cameraSettings.c_str(), pReturnIgnore);
}
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
}
}
}
auto ProjectUnitSysDOM = docReader->FindElement("ProjectUnitSystem");
if(ProjectUnitSysDOM){
const char* US_cstr = docReader->GetAttribute(ProjectUnitSysDOM,"US");
const char* ignore_cstr = docReader->GetAttribute(ProjectUnitSysDOM,"ignore");
d->projectUnitSystem = docReader->ContentToInt( US_cstr );
d->projectUnitSystemIgnore = docReader->ContentToInt( ignore_cstr );
}
}
reader.initLocalDocReader(docReader);
}
void Document::slotStartRestoreDocument(const App::Document& doc)
@@ -1578,6 +1722,15 @@ void Document::SaveDocFile (Base::Writer &writer) const
writer.Stream() << writer.ind() << "<Camera settings=\""
<< encodeAttribute(getCameraSettings()) << "\"/>\n";
writer.decInd(); // indentation for camera settings
if( d->projectUnitSystem >= 0 ){
writer.incInd(); // indentation for ProjectUnitSystem
writer.Stream() << writer.ind() << "<ProjectUnitSystem US=\""
<< d->projectUnitSystem << "\" ignore=\""
<< d->projectUnitSystemIgnore << "\"/>\n";
writer.decInd(); // indentation for ProjectUnitSystem
}
writer.Stream() << "</Document>" << std::endl;
}

View File

@@ -158,6 +158,8 @@ public:
void SaveDocFile (Base::Writer &writer) const override;
/// This method is used to restore large amounts of data from a binary file.
void RestoreDocFile(Base::Reader &reader) override;
void readUsing_XMLReader(Base::Reader &reader);
void readUsing_DocumentReader(Base::Reader &reader);
void exportObjects(const std::vector<App::DocumentObject*>&, Base::Writer&);
void importObjects(const std::vector<App::DocumentObject*>&, Base::Reader&,
const std::map<std::string, std::string>& nameMapping);
@@ -297,6 +299,12 @@ public:
const char *getCameraSettings() const;
bool saveCameraSettings(const char *) const;
void setProjectUnitSystem(int);
int getProjectUnitSystem() const;
void setProjectUnitSystemIgnore(bool);
bool getProjectUnitSystemIgnore() const;
protected:
// pointer to the python class

View File

@@ -38,6 +38,8 @@
#include <Base/Parameter.h>
#include <Base/UnitsApi.h>
#include <Gui/Document.h>
#include <Gui/Action.h>
#include <Gui/Application.h>
#include <Gui/DlgCreateNewPreferencePackImp.h>
@@ -93,6 +95,7 @@ DlgSettingsGeneral::DlgSettingsGeneral( QWidget* parent )
for (int i = 0; i < num; i++) {
QString item = Base::UnitsApi::getDescription(static_cast<Base::UnitSystem>(i));
ui->comboBox_UnitSystem->addItem(item, i);
ui->comboBox_projectUnitSystem->addItem(item, i);
}
// Enable/disable the fractional inch option depending on system
@@ -203,7 +206,21 @@ void DlgSettingsGeneral::saveSettings()
// Set and save the Unit System
viewSystemIndex = ui->comboBox_UnitSystem->currentIndex();
UnitsApi::setSchema(static_cast<UnitSystem>(viewSystemIndex));
auto activeDoc = Gui::Application::Instance->activeDocument();
bool projectUnitSystemIgnore = ui->checkBox_projectUnitSystemIgnore->isChecked();
if(activeDoc){
activeDoc->setProjectUnitSystemIgnore( projectUnitSystemIgnore );
if(!projectUnitSystemIgnore){
int projectUnitSystemIndex = ui->comboBox_projectUnitSystem->currentIndex();
activeDoc->setProjectUnitSystem( projectUnitSystemIndex );
UnitsApi::setSchema(static_cast<UnitSystem>(projectUnitSystemIndex));
}else{
UnitsApi::setSchema(static_cast<UnitSystem>(viewSystemIndex));
}
}else{
UnitsApi::setSchema(static_cast<UnitSystem>(viewSystemIndex));
}
//
ui->SubstituteDecimal->onSave();
ui->UseLocaleFormatting->onSave();
@@ -252,6 +269,24 @@ void DlgSettingsGeneral::loadSettings()
// handy little equation.
cbIndex = std::log2(FracInch) - 1;
ui->comboBox_FracInch->setCurrentIndex(cbIndex);
auto activeDoc = Gui::Application::Instance->activeDocument();
if(activeDoc){
int us = activeDoc->getProjectUnitSystem();
if(us >= 0){//Valid unit system:
ui->comboBox_projectUnitSystem->setCurrentIndex( us );
int pusIgnore = activeDoc->getProjectUnitSystemIgnore();
ui->checkBox_projectUnitSystemIgnore->setChecked( pusIgnore );
}else{
ui->comboBox_projectUnitSystem->setCurrentIndex( 0 );
ui->checkBox_projectUnitSystemIgnore->setChecked( false );
}
}else{
ui->checkBox_projectUnitSystemIgnore->setEnabled(false);
ui->comboBox_projectUnitSystem->setEnabled(false);
}
ui->SubstituteDecimal->onRestore();
@@ -389,9 +424,11 @@ void DlgSettingsGeneral::changeEvent(QEvent *event)
if (event->type() == QEvent::LanguageChange) {
int index = ui->UseLocaleFormatting->currentIndex();
int index2 = ui->comboBox_UnitSystem->currentIndex();
int pusIndex = ui->comboBox_projectUnitSystem->currentIndex();
ui->retranslateUi(this);
ui->UseLocaleFormatting->setCurrentIndex(index);
ui->comboBox_UnitSystem->setCurrentIndex(index2);
ui->comboBox_projectUnitSystem->setCurrentIndex(pusIndex);
}
else {
QWidget::changeEvent(event);
@@ -600,6 +637,19 @@ void DlgSettingsGeneral::onUnitSystemIndexChanged(int index)
}
}
void DlgSettingsGeneral::on_checkBox_projectUnitSystemIgnore_stateChanged(int state)
{
if (state < 0)
return; // happens when clearing the combo box in retranslateUi()
// Enable/disable the projectUnitSystem if being ignored:
if(state == 2){//ignore
ui->comboBox_projectUnitSystem->setEnabled(false);
}else if(state == 0){
ui->comboBox_projectUnitSystem->setEnabled(true);
}
}
void DlgSettingsGeneral::onThemeChanged(int index) {
Q_UNUSED(index);
themeChanged = true;

View File

@@ -70,6 +70,7 @@ protected Q_SLOTS:
public Q_SLOTS:
void onUnitSystemIndexChanged(int index);
void on_checkBox_projectUnitSystemIgnore_stateChanged(int state);
private:
void saveDockWindowVisibility();

View File

@@ -87,14 +87,42 @@
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Project Unit system:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBox_projectUnitSystem">
<property name="toolTip">
<string>Unit system used for display metrics stored in project</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QCheckBox" name="checkBox_projectUnitSystemIgnore">
<property name="toolTip">
<string>If enabled, Unit System stored in project will be ignored.</string>
</property>
<property name="text">
<string>Ignore</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="fractionalInchLabel">
<property name="text">
<string>Minimum fractional inch:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QComboBox" name="comboBox_FracInch">
<property name="toolTip">
<string>Minimum fractional inch to be displayed</string>
@@ -136,14 +164,14 @@
</item>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="TextLabel1_5">
<property name="text">
<string>Number format:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="Gui::PrefComboBox" name="UseLocaleFormatting">
<property name="prefEntry" stdset="0">
<cstring>UseLocaleFormatting</cstring>
@@ -168,7 +196,7 @@
</item>
</widget>
</item>
<item row="3" column="2">
<item row="4" column="2">
<widget class="Gui::PrefCheckBox" name="SubstituteDecimal">
<property name="toolTip">
<string>If enabled, numerical keypad decimal separator

View File

@@ -28,6 +28,8 @@
# include <QGridLayout>
# include <memory>
#endif
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <App/Application.h>
#include <Base/Parameter.h>
@@ -35,8 +37,7 @@
#include <Gui/MainWindow.h>
#include <Gui/View3DSettings.h>
#include <Gui/NavigationStyle.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include "DlgSettingsNavigation.h"
#include "ui_DlgSettingsNavigation.h"

View File

@@ -35,6 +35,11 @@
# include <Inventor/events/SoKeyboardEvent.h>
#endif
// clang-format off
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
// clang-format on
#include <Base/Console.h>
#include <Base/Precision.h>
#include <Base/Quantity.h>
@@ -44,9 +49,9 @@
#include <Gui/BitmapFactory.h>
#include <Gui/Camera.h>
#include <Gui/Document.h>
#include <Gui/SoDatumLabel.h>
#include <Gui/EditableDatumLabel.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Gui/ViewProviderDocumentObject.h>
#include <Gui/TaskView/TaskView.h>

View File

@@ -66,6 +66,10 @@
#include "Widgets.h"
#include "Workbench.h"
#include <Base/DocumentReader.h>
#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/dom/DOM.hpp>
FC_LOG_LEVEL_INIT("Tree", false, true, true)
@@ -351,6 +355,33 @@ public:
}
reader.readEndElement("Expand", level - 1);
}
void restore(Base::DocumentReader& reader, XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *expandEl) {
const char* count_cstr = reader.GetAttribute(expandEl,"count");
if(count_cstr){
long count = reader.ContentToInt( count_cstr );
auto prev_ExpandDOM = reader.FindElement(expandEl,"Expand");
const char* name_cstr = reader.GetAttribute(prev_ExpandDOM,"name");
const char* _count_cstr = reader.GetAttribute(prev_ExpandDOM,"count");
auto& entry = (*this)[name_cstr];
if(_count_cstr){
entry.reset(new ExpandInfo);
entry->restore(reader,prev_ExpandDOM);
}
for (int i = 1; i < count; ++i) {
auto ExpandDOM_i = reader.FindNextElement(prev_ExpandDOM,"Expand");
const char* name_cstr = reader.GetAttribute(ExpandDOM_i,"name");
const char* _count_cstr = reader.GetAttribute(ExpandDOM_i,"count");
auto& entry = (*this)[name_cstr];
if(_count_cstr){
entry.reset(new ExpandInfo);
entry->restore(reader,ExpandDOM_i);
}
prev_ExpandDOM = ExpandDOM_i;
}
}
}
};
// ---------------------------------------------------------------------------
@@ -3951,6 +3982,21 @@ void DocumentItem::Restore(Base::XMLReader& reader) {
}
}
void DocumentItem::Restore(Base::DocumentReader& reader) {
auto expandEl = reader.FindElement("Expand");
if( !reader.GetAttribute(expandEl,"count") )
return;
_ExpandInfo.reset(new ExpandInfo);
_ExpandInfo->restore(reader,expandEl);
for (auto inst : TreeWidget::Instances) {
if (inst != getTree()) {
auto docItem = inst->getDocumentItem(document());
if (docItem)
docItem->_ExpandInfo = _ExpandInfo;
}
}
}
void DocumentItem::restoreItemExpansion(const ExpandInfoPtr& info, DocumentObjectItem* item) {
item->setExpanded(true);
if (!info)

View File

@@ -297,6 +297,7 @@ public:
unsigned int getMemSize () const override;
void Save (Base::Writer &) const override;
void Restore(Base::XMLReader &) override;
void Restore(Base::DocumentReader& reader) override;
class ExpandInfo;
using ExpandInfoPtr = std::shared_ptr<ExpandInfo>;

View File

@@ -837,6 +837,18 @@ void ViewProvider::Restore(Base::XMLReader& reader) {
// setStatus(Gui::isRestoring, false);
}
void ViewProvider::Restore(Base::DocumentReader& reader, XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *viewProviderEl) {
// Because some PropertyLists type properties are stored in a separate file,
// and is thus restored outside this function. So we rely on Gui::Document
// to set the isRestoring flags for us.
//
// setStatus(Gui::isRestoring, true);
TransactionalObject::Restore(reader,viewProviderEl);
// setStatus(Gui::isRestoring, false);
}
void ViewProvider::updateData(const App::Property* prop)
{
auto vector = getExtensionsDerivedFromType<Gui::ViewProviderExtension>();

View File

@@ -500,6 +500,7 @@ public:
//restoring the object from document:
//this may be of interest to extensions, hence call them
void Restore(Base::XMLReader& reader) override;
void Restore(Base::DocumentReader& reader,XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *viewProviderEl);
bool isRestoring() {return testStatus(Gui::isRestoring);}