diff --git a/common/project.cpp b/common/project.cpp index df7513544f..244f96b67f 100644 --- a/common/project.cpp +++ b/common/project.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include + PROJECT::PROJECT() : m_readOnly( false ), m_textVarsTicker( 0 ), @@ -460,3 +462,15 @@ DESIGN_BLOCK_LIB_TABLE* PROJECT::DesignBlockLibs() return tbl; } + + +void PROJECT::SetProjectLock( LOCKFILE* aLockFile ) +{ + m_project_lock.reset( aLockFile ); +} + + +LOCKFILE* PROJECT::GetProjectLock() const +{ + return m_project_lock.get(); +} \ No newline at end of file diff --git a/common/settings/settings_manager.cpp b/common/settings/settings_manager.cpp index 0198742e64..04d840a369 100644 --- a/common/settings/settings_manager.cpp +++ b/common/settings/settings_manager.cpp @@ -939,13 +939,11 @@ bool SETTINGS_MANAGER::LoadProject( const wxString& aFullPath, bool aSetActive ) if( m_projects.count( fullPath ) ) return true; - bool readOnly = false; LOCKFILE lockFile( fullPath ); if( !lockFile.Valid() ) { wxLogTrace( traceSettings, wxT( "Project %s is locked; opening read-only" ), fullPath ); - readOnly = true; } // No MDI yet @@ -986,10 +984,10 @@ bool SETTINGS_MANAGER::LoadProject( const wxString& aFullPath, bool aSetActive ) if( success ) { - project->SetReadOnly( readOnly || project->GetProjectFile().IsReadOnly() ); + project->SetReadOnly( !lockFile.Valid() || project->GetProjectFile().IsReadOnly() ); if( lockFile && aSetActive ) - m_project_lock.reset( new LOCKFILE( std::move( lockFile ) ) ); + project->SetProjectLock( new LOCKFILE( std::move( lockFile ) ) ); } m_projects_list.push_back( std::move( project ) ); @@ -1048,9 +1046,6 @@ bool SETTINGS_MANAGER::UnloadProject( PROJECT* aProject, bool aSave ) // Remove the reference in the environment to the previous project wxSetEnv( PROJECT_VAR_NAME, wxS( "" ) ); - // Release lock on the file, in case we had one - m_project_lock = nullptr; - if( m_kiway ) m_kiway->ProjectChanged(); } diff --git a/include/lockfile.h b/include/lockfile.h index 54bcbb6a59..190e59f5d0 100644 --- a/include/lockfile.h +++ b/include/lockfile.h @@ -127,6 +127,20 @@ public: } } + LOCKFILE( LOCKFILE&& other ) noexcept : + m_originalFile( std::move( other.m_originalFile ) ), + m_lockFilename( std::move( other.m_lockFilename ) ), + m_username( std::move( other.m_username ) ), + m_hostname( std::move( other.m_hostname ) ), + m_fileCreated( other.m_fileCreated ), + m_status( other.m_status ), + m_removeOnRelease( other.m_removeOnRelease ), + m_errorMsg( std::move( other.m_errorMsg ) ) + { + // Disable unlock in the moved-from object + other.m_fileCreated = false; + } + ~LOCKFILE() { UnlockFile(); diff --git a/include/project.h b/include/project.h index a31b12c966..2e153cd92e 100644 --- a/include/project.h +++ b/include/project.h @@ -52,6 +52,7 @@ class SYMBOL_LIB_TABLE; class FILENAME_RESOLVER; class PROJECT_FILE; class PROJECT_LOCAL_SETTINGS; +class LOCKFILE; /** @@ -217,9 +218,9 @@ public: { DOC_PATH, SCH_LIB_PATH, - SCH_LIB_SELECT, // eeschema/selpart.cpp + SCH_LIB_SELECT, // eeschema/selpart.cpp SCH_LIBEDIT_CUR_LIB, - SCH_LIBEDIT_CUR_SYMBOL, // eeschema/libeditframe.cpp + SCH_LIBEDIT_CUR_SYMBOL, // eeschema/libeditframe.cpp VIEWER_3D_PATH, VIEWER_3D_FILTER_INDEX, @@ -270,11 +271,11 @@ public: /** * Clear the _ELEMs and RSTRINGs. */ - void Clear() // inline not virtual + void Clear() // inline not virtual { elemsClear(); - for( unsigned i = 0; i( PROJECT::ELEM::COUNT )> m_elems; + + /// Lock + std::unique_ptr m_project_lock; }; diff --git a/include/settings/settings_manager.h b/include/settings/settings_manager.h index 9c13d2c907..cf32ac0b76 100644 --- a/include/settings/settings_manager.h +++ b/include/settings/settings_manager.h @@ -531,9 +531,6 @@ private: /// Loaded project files, mapped according to project full name. std::map m_project_files; - /// Lock for loaded project (expand to multiple once we support MDI). - std::unique_ptr m_project_lock; - static wxString backupDateTimeFormat; }; diff --git a/kicad/kicad_manager_frame.cpp b/kicad/kicad_manager_frame.cpp index da55f7f6ac..5550bba563 100644 --- a/kicad/kicad_manager_frame.cpp +++ b/kicad/kicad_manager_frame.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -1035,7 +1037,42 @@ void KICAD_MANAGER_FRAME::CommonSettingsChanged( int aFlags ) void KICAD_MANAGER_FRAME::ProjectChanged() { - wxString file = GetProjectFileName(); + wxString file = GetProjectFileName(); + + // empty file string means no project loaded + if( !Prj().IsNullProject() && + Prj().GetProjectLock() == nullptr ) + { + LOCKFILE lockFile( file ); + + if( !lockFile.Valid() && lockFile.IsLockedByMe() ) + { + // If we cannot acquire the lock but we appear to be the one who + // locked it, check to see if there is another KiCad instance running. + // If there is not, then we can override the lock. This could happen if + // KiCad crashed or was interrupted + if( !Pgm().SingleInstance()->IsAnotherRunning() ) + { + lockFile.OverrideLock(); + } + } + + if( !lockFile.Valid() ) + { + wxString msg; + msg.Printf( _( "Project '%s' is already open by '%s' at '%s'." ), file, lockFile.GetUsername(), + lockFile.GetHostname() ); + + if( AskOverrideLock( this, msg ) ) + { + lockFile.OverrideLock(); + } + } + + Prj().SetReadOnly( !lockFile.Valid() || Prj().GetProjectFile().IsReadOnly() ); + Prj().SetProjectLock( new LOCKFILE( std::move( lockFile ) ) ); + } + wxString title; if( !file.IsEmpty() )