Skip to content

Commit

Permalink
Merge branch 'feature/#153' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
HuguesDelorme committed Apr 4, 2024
2 parents 04e8d1d + c901aa2 commit 496ffad
Show file tree
Hide file tree
Showing 14 changed files with 718 additions and 288 deletions.
Binary file modified i18n/mayo_en.qm
Binary file not shown.
277 changes: 159 additions & 118 deletions i18n/mayo_en.ts

Large diffs are not rendered by default.

Binary file modified i18n/mayo_fr.qm
Binary file not shown.
283 changes: 163 additions & 120 deletions i18n/mayo_fr.ts

Large diffs are not rendered by default.

39 changes: 28 additions & 11 deletions src/app/app_module_properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ AppModuleProperties::AppModuleProperties(Settings* settings)
settings->addSetting(&this->recentFiles, groupId_application);
settings->addSetting(&this->lastOpenDir, groupId_application);
settings->addSetting(&this->lastSelectedFormatFilter, groupId_application);
settings->addSetting(&this->reloadDocumentOnFileChange, groupId_application);
settings->addSetting(&this->linkWithDocumentSelector, groupId_application);
settings->addSetting(&this->forceOpenGlFallbackWidget, groupId_application);
this->recentFiles.setUserVisible(false);
Expand Down Expand Up @@ -82,6 +83,7 @@ AppModuleProperties::AppModuleProperties(Settings* settings)
this->recentFiles.setValue({});
this->lastOpenDir.setValue({});
this->lastSelectedFormatFilter.setValue({});
this->reloadDocumentOnFileChange.setValue(true);
this->linkWithDocumentSelector.setValue(true);
#ifndef MAYO_OS_MAC
this->forceOpenGlFallbackWidget.setValue(false);
Expand Down Expand Up @@ -159,10 +161,16 @@ void AppModuleProperties::retranslate()

// Application
this->language.setDescription(
textIdTr("Language used for the application. Change will take effect after application restart"));
textIdTr("Language used for the application. Change will take effect after application restart")
);
this->reloadDocumentOnFileChange.setDescription(
textIdTr("Monitors the file system for changes to documents opened in the application\n\n"
"When such a file change is detected then the application proposes to reload(open again) the document")
);
this->linkWithDocumentSelector.setDescription(
textIdTr("In case where multiple documents are opened, make sure the document displayed in "
"the 3D view corresponds to what is selected in the model tree"));
"the 3D view corresponds to what is selected in the model tree")
);
this->forceOpenGlFallbackWidget.setDescription(
textIdTr("Force usage of the fallback Qt widget to display OpenGL graphics.\n\n"
"When `OFF` the application will try to use OpenGL framebuffer for rendering, "
Expand All @@ -178,33 +186,42 @@ void AppModuleProperties::retranslate()

// Meshing
this->meshingQuality.setDescription(
textIdTr("Controls precision of the mesh to be computed from the BRep shape"));
textIdTr("Controls precision of the mesh to be computed from the BRep shape")
);
this->meshingChordalDeflection.setDescription(
textIdTr("For the tessellation of faces the chordal deflection limits the distance between "
"a curve and its tessellation"));
"a curve and its tessellation")
);
this->meshingAngularDeflection.setDescription(
textIdTr("For the tessellation of faces the angular deflection limits the angle between "
"subsequent segments in a polyline"));
"subsequent segments in a polyline")
);
this->meshingRelative.setDescription(
textIdTr("Relative computation of edge tolerance\n\n"
"If activated, deflection used for the polygonalisation of each edge will be "
"`ChordalDeflection` × `SizeOfEdge`. The deflection used for the faces will be "
"the maximum deflection of their edges."));
"the maximum deflection of their edges.")
);

// Graphics
this->navigationStyle.setDescription(
textIdTr("3D view manipulation shortcuts configuration to mimic other common CAD applications"));
textIdTr("3D view manipulation shortcuts configuration to mimic other common CAD applications")
);
this->turnViewAngleIncrement.setDescription(
textIdTr("Angle increment used to turn(rotate) the 3D view around the normal of the view plane(Z axis frame reference)"));
textIdTr("Angle increment used to turn(rotate) the 3D view around the normal of the view plane(Z axis frame reference)")
);

// -- Graphics/ClipPlanes
this->defaultShowOriginTrihedron.setDescription(
textIdTr("Show or hide by default the trihedron centered at world origin. "
"This doesn't affect 3D view of currently opened documents"));
"This doesn't affect 3D view of currently opened documents")
);
this->clipPlanesCappingOn.setDescription(
textIdTr("Enable capping of currently clipped graphics"));
textIdTr("Enable capping of currently clipped graphics")
);
this->clipPlanesCappingHatchOn.setDescription(
textIdTr("Enable capping hatch texture of currently clipped graphics"));
textIdTr("Enable capping hatch texture of currently clipped graphics")
);
}

void AppModuleProperties::onPropertyChanged(Property* prop)
Expand Down
1 change: 1 addition & 0 deletions src/app/app_module_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class AppModuleProperties : public PropertyGroup {
PropertyRecentFiles recentFiles{ this, textId("recentFiles") };
PropertyFilePath lastOpenDir{ this, textId("lastOpenFolder") };
PropertyString lastSelectedFormatFilter{ this, textId("lastSelectedFormatFilter") };
PropertyBool reloadDocumentOnFileChange{ this, textId("reloadDocumentOnFileChange") };
PropertyBool linkWithDocumentSelector{ this, textId("linkWithDocumentSelector") };
PropertyBool forceOpenGlFallbackWidget{ this, textId("forceOpenGlFallbackWidget") };
// Meshing
Expand Down
87 changes: 54 additions & 33 deletions src/app/commands_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ struct OpenFileNames {

static OpenFileNames get(
QWidget* parentWidget,
OpenFileNames::GetOption option = OpenFileNames::GetMany)
OpenFileNames::GetOption option = OpenFileNames::GetMany
)
{
OpenFileNames result;
result.selectedFormat = IO::Format_Unknown;
Expand All @@ -118,14 +119,16 @@ struct OpenFileNames {
if (option == OpenFileNames::GetOne) {
const QString strFilepath =
QFileDialog::getOpenFileName(
parentWidget, dlgTitle, dlgOpenDir, dlgFilter, dlgPtrSelFilter);
parentWidget, dlgTitle, dlgOpenDir, dlgFilter, dlgPtrSelFilter
);
result.listFilepath.clear();
result.listFilepath.push_back(filepathFrom(strFilepath));
}
else {
const QStringList listStrFilePath =
QFileDialog::getOpenFileNames(
parentWidget, dlgTitle, dlgOpenDir, dlgFilter, dlgPtrSelFilter);
parentWidget, dlgTitle, dlgOpenDir, dlgFilter, dlgPtrSelFilter
);
result.listFilepath.clear();
for (const QString& strFilePath : listStrFilePath)
result.listFilepath.push_back(filepathFrom(strFilePath));
Expand Down Expand Up @@ -211,9 +214,52 @@ void FileCommandTools::openDocumentsFromList(IAppContext* context, Span<const Fi
} // endfor()
}

void FileCommandTools::openDocument(IAppContext* context, const FilePath& fp)
void FileCommandTools::openDocument(IAppContext* context, const FilePath& filePath)
{
FileCommandTools::openDocumentsFromList(context, Span<const FilePath>(&fp, 1));
FileCommandTools::openDocumentsFromList(context, Span<const FilePath>(&filePath, 1));
}

void FileCommandTools::importInDocument(
IAppContext* context, const DocumentPtr& targetDoc, Span<const FilePath> listFilePaths
)
{
auto appModule = AppModule::get();
const Document::Identifier targetDocId = targetDoc->identifier();
const TaskId taskId = context->taskMgr()->newTask([=](TaskProgress* progress) {
QElapsedTimer chrono;
chrono.start();

auto doc = Application::instance()->findDocumentByIdentifier(targetDocId);
const bool okImport = appModule->ioSystem()->importInDocument()
.targetDocument(doc)
.withFilepaths(listFilePaths)
.withParametersProvider(appModule)
.withEntityPostProcess([=](TDF_Label labelEntity, TaskProgress* progress) {
appModule->computeBRepMesh(labelEntity, progress);
})
.withEntityPostProcessRequiredIf(&IO::formatProvidesBRep)
.withEntityPostProcessInfoProgress(20, Command::textIdTr("Mesh BRep shapes"))
.withMessenger(appModule)
.withTaskProgress(progress)
.execute();
if (okImport)
appModule->emitInfo(fmt::format(Command::textIdTr("Import time: {}ms"), chrono.elapsed()));
});
const QString taskTitle =
listFilePaths.size() > 1 ?
Command::tr("Import") :
filepathTo<QString>(listFilePaths.front().stem());
context->taskMgr()->setTitle(taskId, to_stdString(taskTitle));
context->taskMgr()->run(taskId);
}

void FileCommandTools::importInDocument(
IAppContext* context,
const DocumentPtr& targetDoc,
const FilePath& filePath
)
{
FileCommandTools::importInDocument(context, targetDoc, Span<const FilePath>(&filePath, 1));
}

CommandNewDocument::CommandNewDocument(IAppContext* context)
Expand Down Expand Up @@ -354,40 +400,15 @@ void CommandImportInCurrentDocument::execute()
if (resFileNames.listFilepath.empty())
return;

auto appModule = AppModule::get();
const TaskId taskId = this->taskMgr()->newTask([=](TaskProgress* progress) {
QElapsedTimer chrono;
chrono.start();

const bool okImport = appModule->ioSystem()->importInDocument()
.targetDocument(guiDoc->document())
.withFilepaths(resFileNames.listFilepath)
.withParametersProvider(appModule)
.withEntityPostProcess([=](TDF_Label labelEntity, TaskProgress* progress) {
appModule->computeBRepMesh(labelEntity, progress);
})
.withEntityPostProcessRequiredIf(&IO::formatProvidesBRep)
.withEntityPostProcessInfoProgress(20, Command::textIdTr("Mesh BRep shapes"))
.withMessenger(appModule)
.withTaskProgress(progress)
.execute();
if (okImport)
appModule->emitInfo(fmt::format(Command::textIdTr("Import time: {}ms"), chrono.elapsed()));
});
const QString taskTitle =
resFileNames.listFilepath.size() > 1 ?
Command::tr("Import") :
filepathTo<QString>(resFileNames.listFilepath.front().stem());
this->taskMgr()->setTitle(taskId, to_stdString(taskTitle));
this->taskMgr()->run(taskId);
FileCommandTools::importInDocument(this->context(), guiDoc->document(), resFileNames.listFilepath);
for (const FilePath& fp : resFileNames.listFilepath)
appModule->prependRecentFile(fp);
AppModule::get()->prependRecentFile(fp);
}

bool CommandImportInCurrentDocument::getEnabledStatus() const
{
return this->app()->documentCount() != 0
&& this->context()->currentPage() == IAppContext::Page::Documents;
&& this->context()->currentPage() == IAppContext::Page::Documents;
}

CommandExportSelectedApplicationItems::CommandExportSelectedApplicationItems(IAppContext* context)
Expand Down
12 changes: 11 additions & 1 deletion src/app/commands_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,17 @@ class FileCommandTools {
public:
static void closeDocument(IAppContext* context, Document::Identifier docId);
static void openDocumentsFromList(IAppContext* context, Span<const FilePath> listFilePath);
static void openDocument(IAppContext* context, const FilePath& fp);
static void openDocument(IAppContext* context, const FilePath& filePath);
static void importInDocument(
IAppContext* context,
const DocumentPtr& targetDoc,
Span<const FilePath> listFilePaths
);
static void importInDocument(
IAppContext* context,
const DocumentPtr& targetDoc,
const FilePath& filePath
);
};

class CommandNewDocument : public Command {
Expand Down
117 changes: 117 additions & 0 deletions src/app/document_files_watcher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/****************************************************************************
** Copyright (c) 2024, Fougue Ltd. <https://www.fougue.pro>
** All rights reserved.
** See license at https://github.com/fougue/mayo/blob/master/LICENSE.txt
****************************************************************************/

#include "document_files_watcher.h"

#include "../base/application.h"
#include "../qtcommon/filepath_conv.h"

#include <QtCore/QFileSystemWatcher>

namespace Mayo {

DocumentFilesWatcher::DocumentFilesWatcher(const ApplicationPtr& app, QObject* parent)
: QObject(parent),
m_app(app)
{
app->signalDocumentAdded.connectSlot(&DocumentFilesWatcher::onDocumentAdded, this);
app->signalDocumentAboutToClose.connectSlot(&DocumentFilesWatcher::onDocumentAboutToClose, this);
app->signalDocumentFilePathChanged.connectSlot(&DocumentFilesWatcher::onDocumentFilePathChanged, this);
}

void DocumentFilesWatcher::enable(bool on)
{
if (m_isEnabled == on)
return;

m_isEnabled = on;
if (on) {
for (Application::DocumentIterator itDoc(m_app); itDoc.hasNext(); itDoc.next()) {
const FilePath& docFilePath = itDoc.current()->filePath();
const QString strDocFilePath = filepathTo<QString>(docFilePath);
if (filepathExists(docFilePath))
this->fileSystemWatcher()->addPath(strDocFilePath);
}
}
else {
this->destroyFileSystemWatcher();
m_vecNonAckDocumentChanged.clear();
}
}

bool DocumentFilesWatcher::isEnabled() const
{
return m_isEnabled;
}

void DocumentFilesWatcher::acknowledgeDocumentFileChange(const DocumentPtr& doc)
{
auto it = std::find(m_vecNonAckDocumentChanged.begin(), m_vecNonAckDocumentChanged.end(), doc);
if (it != m_vecNonAckDocumentChanged.end())
m_vecNonAckDocumentChanged.erase(it);
}

QFileSystemWatcher* DocumentFilesWatcher::fileSystemWatcher()
{
if (!m_fileSystemWatcher) {
m_fileSystemWatcher = new QFileSystemWatcher(this);
QObject::connect(
m_fileSystemWatcher, &QFileSystemWatcher::fileChanged,
this, &DocumentFilesWatcher::onFileChanged
);
}

return m_fileSystemWatcher;
}

void DocumentFilesWatcher::destroyFileSystemWatcher()
{
delete m_fileSystemWatcher;
m_fileSystemWatcher = nullptr;
}

void DocumentFilesWatcher::onFileChanged(const QString& strFilePath)
{
if (m_isEnabled) {
const FilePath docFilePath = filepathFrom(strFilePath);
DocumentPtr doc = m_app->findDocumentByLocation(docFilePath);
if (this->isDocumentChangeAcknowledged(doc)) {
m_vecNonAckDocumentChanged.push_back(doc);
this->signalDocumentFileChanged.send(doc);
}
}
}

bool DocumentFilesWatcher::isDocumentChangeAcknowledged(const DocumentPtr& doc) const
{
auto it = std::find(m_vecNonAckDocumentChanged.cbegin(), m_vecNonAckDocumentChanged.cend(), doc);
return it == m_vecNonAckDocumentChanged.cend();
}

void DocumentFilesWatcher::onDocumentFilePathChanged(const DocumentPtr&, const FilePath& fp)
{
if (m_isEnabled) {
if (filepathExists(fp))
this->fileSystemWatcher()->addPath(filepathTo<QString>(fp));
}
}

void DocumentFilesWatcher::onDocumentAdded(const DocumentPtr& doc)
{
if (m_isEnabled) {
if (filepathExists(doc->filePath()))
this->fileSystemWatcher()->addPath(filepathTo<QString>(doc->filePath()));
}
}

void DocumentFilesWatcher::onDocumentAboutToClose(const DocumentPtr& doc)
{
if (m_isEnabled)
this->fileSystemWatcher()->removePath(filepathTo<QString>(doc->filePath()));
}


} // namespace Mayo
Loading

0 comments on commit 496ffad

Please sign in to comment.