← Back to team overview

kicad-developers team mailing list archive

[PATCH] Prevent Eeschema from opening the same file twice

 

Currently KiCad applications allow opening the same file more than once,
and they don't check if the files have changed in disk before saving. As
a consequence, there can be situations where the user loses some data
without notice.

This patch uses wxSingleInstanceChecker to create a lock on the open
file. It is checked every time Eeschema tries to open a file. We can
distinguish two situations:

* Open a file when the application is started. In this case, if the lock
is unsuccessful the application closes, it doesn't even show the alert
about other instances running.

* Open another file from the menu (file -> open or tool bar). In this
case, if the lock is unsuccessful the application remains open with its
contents unchanged.

Finally, this patch is a starting point to implement similar checks in
other KiCad applications.

-- 
Jacobo
=== modified file 'common/edaappl.cpp'
--- common/edaappl.cpp	2012-11-09 06:58:00 +0000
+++ common/edaappl.cpp	2013-01-03 17:22:08 +0000
@@ -273,6 +273,7 @@
 EDA_APP::EDA_APP()
 {
     m_Checker = NULL;
+    m_oneInstancePerFileChecker = NULL;
     m_HtmlCtrl = NULL;
     m_settings = NULL;
     m_LanguageId = wxLANGUAGE_DEFAULT;
@@ -298,6 +299,9 @@
     if( m_Checker )
         delete m_Checker;
 
+    if( m_oneInstancePerFileChecker )
+        delete m_oneInstancePerFileChecker;
+
     delete m_Locale;
 }
 
@@ -1124,3 +1128,23 @@
         }
     }
 }
+
+bool EDA_APP::LockFile( const wxString& fileName )
+{
+    // semaphore to protect the edition of the file by more than one instance
+    if( m_oneInstancePerFileChecker != NULL )
+    {
+        // it means that we had an open file and we are opening a different one
+        delete m_oneInstancePerFileChecker;
+    }
+    wxString lockFileName = fileName + wxT( ".lock" );
+    lockFileName.Replace( wxT( "/" ), wxT( "_" ) );
+    m_oneInstancePerFileChecker = new wxSingleInstanceChecker( lockFileName );
+    if( m_oneInstancePerFileChecker &&
+        m_oneInstancePerFileChecker->IsAnotherRunning() )
+    {
+        return false;
+    }
+
+    return true;
+}

=== modified file 'eeschema/eeschema.cpp'
--- eeschema/eeschema.cpp	2012-10-31 20:27:31 +0000
+++ eeschema/eeschema.cpp	2013-01-03 17:22:08 +0000
@@ -89,18 +89,33 @@
 {
     wxFileName      filename;
     SCH_EDIT_FRAME* frame = NULL;
+    bool fileReady = false;
 
     InitEDA_Appl( wxT( "Eeschema" ), APP_EESCHEMA_T );
 
-    if( m_Checker && m_Checker->IsAnotherRunning() )
-    {
-        if( !IsOK( NULL, _( "Eeschema is already running, Continue?" ) ) )
-            return false;
-    }
-
     if( argc > 1 )
         filename = argv[1];
 
+    if( filename.IsOk() )
+    {
+        if( filename.GetExt() != SchematicFileExtension )
+            filename.SetExt( SchematicFileExtension );
+
+        if( !wxGetApp().LockFile( filename.GetFullPath() ) )
+        {
+            DisplayError( NULL, _( "This file is already open." ) );
+            return false;
+        }
+
+        fileReady = true;
+    }
+
+    if( m_Checker && m_Checker->IsAnotherRunning() )
+      {
+          if( !IsOK( NULL, _( "Eeschema is already running, Continue?" ) ) )
+              return false;
+      }
+
     // Give a default colour for all layers
     // (actual color will beinitialized by config)
     for( int ii = 0; ii < MAX_LAYERS; ii++ )
@@ -130,11 +145,8 @@
     frame->Zoom_Automatique( true );
 
     /* Load file specified in the command line. */
-    if( filename.IsOk() )
+    if( fileReady )
     {
-        if( filename.GetExt() != SchematicFileExtension )
-            filename.SetExt( SchematicFileExtension );
-
         wxSetWorkingDirectory( filename.GetPath() );
 
         if( frame->LoadOneEEProject( filename.GetFullPath(), false ) )

=== modified file 'eeschema/files-io.cpp'
--- eeschema/files-io.cpp	2012-09-28 17:47:41 +0000
+++ eeschema/files-io.cpp	2013-01-03 17:22:08 +0000
@@ -32,6 +32,7 @@
 #include <confirm.h>
 #include <gestfich.h>
 #include <wxEeschemaStruct.h>
+#include <appl_wxstruct.h>
 
 #include <general.h>
 #include <protos.h>
@@ -204,6 +205,21 @@
         FullFileName = dlg.GetPath();
     }
 
+    wxFileName fn = FullFileName;
+
+    if( fn.IsRelative() )
+    {
+        fn.MakeAbsolute();
+        FullFileName = fn.GetFullPath();
+    }
+
+    if( !wxGetApp().LockFile( FullFileName ) )
+    {
+        DisplayError( this, _( "This file is already open." ) );
+        return false;
+    }
+
+    // Clear the screen before open a new file
     if( g_RootSheet )
     {
         SAFE_DELETE( g_RootSheet );
@@ -212,14 +228,6 @@
     CreateScreens();
     screen = GetScreen();
 
-    wxFileName fn = FullFileName;
-
-    if( fn.IsRelative() )
-    {
-        fn.MakeAbsolute();
-        FullFileName = fn.GetFullPath();
-    }
-
     wxLogDebug( wxT( "Loading schematic " ) + FullFileName );
     wxSetWorkingDirectory( fn.GetPath() );
 

=== modified file 'include/appl_wxstruct.h'
--- include/appl_wxstruct.h	2012-08-02 07:47:30 +0000
+++ include/appl_wxstruct.h	2013-01-03 17:22:08 +0000
@@ -67,6 +67,9 @@
     /// Used to prevent multiple instances of an application from being run at the same time.
     wxSingleInstanceChecker* m_Checker;
 
+    /// Used to prevent opening the same file multiple times.
+    wxSingleInstanceChecker* m_oneInstancePerFileChecker;
+
     wxString m_Project;
 
     /// The application specific configuration settings.
@@ -410,6 +413,13 @@
      */
     void InsertLibraryPath( const wxString& aPaths, size_t aIndex );
 
+    /**
+     * Function LockFile
+     * Locks the access to a file.
+     * @param fileName = full path to the file.
+     * @return false if the file was already locked, true otherwise.
+     */
+    bool LockFile( const wxString& fileName );
 };
 
 /*


Follow ups