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 );
 };
 
 /*

_______________________________________________
Mailing list: https://launchpad.net/~kicad-developers
Post to     : kicad-developers@lists.launchpad.net
Unsubscribe : https://launchpad.net/~kicad-developers
More help   : https://help.launchpad.net/ListHelp

Reply via email to