Attached my patch for this one.

This concludes the efficiency story as far as I would like to address
it.

I kept the limited-set-of-corrections [-max N] operational on the tkscid
API, with the convention that if N = 0, this is taken as "unlimited."

Both the spellchecker and the cleaner use this N = 0 value, thus finding
all corrections in one run.

Next I will address the spellchecker more from a qualitative perspective
E.g., ever seen a 1 year old playing a correspondence chess game? Scid
considers this most likely :-)

Happy hunting,
Joost.

On Mon, 2009-03-02 at 16:48 +0100, Joost ´t Hart wrote:
> Hi Pascal,
> 
> I see I need just a little bit more patience :-)
> 
> The switch - if defined, of course (!) - does exactly what it says: It
> makes scid bail out after it has found maxCorrections. This saves time.
> 
> This means that it handles issue (2) from my previous posting.
> 
> So, indeed my proposal is in line with your statement below, _PLUS_ /
> _BUT_
> 
> I suggest NOT to use the maxCorrections option from the tcl layer at
> all.
> It is good to leave the C-code for this feature in there (we have it
> anyway), but I suggest not to use it, as it makes no sense (issue (1)).
> 
> It seems this is the final thing we need to agree on. After this I am
> perfectly happy to resend a complete patch to be included in some
> release candidate.
> 
> You can be sure that I (white-box-) tested a lot of different (dbase)
> use cases, but
> 1) developers should not be testers
> 2) I build and test only on Linux. I have a windoze XP PC as well, but
> no clue how to build for it
> 
> So it is certainly better if someone else is willing to conduct some
> testing indeed.
> 
> Cheers,
> Joost.
> 
> On Mon, 2009-03-02 at 13:12 +0100, Pascal Georges wrote:
> > Thanks for your patience and your explanation. What I see :
> > 
> > 1. The define is useless. I was mislead by your default 
> > #undef BAIL_OUT_AFTER_MAXCORRECTIONS
> > 
> > where 
> > 
> > #define BAIL_OUT_AFTER_MAXCORRECTIONS 
> > 
> > gives far better result, and I don't see much drawbacks using this one
> > (or did I miss something ?). 
> > 
> > So I agree with your conclusions (provided that you also think the
> > compiler switch should be the #define above) : could you post an
> > updated patch ?
> > Are there some users willing to test this ? My own tests are very
> > partial as, again, I am not a big user of name checking.
> > 
> > Pascal
> > ------------------------------------------------------------------------------
> > Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
> > -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
> > -Strategies to boost innovation and cut costs with open source participation
> > -Receive a $600 discount off the registration fee with the source code: SFAD
> > http://p.sf.net/sfu/XcvMzF8H
> > _______________________________________________ Scid-users mailing list 
> > Scid-users@lists.sourceforge.net 
> > https://lists.sourceforge.net/lists/listinfo/scid-users
? Makefile
? pgnfix
? pgnscid
? sc_addmove
? sc_eco
? sc_epgn
? sc_import
? sc_remote
? sc_spell
? sc_tree
? scid
? scid.log
? scidlet
? scidpgn
? scidt
? scmerge
? spf2spi
? spliteco
? tcscid
? tkscid
? engines/Phalanx-XXII/phalanx
? engines/togaII1.2.1a/src/.depend
? engines/togaII1.2.1a/src/fruit
Index: src/tkscid.cpp
===================================================================
RCS file: /cvsroot/scid/scid/src/tkscid.cpp,v
retrieving revision 1.29
diff -u -r1.29 tkscid.cpp
--- src/tkscid.cpp	10 Jan 2009 17:51:57 -0000	1.29
+++ src/tkscid.cpp	3 Mar 2009 18:38:20 -0000
@@ -10616,12 +10616,22 @@
     idNumberT * newIDs = new idNumberT [nameCount];
     dateT * startDate = new dateT [nameCount];
     dateT * endDate = new dateT [nameCount];
-#endif
+#endif
+
+    bool interrupted = false;
+
+    // Set the scroll bar to its initial state
+    //
+    bool showProgress = startProgressBar();
+    
+    // Scroll bar threshold (about 200 steps)
+    //
+    uint threshold = (db->numGames / 200) + 1;
 
     for (idNumberT id=0; id < nameCount; id++) {
         newIDs[id] = id;
-        startDate[0] = ZERO_DATE;
-        endDate[0] = ZERO_DATE;
+        startDate[id] = ZERO_DATE;
+        endDate[id] = ZERO_DATE;
     }
 
     while (*str != 0) {
@@ -10664,8 +10674,12 @@
     if (correctionCount == 0) {
 #ifdef WINCE
         my_Tcl_Free((char*) newIDs);
+        my_Tcl_Free((char*) startDate);
+        my_Tcl_Free((char*) endDate);
 #else
         delete[] newIDs;
+        delete[] startDate;
+        delete[] endDate;
 #endif
 
         return setResult (ti, "No valid corrections were found.");
@@ -10675,8 +10689,12 @@
     if ((!db->memoryOnly)  &&  db->nb->WriteNameFile() != OK) {
 #ifdef WINCE
         my_Tcl_Free((char*) newIDs);
+        my_Tcl_Free((char*) startDate);
+        my_Tcl_Free((char*) endDate);
 #else
         delete[] newIDs;
+        delete[] startDate;
+        delete[] endDate;
 #endif
         return errorResult (ti, "Error writing name file.");
     }
@@ -10757,19 +10775,48 @@
         if (corrected) {
             if (db->idx->WriteEntries (&newIE, i, 1) != OK) {
 #ifdef WINCE
-        my_Tcl_Free((char*) newIDs);
+              my_Tcl_Free((char*) newIDs);
+              my_Tcl_Free((char*) startDate);
+              my_Tcl_Free((char*) endDate);
 #else
-        delete[] newIDs;
-#endif
-                return errorResult (ti, "Error writing index file.");
-            }
-        }
+              delete[] newIDs;
+              delete[] startDate;
+              delete[] endDate;
+#endif
+              return errorResult (ti, "Error writing index file.");
+            }
+        }
+        
+        // Update the scroll bar
+        //
+        if ( showProgress && (i % threshold) == 1 ) {
+          updateProgressBar( ti, i, db->numGames );
+          
+          // Give the user a chance for a safe interrupt
+          //
+          if ( (interrupted = interruptedProgress()) ) {
+              break;
+          }
+        }
+    }
+    
+    if ( ! interrupted )
+    {
+        // Ensure the scroll bar is complete at this point
+        //
+        if ( showProgress )  {
+            updateProgressBar( ti, 1, 1 );
+        }
     }
 
 #ifdef WINCE
-        my_Tcl_Free((char*) newIDs);
+    my_Tcl_Free((char*) newIDs);
+    my_Tcl_Free((char*) startDate);
+    my_Tcl_Free((char*) endDate);
 #else
-        delete[] newIDs;
+    delete[] newIDs;
+    delete[] startDate;
+    delete[] endDate;
 #endif
 
     if (db->idx->WriteHeader() != OK) {
@@ -12198,7 +12245,8 @@
     *target = 0;
     return;
 }
-
+
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // sc_name_spellcheck:
 //   Scan the current database for spelling corrections.
@@ -12217,7 +12265,13 @@
     };
     enum {
         OPT_MAX, OPT_SURNAMES, OPT_AMBIGUOUS
-    };
+    };
+    
+    bool interrupted = false;
+    
+    // Set the progress bar to its intial state
+    //
+    bool showProgress = startProgressBar();
 
     int arg = 2;
     while (arg+1 < argc) {
@@ -12229,7 +12283,10 @@
 
         switch (index) {
         case OPT_MAX:
-            maxCorrections = strGetUnsigned (value);
+            maxCorrections = strGetUnsigned (value);
+            if ( maxCorrections == 0 ) {
+                maxCorrections = (uint)-1;
+            }
             break;
         case OPT_SURNAMES:
             doSurnames = strGetBoolean (value);
@@ -12266,28 +12323,46 @@
     char tempName [1024];
     const char * prevCorrection = "";
     idNumberT id = 0;
-    uint correctionCount = 0;
+    uint correctionCount = 0;
+    
+    // Counters to monitor the crawl through the name base
+    //
+    uint maxName  = nb->GetNumNames( nt );
+    uint thisName = 0;
+    
+    // Thresholds for progress-bar updating
+    // We try to make about 200 steps, which should allow
+    // an update at least every second, even for a big name base.
+    //
+    uint nameThres = (maxName / 200)        + 1;
+    uint corrThres = (maxCorrections / 200) + 1;
 
     // Check every name of the specified type:
 
     nb->IterateStart (nt);
 
     while (nb->Iterate (nt, &id) == OK) {
-        uint frequency = nb->GetFrequency (nt, id);
-        // Do not bother trying to correct unused names:
-        if (frequency == 0) { continue; }
-
+        uint frequency = nb->GetFrequency (nt, id);
+        
+        // We have got the next name from the base
+        //
+        thisName++;
+        
         const char * name = nb->GetName (nt, id);
         const char * origName = name;
 
-        if (nt == NAME_PLAYER  &&  !doSurnames  && strIsSurnameOnly (name)) {
-            continue;
-        }
-
-        // First, check for a general prefix or suffix correction:
         int offset = 0;
         const char * replace;
 
+        // Do not bother trying to correct unused names:
+        if (frequency == 0) { goto bar; }
+
+        if (nt == NAME_PLAYER  &&  !doSurnames  && strIsSurnameOnly (name)) {
+            goto bar;
+        }
+
+        // First, check for a general prefix or suffix correction:
+        //
         replace = spellChecker[nt]->CorrectPrefix (name, &offset);
         if (replace != NULL) {
             if (correctionCount < maxCorrections) {
@@ -12300,7 +12375,7 @@
                 prevCorrection = origName;
             }
             correctionCount++;
-            continue;
+            goto bar;
         }
 
         replace = spellChecker[nt]->CorrectSuffix (name, &offset);
@@ -12315,24 +12390,26 @@
                 prevCorrection = origName;
             }
             correctionCount++;
-            continue;
+            goto bar;
         }
-
-        int replacedLength = 0;
-        replace = spellChecker[nt]->CorrectInfix (name, &offset, &replacedLength);
-        if (replace != NULL) {
-            if (correctionCount < maxCorrections) {
-                strCopy (tempName, name);
-                strCopy (tempName + offset, replace);
-                strAppend (tempName, &(name[offset + replacedLength]));
-                sprintf (tempStr, "%s\"%s\"\t>> \"%s\" (%u)\n",
-                         *origName == *prevCorrection ? "" : "\n",
-                         origName, tempName, frequency);
-                dstr->Append (tempStr);
-                prevCorrection = origName;
-            }
-            correctionCount++;
-            continue;
+
+        {
+            int replacedLength = 0;
+            replace = spellChecker[nt]->CorrectInfix (name, &offset, &replacedLength);
+            if (replace != NULL) {
+                if (correctionCount < maxCorrections) {
+                    strCopy (tempName, name);
+                    strCopy (tempName + offset, replace);
+                    strAppend (tempName, &(name[offset + replacedLength]));
+                    sprintf (tempStr, "%s\"%s\"\t>> \"%s\" (%u)\n",
+                                      *origName == *prevCorrection ? "" : "\n",
+                                      origName, tempName, frequency);
+                    dstr->Append (tempStr);
+                    prevCorrection = origName;
+                }
+                correctionCount++;
+                goto bar;
+            }
         }
 
         // If spellchecking names, remove any country code like " (USA)"
@@ -12347,85 +12424,132 @@
                 name = tempName;
             }
         }
+
+        {
+            const uint maxAmbiguous = 10;
+            uint count = 0;
+            const char * corrections [maxAmbiguous];
+            count = spellChecker[nt]->Corrections (name, corrections, maxAmbiguous);
 
-        const uint maxAmbiguous = 10;
-        uint count = 0;
-        const char * corrections [maxAmbiguous];
-        count = spellChecker[nt]->Corrections (name, corrections, maxAmbiguous);
-
-        if (nt == NAME_PLAYER  &&  count < maxAmbiguous) {
-            // If correcting player names, also try the name with the text
-            // after the last space moved to the start, e.g. "R. J. Fischer"
-            // converted to "Fischer R. J.":
-            strPromoteSurname (tempStr, name);
-            count += spellChecker[nt]->Corrections (tempStr,
-                          &(corrections[count]), maxAmbiguous - count);
-            // The above step can cause duplicated corrections, so
-            // remove them:
-            for (uint i=1; i < count; i++) {
-                if (strEqual (corrections[i], corrections[i-1])) {
-                    for (uint j=i+1; j < count; j++) {
-                        corrections[j-1] = corrections[j];
+            if (nt == NAME_PLAYER  &&  count < maxAmbiguous) {
+                // If correcting player names, also try the name with the text
+                // after the last space moved to the start, e.g. "R. J. Fischer"
+                // converted to "Fischer R. J.":
+                strPromoteSurname (tempStr, name);
+                count += spellChecker[nt]->Corrections( tempStr, &(corrections[count]), maxAmbiguous - count);
+                // The above step can cause duplicated corrections, so
+                // remove them:
+                for (uint i=1; i < count; i++) {
+                    if (strEqual (corrections[i], corrections[i-1])) {
+                        for (uint j=i+1; j < count; j++) {
+                            corrections[j-1] = corrections[j];
+                        }
+                        count--;
                     }
-                    count--;
                 }
             }
-        }
-
-        if (count > 1  &&  !ambiguous) { count = 0; }
-
-        for (uint i=0; i < count; i++) {
-            if (strEqual (origName, corrections[i])) { continue; }
-            correctionCount++;
-            if (correctionCount >= maxCorrections) { continue; }
-
-            // Add correction to output, with a blank line first if the
-            // correction starts with a different character to the
-            // previous correction:
-            sprintf (tempStr, "%s%s\"%s\"\t>> \"%s\" (%u)",
-                     *origName == *prevCorrection ? "" : "\n",
-                     count > 1 ? "Ambiguous: " : "",
-                     origName, corrections[i], frequency);
-            dstr->Append (tempStr);
-            if (nt == NAME_PLAYER) {
-                // Look for a player birthdate:
-                    const char * text =
-                        spellChecker[nt]->GetCommentExact (corrections[i]);
-                    dateT birthdate = SpellChecker::GetBirthdate(text);
-                    dateT deathdate = SpellChecker::GetDeathdate(text);
-                    if (birthdate != ZERO_DATE  ||  deathdate != ZERO_DATE) {
-                        dstr->Append ("  ");
-                        if (birthdate != ZERO_DATE) {
-                            date_DecodeToString (birthdate, tempStr);
-                            dstr->Append(tempStr);
-                        }
-                        dstr->Append ("--");
-                        if (deathdate != ZERO_DATE) {
-                            date_DecodeToString (deathdate, tempStr);
-                            dstr->Append(tempStr);
+
+            // Handle ambiguous corrections, if wanted
+            //
+            if ( ambiguous || count == 1) {
+                for (uint i=0; i < count; i++) {
+
+                    // No need to include onself. Skip.
+                    //
+                    if (strEqual (origName, corrections[i])) { 
+                        continue; // to next ambiguous candidate
+                    }
+
+                    // We have a new one
+                    //
+                    correctionCount++;
+                    
+                    // Add correction to output, with a blank line first if the
+                    // correction starts with a different character to the
+                    // previous correction:
+                    sprintf (tempStr, "%s%s\"%s\"\t>> \"%s\" (%u)",
+                                      *origName == *prevCorrection ? "" : "\n",
+                                      count > 1 ? "Ambiguous: " : "",
+                                      origName, corrections[i], frequency);
+                    dstr->Append (tempStr);
+                    if (nt == NAME_PLAYER) {
+                        // Look for a player birthdate:
+                        const char * text =
+                            spellChecker[nt]->GetCommentExact (corrections[i]);
+                        dateT birthdate = SpellChecker::GetBirthdate(text);
+                        dateT deathdate = SpellChecker::GetDeathdate(text);
+                        if (birthdate != ZERO_DATE  ||  deathdate != ZERO_DATE) {
+                            dstr->Append ("  ");
+                            if (birthdate != ZERO_DATE) {
+                                date_DecodeToString (birthdate, tempStr);
+                                dstr->Append(tempStr);
+                            }
+                            dstr->Append ("--");
+                            if (deathdate != ZERO_DATE) {
+                                date_DecodeToString (deathdate, tempStr);
+                                dstr->Append(tempStr);
+                            }
                         }
                     }
-                }
-                dstr->Append ("\n");
-                prevCorrection = origName;
-
-        }
+                    dstr->Append ("\n");
+                    prevCorrection = origName;
+                }
+            }
+        }
+        
+        // Update the progress bar
+        //
+        
+        bar:
+        
+        if ( showProgress ) {
+            // Update filter to avoid hyperactivity
+            //
+            bool filter = (thisName        % nameThres == 1)
+                       || (correctionCount % corrThres == 1);
+        
+            // Try to be clever here: If we go for maxCorrections only, we do not know if and when
+            // they will be found. So we base our progress indicator on either the name base crawl
+            // or the actual correction counter, whichever is closer to its finish.
+            //
+            if ( filter ) {
+                if ( (double)correctionCount / (double)maxCorrections > (double)thisName / (double)maxName ) {
+                    updateProgressBar( ti, correctionCount, maxCorrections );
+                }
+                else {
+                    updateProgressBar( ti, thisName, maxName );
+                }
+
+                // Allow the user to break in at this point
+                //
+                if ( (interrupted = interruptedProgress()) )  {
+                    break;
+                }
+            }
+        }
+
+        // Bail out once we have found maxCorrections
+        //
+        if ( correctionCount >= maxCorrections ) {
+            break;
+        }
+    }
+
+    // Ensure a truely full bar at this point, but only do so if
+    // the user chose to run the thing till the very end.
+    //    
+    if ( ! interrupted )  {
+        if ( showProgress ) {
+            updateProgressBar (ti, 1, 1);
+        }
     }
 
     // Now generate the return message:
 
-    sprintf (tempStr, "Scid found %u %s name correction%s",
+    sprintf (tempStr, "Scid found %u %s name correction%s.\n",
              correctionCount, NAME_TYPE_STRING[nt],
              strPlural (correctionCount));
     Tcl_AppendResult (ti, tempStr, NULL);
-    if (correctionCount > maxCorrections) {
-        sprintf (tempStr, ", the first %u are listed below.", maxCorrections);
-    } else if (correctionCount > 0) {
-        strCopy (tempStr, ", all are listed below.");
-    } else {
-        strCopy (tempStr, ".");
-    }
-    Tcl_AppendResult (ti, tempStr, "\n", NULL);
 
     Tcl_AppendResult (ti,
         "Edit the list to remove any corrections you do not want.\n",
Index: tcl/file/maint.tcl
===================================================================
RCS file: /cvsroot/scid/scid/tcl/file/maint.tcl,v
retrieving revision 1.11
diff -u -r1.11 maint.tcl
--- tcl/file/maint.tcl	11 Jan 2009 16:03:29 -0000	1.11
+++ tcl/file/maint.tcl	3 Mar 2009 18:38:20 -0000
@@ -1439,8 +1439,16 @@
   catch {grab $w}
 }
 
+# Maximum nr of corrections to be scanned
+# Set to zero to find them all
+# Set to some positive number to limit
+#
+set cleaner_maxSpellCorrections 0
+
+
 proc doCleaner {} {
   global cleaner twinSettings
+  global cleaner_maxSpellCorrections
   
   set answer [tk_dialog .mtoolDialog "Scid" \
       [string trim $::tr(CleanerConfirm)] "" \
@@ -1483,7 +1491,7 @@
       mtoolAdd $t "$count: $::tr(Spellchecking): $::tr($names)..."
       incr count
       set result "0 $nameType names were corrected."
-      if {! [catch {sc_name spellcheck -max 100000 $nameType} corrections]} {
+      if {! [catch {sc_name spellcheck -max $cleaner_maxSpellCorrections $nameType} corrections]} {
         update
         catch {sc_name correct $nameType $corrections} result
       }
Index: tcl/file/spellchk.tcl
===================================================================
RCS file: /cvsroot/scid/scid/tcl/file/spellchk.tcl,v
retrieving revision 1.3
diff -u -r1.3 spellchk.tcl
--- tcl/file/spellchk.tcl	23 Dec 2008 20:10:46 -0000	1.3
+++ tcl/file/spellchk.tcl	3 Mar 2009 18:38:20 -0000
@@ -3,10 +3,23 @@
 ### Copyright (C) 2000-2003 Shane Hudson.
 
 set spellcheckType Player
-set spell_maxCorrections 2000
+
+# Maximum nr of corrections to be scanned
+# Set to zero to find them all
+# Set to some positive number to limit
+#
+set spell_maxCorrections 0
+
 set spellcheckSurnames 0
 set spellcheckAmbiguous 1
 
+# Remember what we are doing, being
+# - "idle"       - nothing special
+# - "scanning"   - finding corrections
+# - "correcting" - making corrections
+#
+set spellstate idle
+
 # readSpellCheckFile:
 #    Presents a File Open dialog box for a Scid spellcheck file,
 #    then tries to read the file. If the parameter "message" is true
@@ -34,118 +47,245 @@
   return 1
 }
 
-proc updateSpellCheckWin {type} {
-  global spellcheckType spell_maxCorrections spellcheckSurnames
-  global spellcheckAmbiguous
-  busyCursor .
-  .spellcheckWin.text.text delete 1.0 end
-  #.spellcheckWin.text.text insert end "Finding player corrections..."
-  update idletasks
-  catch {sc_name spellcheck -max $spell_maxCorrections \
-           -surnames $spellcheckSurnames \
-           -ambiguous $spellcheckAmbiguous $type} result
-  .spellcheckWin.text.text delete 1.0 end
-  .spellcheckWin.text.text insert end $result
-  unbusyCursor .
+# Set the environment when the correction scan starts
+#
+proc startScanning {} {
+    global spellstate
+    global spellcheckType
+    
+    # Remember that we are scanning
+    #
+    set spellstate scanning
+    
+    # Disable all buttons except the cancel button that we
+    # transfer into a stop button
+    #
+    .spellcheckWin.buttons.ambig  configure -state disabled
+    .spellcheckWin.buttons.ok     configure -state disabled
+    .spellcheckWin.buttons.cancel configure -text "Stop"
+    bind .spellcheckWin <Alt-s> ".spellcheckWin.buttons.cancel invoke; break"
+    if {$spellcheckType == "Player"} {
+        .spellcheckWin.buttons.surnames configure -state disabled
+    }
 }
 
-proc openSpellCheckWin {type {parent .}} {
-  global spellcheckType spell_maxCorrections spellcheckSurnames
-  global spellcheckAmbiguous
-  set w .spellcheckWin
-  if {[winfo exists $w]} {
-    tk_messageBox -type ok -icon info -title "Scid: Spellcheck error" \
-      -parent $parent \
-      -message "The spellcheck window is already open; close it first."
-    return
-  }
-  if {[lindex [sc_name read] 0] == 0} {
-    # No spellcheck file loaded, so try to open one:
-    if {![readSpellCheckFile]} {
-      return
+# Set the environment when the correction scan stops
+#
+proc stopScanning {} {
+    global spellstate
+    global spellcheckType
+    
+    # Remember that we are not scanning
+    #
+    set spellstate idle
+    
+    # Enable all buttons and set the cancel button back
+    #
+    .spellcheckWin.buttons.ambig  configure -state enabled
+    .spellcheckWin.buttons.ok     configure -state enabled
+    .spellcheckWin.buttons.cancel configure -text "Cancel"
+    bind .spellcheckWin <Alt-c> ".spellcheckWin.buttons.cancel invoke; break"
+    if {$spellcheckType == "Player"} {
+        .spellcheckWin.buttons.surnames configure -state enabled
     }
-  }
-  busyCursor .
-  if {[catch {sc_name spellcheck -max $spell_maxCorrections \
-                -surnames $spellcheckSurnames \
-                -ambiguous $spellcheckAmbiguous $type} result]} {
-    unbusyCursor .
-    tk_messageBox -type ok -icon info -title "Scid: Spellcheck results" \
-      -parent $parent -message $result
-    return
-  }
-  unbusyCursor .
-  set spellcheckType $type
+}
 
-  toplevel $w
-  wm title $w "Scid: Spellcheck Results"
-  wm minsize $w 50 10
-
-  bind $w <F1> { helpWindow Maintenance }
-  bind $w <Configure> "recordWinSize $w"
-
-  set f [ttk::frame $w.buttons]
-  pack $f -side bottom -ipady 1 -fill x
-
-ttk::checkbutton $f.ambig -variable spellcheckAmbiguous \
-    -text "Ambiguous" -command "updateSpellCheckWin $type"
-  pack $f.ambig -side left -padx 2 -ipady 2 -ipadx 3
-  if {$type == "Player"} {
-    ttk::checkbutton $f.surnames -variable spellcheckSurnames \
-      -text "Surnames" -command "updateSpellCheckWin Player"
-    pack $f.surnames -side left -padx 2 -ipady 2 -ipadx 3
-  }
 
-  ttk::button $f.ok -text "Make Corrections" -underline 0 -command {
+# Set the environment when correction starts
+#
+proc startCorrecting {} {
+    global spellstate
+    global spellcheckType
+    
+    # Remember that we are correcting
+    #
+    set spellstate correcting
+    
+    # Disable all buttons except the cancel button that we
+    # transfer into a stop button
+    #
+    .spellcheckWin.buttons.ambig  configure -state disabled
+    .spellcheckWin.buttons.ok     configure -state disabled
+    .spellcheckWin.buttons.cancel configure -text "Stop"
+    bind .spellcheckWin <Alt-s> ".spellcheckWin.buttons.cancel invoke; break"
+    if {$spellcheckType == "Player"} {
+        .spellcheckWin.buttons.surnames configure -state disabled
+    }
+}
+
+
+# Start the correction scan and dump the results into the
+# text window. After this the user may edit the correction
+# 'script' and actually make the corrections.
+#
+# While the scan is running, all buttons except a stop button
+# are disabled.
+#
+proc updateSpellCheckWin {type} {
+    global spellcheckType spell_maxCorrections spellcheckSurnames
+    global spellcheckAmbiguous
+
     busyCursor .
-    set spelltext ""
-    catch {set spelltext [.spellcheckWin.text.text get 1.0 end-1c]}
     .spellcheckWin.text.text delete 1.0 end
-    .spellcheckWin.text.text insert end \
-      "Scid is making the spelling corrections.\nPlease wait..."
+    .spellcheckWin.text.text insert end "Scid is finding spelling corrections.\nPlease wait..."
+
+    # Enable the progress bar
+    #
+    sc_progressBar .spellcheckWin.progress bar 451 21 time
+
+    startScanning
+
     update idletasks
-    set spell_result ""
-    set result [catch {sc_name correct $spellcheckType $spelltext} spell_result]
-    set messageIcon info
-    if {$result} { set messageIcon error }
-    tk_messageBox -type ok -parent .spellcheckWin -icon $messageIcon \
-      -title "Scid: Spellcheck results" -message $spell_result
+    if {[catch {sc_name spellcheck -max $spell_maxCorrections \
+                                   -surnames $spellcheckSurnames \
+                                   -ambiguous $spellcheckAmbiguous $type} result]} {
+        stopScanning
+        unbusyCursor .
+        tk_messageBox -type ok -icon info -title "Scid: Spellcheck results" \
+                      -parent $parent -message $result
+        return
+    }
+    stopScanning
+
+    .spellcheckWin.text.text delete 1.0 end
+    .spellcheckWin.text.text insert end $result
     unbusyCursor .
-    focus .
-    destroy .spellcheckWin
-    sc_game tags reload
-    updateBoard -pgn
-    ::windows::gamelist::Refresh
-  }
-  bind $w <Alt-m> "$f.ok invoke; break"
+}
 
-  ttk::button $f.cancel -text "Cancel" -underline 0 -command {
-    focus .
-    destroy .spellcheckWin
-  }
-  bind $w <Alt-c> "$f.cancel invoke; break"
 
-  pack $f.cancel $f.ok -side right -padx 5
+# Create the spell checking window with its event handlers
+# and start the initial correction scan
+#
+proc openSpellCheckWin {type {parent .}} {
+    global spellcheckType spellcheckSurnames
+    global spellcheckAmbiguous
+    global spellstate
+
+    set w .spellcheckWin
+
+    if {[winfo exists $w]} {
+        tk_messageBox -type ok -icon info -title "Scid: Spellcheck error" \
+                      -parent $parent \
+                      -message "The spellcheck window is already open; close it first."
+        return
+    }
+
+    if {[lindex [sc_name read] 0] == 0} {
+        # No spellcheck file loaded, so try to open one:
+        if {![readSpellCheckFile]} {
+            return
+        }
+    }
+    set spellcheckType $type
 
-  set f [ttk::frame $w.text]
-  pack $w.text -expand yes -fill both
-  ttk::scrollbar $f.ybar -command "$f.text yview"
-  ttk::scrollbar $f.xbar -orient horizontal -command "$f.text xview"
-  text $f.text -yscrollcommand "$f.ybar set" -xscrollcommand "$f.xbar set" \
-    -setgrid 1 -width $::winWidth($w) -height $::winHeight($w) \
-    -background white -wrap none
-  $f.text configure -tabs \
-    [font measure font_Regular  "xxxxxxxxxxxxxxxxxxxxxxxxx"]
-
-  grid $f.text -row 0 -column 0 -sticky news
-  grid $f.ybar -row 0 -column 1 -sticky news
-  grid $f.xbar -row 1 -column 0 -sticky news
+    toplevel $w
+    wm title $w "Scid: Spellcheck Results"
+    wm minsize $w 50 10
+
+    bind $w <F1> { helpWindow Maintenance }
+    bind $w <Configure> "recordWinSize $w"
+
+    # Create the button pad at the bottom of the window
+    #
+    set f [ttk::frame $w.buttons]
+    pack $f -side bottom -ipady 1 -fill x
+  
+    # Draw a canvas ("progress") to hold the progress bar
+    # and put it above the buttons at the bottom of the window
+    #
+    canvas $w.progress -width 450 -height 20 -bg white -relief solid -border 1
+    $w.progress create rectangle 0 0 0 0 -fill blue -outline blue -tags bar
+    $w.progress create text 445 10 -anchor e -font font_Regular -tags time \
+                                   -fill black -text "0:00 / 0:00"
+    pack $w.progress -side bottom
+
+    # The ambiguous check mark
+    # Hitting it starts a new correction scan
+    ttk::checkbutton $f.ambig -variable spellcheckAmbiguous \
+                              -text "Ambiguous" -command "updateSpellCheckWin $type"
+    pack $f.ambig -side left -padx 2 -ipady 2 -ipadx 3
+
+    # When correcting player names, we add a surnames option
+    #
+    if {$type == "Player"} {
+        # The surnames check mark
+        # Hitting it starts a new correction scan
+        #
+        ttk::checkbutton $f.surnames -variable spellcheckSurnames \
+                                     -text "Surnames" -command "updateSpellCheckWin Player"
+        pack $f.surnames -side left -padx 2 -ipady 2 -ipadx 3
+    }
 
-  grid rowconfig $w.text 0 -weight 1 -minsize 0
-  grid columnconfig $w.text 0 -weight 1 -minsize 0
+    # The button to start the correction making...
+    #
+    ttk::button $f.ok -text "Make Corrections" -underline 0 -command {
+        busyCursor .
+        set spelltext ""
+        catch {set spelltext [.spellcheckWin.text.text get 1.0 end-1c]}
+        .spellcheckWin.text.text delete 1.0 end
+        .spellcheckWin.text.text insert end \
+            "Scid is making the spelling corrections.\nPlease wait..."
+
+        # Enable the progress bar
+        #
+        sc_progressBar .spellcheckWin.progress bar 451 21 time
+
+        update idletasks
+        set spell_result ""
+        startCorrecting
+        set result [catch {sc_name correct $spellcheckType $spelltext} spell_result]
+        set messageIcon info
+        if {$result} { set messageIcon error }
+        tk_messageBox -type ok -parent .spellcheckWin -icon $messageIcon \
+            -title "Scid: Spellcheck results" -message $spell_result
+        unbusyCursor .
+        focus .
+        destroy .spellcheckWin
+        sc_game tags reload
+        updateBoard -pgn
+        ::windows::gamelist::Refresh
+    }
+    bind $w <Alt-m> "$f.ok invoke; break"
+
+    # The cancel button operates in an either/or context
+    # While some process is running, it simply stops it
+    # In other cases, spell checking is left
+    #
+    ttk::button $f.cancel -text "Cancel" -underline 0 -command {
+        if {$spellstate == "scanning" || $spellstate == "correcting"} {
+            sc_progressBar
+        } else {
+            focus .
+            destroy .spellcheckWin
+        }
+    }
+    bind $w <Alt-c> "$f.cancel invoke; break"
+    pack $f.cancel $f.ok -side right -padx 5
 
-  $f.text insert end $result
-  focus $f.text
+    # Prepare the text pad
+    #
+    set f [ttk::frame $w.text]
+    pack $w.text -expand yes -fill both
+    ttk::scrollbar $f.ybar -command "$f.text yview"
+    ttk::scrollbar $f.xbar -orient horizontal -command "$f.text xview"
+    text $f.text -yscrollcommand "$f.ybar set" -xscrollcommand "$f.xbar set" \
+                 -setgrid 1 -width $::winWidth($w) -height $::winHeight($w) \
+                 -background white -wrap none
+    $f.text configure -tabs \
+        [font measure font_Regular  "xxxxxxxxxxxxxxxxxxxxxxxxx"]
+
+    grid $f.text -row 0 -column 0 -sticky news
+    grid $f.ybar -row 0 -column 1 -sticky news
+    grid $f.xbar -row 1 -column 0 -sticky news
+
+    grid rowconfig $w.text 0 -weight 1 -minsize 0
+    grid columnconfig $w.text 0 -weight 1 -minsize 0
+  
+    focus $f.text
+
+    # Start the initial search for spelling corrections
+    #
+    updateSpellCheckWin $type
 }
 
 
------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
_______________________________________________
Scid-users mailing list
Scid-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/scid-users

Reply via email to