diff --git a/common/lc_mainwindow.cpp b/common/lc_mainwindow.cpp index 39174517..3c921ed9 100644 --- a/common/lc_mainwindow.cpp +++ b/common/lc_mainwindow.cpp @@ -810,6 +810,41 @@ void lcMainWindow::ColorChanged(int ColorIndex) SetColorIndex(ColorIndex); } +void lcMainWindow::ProjectFileChanged(const QString& Path) +{ + static bool Ignore; + + if (Ignore) + return; + + QString Text = tr("The file '%1' has been modified by another application, do you want to reload it?").arg(Path); + + Ignore = true; + + if (QMessageBox::question(this, tr("File Changed"), Text, QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) + { + Ignore = false; + return; + } + + Ignore = false; + + Project* NewProject = new Project; + + if (NewProject->Load(Path)) + { + QByteArray TabLayout = SaveTabLayout(); + gApplication->SetProject(NewProject); + RestoreTabLayout(TabLayout); + UpdateAllViews(); + } + else + { + QMessageBox::information(this, tr("LeoCAD"), tr("Error loading '%1'.").arg(Path)); + delete NewProject; + } +} + void lcMainWindow::Print(QPrinter* Printer) { #ifndef QT_NO_PRINTER @@ -1061,6 +1096,177 @@ void lcMainWindow::SetSelectionMode(lcSelectionMode SelectionMode) UpdateSelectionMode(); } +QByteArray lcMainWindow::SaveTabLayout() +{ + QByteArray TabLayout; + QDataStream DataStream(&TabLayout, QIODevice::WriteOnly); + + // todo: save version number and focus view + + qint32 NumTabs = mModelTabWidget->count(); + DataStream << NumTabs; + DataStream << ((lcModelTabWidget*)mModelTabWidget->currentWidget())->GetModel()->GetProperties().mName; + + for (int TabIdx = 0; TabIdx < NumTabs; TabIdx++) + { + lcModelTabWidget* TabWidget = (lcModelTabWidget*)mModelTabWidget->widget(TabIdx); + + DataStream << TabWidget->GetModel()->GetProperties().mName; + + std::function SaveWidget = [&DataStream, &SaveWidget](QWidget* Widget) + { + if (Widget->metaObject() == &lcQGLWidget::staticMetaObject) + { + DataStream << (qint32)0; + + lcCamera* Camera = ((View*)((lcQGLWidget*)Widget)->widget)->mCamera; + + if (Camera->IsSimple()) + { + DataStream << (qint32)0; + DataStream << Camera->m_fovy; + DataStream << Camera->m_zNear; + DataStream << Camera->m_zFar; + DataStream << Camera->mPosition; + DataStream << Camera->mTargetPosition; + DataStream << Camera->mUpVector; + } + else + { + DataStream << (qint32)1; + DataStream << QByteArray::fromRawData(Camera->m_strName, sizeof(Camera->m_strName)); + } + } + else + { + QSplitter* Splitter = (QSplitter*)Widget; + + DataStream << (qint32)(Splitter->orientation() == Qt::Horizontal ? 1 : 2); + DataStream << Splitter->sizes(); + + SaveWidget(Splitter->widget(0)); + SaveWidget(Splitter->widget(1)); + } + }; + + QLayout* TabLayout = TabWidget->layout(); + SaveWidget(TabLayout->itemAt(0)->widget()); + } + + return TabLayout; +} + +void lcMainWindow::RestoreTabLayout(const QByteArray& TabLayout) +{ + QDataStream DataStream(TabLayout); + + qint32 NumTabs; + DataStream >> NumTabs; + QString CurrentTabName; + DataStream >> CurrentTabName; + + RemoveAllModelTabs(); + + for (int TabIdx = 0; TabIdx < NumTabs; TabIdx++) + { + QString ModelName; + DataStream >> ModelName; + + lcModel* Model = lcGetActiveProject()->GetModel(ModelName); + lcModelTabWidget* TabWidget = nullptr; + + if (Model) + { + SetCurrentModelTab(Model); + TabWidget = (lcModelTabWidget*)mModelTabWidget->widget(mModelTabWidget->count() - 1); + } + + std::function LoadWidget = [&DataStream, &LoadWidget, Model, this](QWidget* ParentWidget) + { + qint32 WidgetType; + DataStream >> WidgetType; + + if (WidgetType == 0) + { + qint32 CameraType; + DataStream >> CameraType; + + View* CurrentView = nullptr; + + if (ParentWidget) + CurrentView = (View*)((lcQGLWidget*)ParentWidget)->widget; + + if (CameraType == 0) + { + float FoV, ZNear, ZFar; + lcVector3 Position, TargetPosition, UpVector; + + DataStream >> FoV; + DataStream >> ZNear; + DataStream >> ZFar; + DataStream >> Position; + DataStream >> TargetPosition; + DataStream >> UpVector; + + if (CurrentView) + { + lcCamera* Camera = CurrentView->mCamera; + Camera->m_fovy = FoV; + Camera->m_zNear = ZNear; + Camera->m_zFar = ZFar; + Camera->mPosition = Position; + Camera->mTargetPosition = TargetPosition; + Camera->mUpVector = UpVector; + Camera->UpdatePosition(1); + } + } + else + { + QByteArray CameraName; + DataStream >> CameraName; + + if (CurrentView) + CurrentView->SetCamera(CameraName); + } + } + else + { + QList Sizes; + DataStream >> Sizes; + + if (ParentWidget) + { + ParentWidget->setFocus(); + + if (WidgetType == 1) + SplitVertical(); + else + SplitHorizontal(); + + QSplitter* Splitter = (QSplitter*)ParentWidget->parentWidget(); + Splitter->setSizes(Sizes); + + LoadWidget(Splitter->widget(0)); + LoadWidget(Splitter->widget(1)); + } + else + { + LoadWidget(nullptr); + LoadWidget(nullptr); + } + } + }; + + QLayout* TabLayout = TabWidget->layout(); + LoadWidget(TabLayout->itemAt(0)->widget()); + } + + if (!mModelTabWidget->count()) + lcGetActiveProject()->SetActiveModel(0); + else + lcGetActiveProject()->SetActiveModel(CurrentTabName); +} + void lcMainWindow::RemoveAllModelTabs() { while (mModelTabWidget->count() > 1) diff --git a/common/lc_mainwindow.h b/common/lc_mainwindow.h index 9ac99209..8741cd43 100644 --- a/common/lc_mainwindow.h +++ b/common/lc_mainwindow.h @@ -229,6 +229,8 @@ public: return mShadingMenu; } + QByteArray SaveTabLayout(); + void RestoreTabLayout(const QByteArray& TabLayout); void RemoveAllModelTabs(); void SetCurrentModelTab(lcModel* Model); void ResetCameras(); @@ -300,6 +302,9 @@ public: lcSearchOptions mSearchOptions; QAction* mActions[LC_NUM_COMMANDS]; +public slots: + void ProjectFileChanged(const QString& Path); + protected slots: void ModelTabClosed(int Index); void ModelTabChanged(int Index); diff --git a/common/lc_math.h b/common/lc_math.h index 38f00671..05dc5fb4 100644 --- a/common/lc_math.h +++ b/common/lc_math.h @@ -393,6 +393,30 @@ inline QDebug operator<<(QDebug Debug, const lcMatrix44& m) #endif +inline QDataStream& operator<<(QDataStream& Stream, const lcVector3& v) +{ + Stream << v.x << v.y << v.z; + return Stream; +} + +inline QDataStream& operator>>(QDataStream& Stream, lcVector3& v) +{ + Stream >> v.x >> v.y >> v.z; + return Stream; +} + +inline QDataStream& operator<<(QDataStream& Stream, const lcVector4& v) +{ + Stream << v.x << v.y << v.z << v.w; + return Stream; +} + +inline QDataStream& operator >> (QDataStream& Stream, lcVector4& v) +{ + Stream >> v.x >> v.y >> v.z >> v.w; + return Stream; +} + inline void lcVector3::Normalize() { float InvLength = 1.0f / Length(); diff --git a/common/project.cpp b/common/project.cpp index ab02ce24..b3fed79f 100644 --- a/common/project.cpp +++ b/common/project.cpp @@ -84,9 +84,7 @@ Project::Project() mActiveModel->SetSaved(); mModels.Add(mActiveModel); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) - QObject::connect(&mFileWatcher, &QFileSystemWatcher::fileChanged, [&](const QString& Path) { Q_UNUSED(Path); FileChanged(); }); -#endif + QObject::connect(&mFileWatcher, SIGNAL(fileChanged(const QString&)), gMainWindow, SLOT(ProjectFileChanged(const QString&))); } Project::~Project() @@ -94,6 +92,15 @@ Project::~Project() mModels.DeleteAll(); } +lcModel* Project::GetModel(const QString& Name) const +{ + for (lcModel* Model : mModels) + if (Model->GetProperties().mName == Name) + return Model; + + return nullptr; +} + bool Project::IsModified() const { if (mModified) @@ -159,7 +166,6 @@ void Project::SetActiveModel(const QString& ModelName) return; } } - } QString Project::GetNewModelName(QWidget* ParentWidget, const QString& DialogTitle, const QString& CurrentName, const QStringList& ExistingModels) const @@ -331,20 +337,6 @@ void Project::SetFileName(const QString& FileName) mFileName = FileName; } -void Project::FileChanged() -{ - QString Text = tr("The file '%1' has been modified by another application, do you want to reload it?").arg(mFileName); - - if (QMessageBox::question(gMainWindow, tr("File Changed"), Text, QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) - return; - - // todo: don't close tabs - Load(mFileName); - gMainWindow->RemoveAllModelTabs(); - SetActiveModel(0); - lcGetPiecesLibrary()->RemoveTemporaryPieces(); -} - bool Project::Load(const QString& FileName) { QFile File(FileName); diff --git a/common/project.h b/common/project.h index 63930428..8d3eb3f8 100644 --- a/common/project.h +++ b/common/project.h @@ -58,6 +58,8 @@ public: return mModels; } + lcModel* GetModel(const QString& Name) const; + lcModel* GetActiveModel() const { return mActiveModel; @@ -115,7 +117,6 @@ protected: QImage CreatePartsListImage(lcModel* Model, lcStep Step); void CreateHTMLPieceList(QTextStream& Stream, lcModel* Model, lcStep Step, bool Images); void SetFileName(const QString& FileName); - void FileChanged(); bool mModified; QString mFileName;