This patch is taken against 072300 nightly sources.  It provides, as
hinted some days ago, a modification of the background spell checking
stuff into a general background checking mechanism.  All code is XP
and tested on Linux.

Besides the familiar background spell-checking, there is a
demonstration background check that I call DebugFlash.  If you set a
user preference item:

        DebugFlash="1"

and have spell-checking turned on, you'll see visual evidence of the
background check mechanism.  Blocks (in the fl_BlockLayout sense) are
briefly underlined with squiggles as each block is considered.  Since
that happens right before spell-checking, the squiggles look normal
after a quarter second or so.  Oh, that doesn't happen for the initial
pass through the document (has to do with when preferences are read to
sensing DebugFlash), so "cut" out a few paragraphs and then "paste" it
back in the same place ... then you'll see the background checks on
the pasted text.  (The DebugFlash preference item isn't in the
_builtin_ list.  If it's not set to true, you just get the same old
spell-checking you're used to.)

I'll have more to say about how to add a background checking function
at some near-future date.
-- 
[EMAIL PROTECTED] (WJCarpenter)    PGP 0x91865119
38 95 1B 69 C9 C6 3D 25    73 46 32 04 69 D6 ED F3

diff -ru abi-072300-ORIG/src/text/fmt/xp/fl_BlockLayout.cpp 
abi-072300/src/text/fmt/xp/fl_BlockLayout.cpp
--- abi-072300-ORIG/src/text/fmt/xp/fl_BlockLayout.cpp  Thu Jul 20 20:07:37 2000
+++ abi-072300/src/text/fmt/xp/fl_BlockLayout.cpp       Sun Jul 23 22:49:41 2000
@@ -95,7 +95,8 @@
        m_bStartList = UT_FALSE;
        m_bStopList = UT_FALSE;
        m_bListLabelCreated = UT_FALSE;
-        m_bCursorErased = UT_FALSE;
+       m_bCursorErased = UT_FALSE;
+       m_uBackgroundCheckReasons = 0;
 
        m_pLayout = m_pSectionLayout->getDocLayout();
        m_pDoc = m_pLayout->getDocument();
@@ -2963,7 +2964,7 @@
        }
 
        // in case we've never checked this one
-       m_pLayout->dequeueBlock(this);
+       m_pLayout->dequeueBlockForBackgroundCheck(this);
 
        FV_View* pView = pSL->getDocLayout()->getView();
        if (pView)
@@ -3218,8 +3219,8 @@
        {
                // this block may never have been checked
                // just to be safe, let's make sure both will
-               m_pLayout->queueBlockForSpell(this);
-               m_pLayout->queueBlockForSpell(pNewBL);
+               m_pLayout->queueBlockForBackgroundCheck(FL_DocLayout::bgcrSpelling, 
+this);
+               m_pLayout->queueBlockForBackgroundCheck(FL_DocLayout::bgcrSpelling, 
+pNewBL);
        }
 
        return UT_TRUE;
@@ -4194,7 +4195,34 @@
        m_bStopList = bValue;
 }
 
+void fl_BlockLayout::debugFlashing(void)
+{
+       // Trivial background checker which puts on and takes off squiggles from
+       // the entire block that's being checked.  This sort of messes up the
+       // spelling squiggles, but it's just a debug thing anyhow.  Enable it
+       // by setting a preference DebugFlash="1"
+       UT_DEBUGMSG(("fl_BlockLayout::debugFlashing() was called\n"));
+       UT_GrowBuf pgb(1024);
+       UT_Bool bRes = getBlockBuf(&pgb);
+       UT_ASSERT(bRes);
 
+       const UT_UCSChar* pBlockText = pgb.getPointer(0);
+       UT_uint32 eor = pgb.getLength(); /* end of region */
+
+       FV_View* pView = m_pLayout->getView();
 
+       _addSquiggle(0, eor, UT_FALSE);
 
+       pView->_eraseInsertionPoint();
+       pView->updateScreen();
+       pView->_drawInsertionPoint();
+       usleep(250000);
 
+       //_deleteSquiggles(0, eor);
+
+       pView->_eraseInsertionPoint();
+       pView->updateScreen();
+       pView->_drawInsertionPoint();
+
+       return;
+}
diff -ru abi-072300-ORIG/src/text/fmt/xp/fl_BlockLayout.h 
abi-072300/src/text/fmt/xp/fl_BlockLayout.h
--- abi-072300-ORIG/src/text/fmt/xp/fl_BlockLayout.h    Sun Jul 16 13:13:51 2000
+++ abi-072300/src/text/fmt/xp/fl_BlockLayout.h Sun Jul 23 20:14:35 2000
@@ -215,6 +215,7 @@
        void checkForEndOnForcedBreak(void);
 
        void checkSpelling(void);
+       void debugFlashing(void);
        UT_Bool findNextTabStop(UT_sint32 iStartX, UT_sint32 iMaxX, UT_sint32& 
iPosition, unsigned char& iType);
        UT_Bool findNextTabStopInLayoutUnits(UT_sint32 iStartX, UT_sint32 iMaxX, 
UT_sint32& iPosition, unsigned char& iType);
        inline UT_sint32 getDefaultTabInterval(void) const { return 
m_iDefaultTabInterval; }
@@ -270,6 +271,14 @@
 
        static UT_Bool                  s_EnumTabStops(void * myThis, UT_uint32 k, 
UT_sint32 & iPosition, unsigned char & iType, UT_uint32 & iOffset);
        
+       inline void                     addBackgroundCheckReason(UT_uint32 reason) 
+{m_uBackgroundCheckReasons |= reason;}
+       inline void                     removeBackgroundCheckReason(UT_uint32 reason) 
+{m_uBackgroundCheckReasons &= ~reason;}
+       inline UT_Bool          hasBackgroundCheckReason(UT_uint32 reason) const 
+{return (m_uBackgroundCheckReasons & reason);}
+
+       // The following is a set of bit flags giving the reason this block is
+       // queued for background checking.  See specific values in fl_DocLayout.h
+       UT_uint32                               m_uBackgroundCheckReasons;
+
 #ifdef FMT_TEST
        void                                    __dump(FILE * fp) const;
 #endif
@@ -386,6 +395,7 @@
 
        // spell check stuff
        UT_Vector                               m_vecSquiggles;
+
 };
 
 /*
diff -ru abi-072300-ORIG/src/text/fmt/xp/fl_DocLayout.cpp 
abi-072300/src/text/fmt/xp/fl_DocLayout.cpp
--- abi-072300-ORIG/src/text/fmt/xp/fl_DocLayout.cpp    Wed Jul 19 18:12:52 2000
+++ abi-072300/src/text/fmt/xp/fl_DocLayout.cpp Sun Jul 23 22:38:11 2000
@@ -49,17 +49,18 @@
        m_pDoc = doc;
        m_pG = pG;
        m_pView = NULL;
-       m_pSpellCheckTimer = NULL;
+       m_pBackgroundCheckTimer = NULL;
        m_pPendingBlock = NULL;
        m_pPendingWord = NULL;
        m_pFirstSection = NULL;
        m_pLastSection = NULL;
-       m_bAutoSpellCheck = UT_FALSE;
        m_bSpellCheckCaps = UT_TRUE;
        m_bSpellCheckNumbers = UT_TRUE;
        m_bSpellCheckInternet = UT_TRUE;
        m_pPrefs = NULL;
 
+       m_uBackgroundCheckReasons = 0;
+
        m_pRedrawUpdateTimer = UT_Timer::static_constructor(_redrawUpdate, this, m_pG);
        if (m_pRedrawUpdateTimer)
        {
@@ -93,12 +94,12 @@
 
        DELETEP(m_pDocListener);
 
-       if (m_pSpellCheckTimer)
+       if (m_pBackgroundCheckTimer)
        {
-               m_pSpellCheckTimer->stop();
+               m_pBackgroundCheckTimer->stop();
        }
        
-       DELETEP(m_pSpellCheckTimer);
+       DELETEP(m_pBackgroundCheckTimer);
        DELETEP(m_pPendingWord);
 
        if (m_pRedrawUpdateTimer)
@@ -150,6 +151,11 @@
 
                        // keep updating itself 
                        pPrefs->addListener ( _prefsListener, this ); 
+                       UT_Bool b;
+                       if (m_pPrefs->getPrefsValueBool("DebugFlash",&b))
+                       {
+                               addBackgroundCheckReason(bgcrDebugFlash);
+                       }
                }
        }
 }
@@ -526,29 +532,24 @@
 }
 #endif
 
-#define SPELL_CHECK_MSECS 100
+#define BACKGROUND_CHECK_MSECS 100
 
 void FL_DocLayout::_toggleAutoSpell(UT_Bool bSpell)
 {
-       UT_Bool bOldAutoSpell = m_bAutoSpellCheck;
-       m_bAutoSpellCheck = bSpell;
+       UT_Bool bOldAutoSpell = getAutoSpellCheck();
+       if (bSpell)
+       {
+               addBackgroundCheckReason(bgcrSpelling);
+       }
+       else
+       {
+               removeBackgroundCheckReason(bgcrSpelling);
+       }
 
        UT_DEBUGMSG(("FL_DocLayout::_toggleAutoSpell (%s)\n", bSpell ? "UT_TRUE" : 
"UT_FALSE" ));
 
        if (bSpell)
        {
-               // make sure the timer is started
-               if (!m_pSpellCheckTimer)
-               {
-                       m_pSpellCheckTimer = UT_Timer::static_constructor(_spellCheck, 
this, m_pG);
-                       if (m_pSpellCheckTimer)
-                               m_pSpellCheckTimer->set(SPELL_CHECK_MSECS);
-               }
-               else
-               {
-                       m_pSpellCheckTimer->start();
-               }
-
                // recheck the whole doc
                fl_DocSectionLayout * pSL = getFirstSection();
                while (pSL)
@@ -558,7 +559,7 @@
                        {
                                // TODO: just check and remove matching squiggles
                                // for now, destructively recheck the whole thing
-                               queueBlockForSpell(b, UT_FALSE);
+                               queueBlockForBackgroundCheck(bgcrSpelling, b);
                                b = b->getNext();
                        }
                        pSL = (fl_DocSectionLayout *) pSL->getNext();
@@ -566,10 +567,6 @@
        }
        else
        {
-               // make sure the timer is stopped
-               if (m_pSpellCheckTimer)
-                       m_pSpellCheckTimer->stop();     
-       
                // remove the squiggles, too
                fl_DocSectionLayout * pSL = getFirstSection();
                while (pSL)
@@ -593,7 +590,7 @@
        }
 }
 
-void FL_DocLayout::_spellCheck(UT_Timer * pTimer)
+void FL_DocLayout::_backgroundCheck(UT_Timer * pTimer)
 {
        UT_ASSERT(pTimer);
 
@@ -609,6 +606,10 @@
                return;
        }
 
+       // prevent getting a new timer hit before we've finished this one by
+       // temporarily disabling the timer
+       pDocLayout->m_pBackgroundCheckTimer->stop();
+
        UT_Vector* vecToCheck = &pDocLayout->m_vecUncheckedBlocks;
        UT_ASSERT(vecToCheck);
 
@@ -620,43 +621,71 @@
 
                if (pB != NULL)
                {
-                       vecToCheck->deleteNthItem(0);
-                       i--;
-
-                       //      note that we remove this block from queue before 
checking it
-                       //      (otherwise asserts could trigger redundant recursive 
calls)
-                       pB->checkSpelling();
+                       for (unsigned int bitdex=0; 
+bitdex<8*sizeof(pB->m_uBackgroundCheckReasons); ++bitdex)
+                       {
+                               // This looping seems like a lot of wasted effort when 
+we
+                               // don't define meaning for most of the bits, but it's 
+small
+                               // effort compared to all that squiggle stuff that 
+goes on
+                               // for the spelling stuff.
+                               UT_uint32 mask;
+                               mask = (1 << bitdex);
+                               if (pB->hasBackgroundCheckReason(mask))
+                               {
+                                       //      note that we remove this reason from 
+queue before checking it
+                                       //      (otherwise asserts could trigger 
+redundant recursive calls)
+                                       pB->removeBackgroundCheckReason(mask);
+                                       switch (mask)
+                                       {
+                                       case bgcrDebugFlash:
+                                               pB->debugFlashing();
+                                               break;
+                                       case bgcrSpelling:
+                                               pB->checkSpelling();
+                                               break;
+                                       case bgcrSmartQuotes:
+                                       default:
+                                               break;
+                                       }
+                               }
+                       }
+                       if (!pB->m_uBackgroundCheckReasons)
+                       {
+                               vecToCheck->deleteNthItem(0);
+                               i--;
+                       }
                }
        }
 
-       if (i == 0)
+       if (i != 0)
        {
-               // timer not needed any more, so suspend it
-               pDocLayout->m_pSpellCheckTimer->stop();
+               // restart timer unless it's not needed any more
+               pDocLayout->m_pBackgroundCheckTimer->start();
        }
 }
 
-void FL_DocLayout::queueBlockForSpell(fl_BlockLayout *pBlock, UT_Bool bHead)
+void FL_DocLayout::queueBlockForBackgroundCheck(UT_uint32 reason, fl_BlockLayout 
+*pBlock, UT_Bool bHead)
 {
        /*
-               This routine queues up blocks for timer-driven spell checking.  
+               This routine queues up blocks for timer-driven spell checking, etc.  
                By default, this is a FIFO queue, but it can be explicitly 
                reprioritized by setting bHead == UT_TRUE.  
        */
+       if (!m_pBackgroundCheckTimer)
+       {
+               m_pBackgroundCheckTimer = 
+UT_Timer::static_constructor(_backgroundCheck, this, m_pG);
+               if (m_pBackgroundCheckTimer)
+                       m_pBackgroundCheckTimer->set(BACKGROUND_CHECK_MSECS);
+       }
+       else
+       {
+               m_pBackgroundCheckTimer->start();
+       }
 
-       if (m_bAutoSpellCheck)
+       if (hasBackgroundCheckReason(bgcrDebugFlash))
        {
-               if (!m_pSpellCheckTimer)
-               {
-                       m_pSpellCheckTimer = UT_Timer::static_constructor(_spellCheck, 
this, m_pG);
-                       if (m_pSpellCheckTimer)
-                               m_pSpellCheckTimer->set(SPELL_CHECK_MSECS);
-               }
-               else
-               {
-                       m_pSpellCheckTimer->start();
-               }
+               pBlock->addBackgroundCheckReason(bgcrDebugFlash);
        }
+       pBlock->addBackgroundCheckReason(reason);
 
        UT_sint32 i = m_vecUncheckedBlocks.findItem(pBlock);
 
@@ -676,7 +705,7 @@
        }
 }
 
-void FL_DocLayout::dequeueBlock(fl_BlockLayout *pBlock)
+void FL_DocLayout::dequeueBlockForBackgroundCheck(fl_BlockLayout *pBlock)
 {
        UT_sint32 i = m_vecUncheckedBlocks.findItem(pBlock);
 
@@ -688,7 +717,7 @@
        // when queue is empty, kill timer
        if (m_vecUncheckedBlocks.getItemCount() == 0)
        {
-               m_pSpellCheckTimer->stop();
+               m_pBackgroundCheckTimer->stop();
        }
 }
 
diff -ru abi-072300-ORIG/src/text/fmt/xp/fl_DocLayout.h 
abi-072300/src/text/fmt/xp/fl_DocLayout.h
--- abi-072300-ORIG/src/text/fmt/xp/fl_DocLayout.h      Sun Jul  9 11:11:52 2000
+++ abi-072300/src/text/fmt/xp/fl_DocLayout.h   Sun Jul 23 20:17:05 2000
@@ -126,8 +126,8 @@
        void            setPendingWord(fl_BlockLayout *pBlock, fl_PartOfBlock* pWord);
        UT_Bool         checkPendingWord(void);
        
-       void            queueBlockForSpell(fl_BlockLayout *pBlock, UT_Bool 
bHead=UT_FALSE);
-       void            dequeueBlock(fl_BlockLayout *pBlock);
+       void            queueBlockForBackgroundCheck(UT_uint32 reason, fl_BlockLayout 
+*pBlock, UT_Bool bHead=UT_FALSE);
+       void            dequeueBlockForBackgroundCheck(fl_BlockLayout *pBlock);
 
        void            addSection(fl_DocSectionLayout*);
        void            removeSection(fl_DocSectionLayout*);
@@ -141,13 +141,27 @@
        void                            deleteEmptyPages(void);
 
 
-       UT_Bool         getAutoSpellCheck(void) const { return m_bAutoSpellCheck; }
+       UT_Bool         getAutoSpellCheck(void) const { return 
+(hasBackgroundCheckReason(bgcrSpelling)); }
        UT_Bool         getSpellCheckCaps(void) const { return m_bSpellCheckCaps; }
        UT_Bool         getSpellCheckNumbers(void) const { return 
m_bSpellCheckNumbers; }
        UT_Bool         getSpellCheckInternet(void) const { return 
m_bSpellCheckInternet; }
 
        void            recheckIgnoredWords();
 
+       inline void                     addBackgroundCheckReason(UT_uint32 reason) 
+{m_uBackgroundCheckReasons |= reason;}
+       inline void                     removeBackgroundCheckReason(UT_uint32 reason) 
+{m_uBackgroundCheckReasons &= ~reason;}
+       inline UT_Bool          hasBackgroundCheckReason(UT_uint32 reason) const 
+{return (m_uBackgroundCheckReasons & reason);}
+       inline UT_uint32        getBackgroundCheckReasons() const {return 
+(m_uBackgroundCheckReasons);}
+
+       // These are used as bit flags in a UT_uint32.  The enum is here just
+       // to get the namespace protection.
+       enum backgroundCheckReason
+       {
+               bgcrDebugFlash   = (1 <<  0),
+               bgcrSpelling     = (1 <<  1),
+               bgcrSmartQuotes  = (1 <<  2)
+       };
+
 #ifdef FMT_TEST
        static          FL_DocLayout* m_pDocLayout;
 
@@ -155,7 +169,7 @@
 #endif
        
 protected:
-       static void                     _spellCheck(UT_Timer * pTimer);
+       static void                     _backgroundCheck(UT_Timer * pTimer);
        void                            _toggleAutoSpell(UT_Bool bSpell);
        
        static void                     _prefsListener(class XAP_App *, class 
XAP_Prefs *, 
@@ -178,14 +192,15 @@
        UT_HashTable            m_hashFontCache;
 
        // spell check stuff
-       UT_Timer*                       m_pSpellCheckTimer; 
        UT_Vector                       m_vecUncheckedBlocks;
        fl_BlockLayout*         m_pPendingBlock;        // if NULL, then ignore 
m_pPendingWord
        fl_PartOfBlock*         m_pPendingWord;
-       UT_Bool                         m_bAutoSpellCheck;
        UT_Bool                         m_bSpellCheckCaps;
        UT_Bool                         m_bSpellCheckNumbers;
        UT_Bool                         m_bSpellCheckInternet;
+
+       UT_Timer*                       m_pBackgroundCheckTimer; 
+       UT_uint32                       m_uBackgroundCheckReasons;  // bit flags
 
        XAP_Prefs *                     m_pPrefs;
 
diff -ru abi-072300-ORIG/src/text/fmt/xp/fl_DocListener.cpp 
abi-072300/src/text/fmt/xp/fl_DocListener.cpp
--- abi-072300-ORIG/src/text/fmt/xp/fl_DocListener.cpp  Thu Jul  6 16:42:02 2000
+++ abi-072300/src/text/fmt/xp/fl_DocListener.cpp       Sun Jul 23 20:17:37 2000
@@ -241,7 +241,7 @@
 
                // BUGBUG: this is *not* thread-safe, but should work for now
                if (m_bScreen)
-                       m_pLayout->queueBlockForSpell(pBL);
+                       
+m_pLayout->queueBlockForBackgroundCheck(FL_DocLayout::bgcrSpelling, pBL);
 
                *psfh = (PL_StruxFmtHandle)pBL;
        }
diff -ru abi-072300-ORIG/src/text/fmt/xp/fl_SectionLayout.cpp 
abi-072300/src/text/fmt/xp/fl_SectionLayout.cpp
--- abi-072300-ORIG/src/text/fmt/xp/fl_SectionLayout.cpp        Thu Jul  6 16:42:02 
2000
+++ abi-072300/src/text/fmt/xp/fl_SectionLayout.cpp     Sun Jul 23 20:17:53 2000
@@ -2006,7 +2006,7 @@
                
                // BUGBUG: this is *not* thread-safe, but should work for now
                if (m_bScreen)
-                       m_pLayout->queueBlockForSpell(pBL);
+                       m_pLayout->queueBlockForBackgroundCheck(bgcrSpelling, pBL);
 #endif
 
        }
diff -ru abi-072300-ORIG/src/text/fmt/xp/fv_View.cpp 
abi-072300/src/text/fmt/xp/fv_View.cpp
--- abi-072300-ORIG/src/text/fmt/xp/fv_View.cpp Wed Jul 12 21:38:29 2000
+++ abi-072300/src/text/fmt/xp/fv_View.cpp      Sun Jul 23 20:18:15 2000
@@ -5469,7 +5469,7 @@
                        {
                                // TODO: just check and remove matching squiggles
                                // for now, destructively recheck the whole thing
-                               m_pLayout->queueBlockForSpell(b, UT_FALSE);
+                               
+m_pLayout->queueBlockForBackgroundCheck(FL_DocLayout::bgcrSpelling, b);
                                b = b->getNext();
                        }
                        pSL = (fl_DocSectionLayout *) pSL->getNext();
@@ -5505,7 +5505,7 @@
                        {
                                // TODO: just check and remove matching squiggles
                                // for now, destructively recheck the whole thing
-                               m_pLayout->queueBlockForSpell(b, UT_FALSE);
+                               
+m_pLayout->queueBlockForBackgroundCheck(FL_DocLayout::bgcrSpelling, b);
                                b = b->getNext();
                        }
                        pSL = (fl_DocSectionLayout *) pSL->getNext();
diff -ru abi-072300-ORIG/src/wp/ap/xp/ap_Dialog_Spell.cpp 
abi-072300/src/wp/ap/xp/ap_Dialog_Spell.cpp
--- abi-072300-ORIG/src/wp/ap/xp/ap_Dialog_Spell.cpp    Mon Jun 26 14:46:02 2000
+++ abi-072300/src/wp/ap/xp/ap_Dialog_Spell.cpp Sun Jul 23 21:02:02 2000
@@ -128,7 +128,7 @@
         // since we're done with this current block, put it
         // in the block spell queue so squiggles will be updated
         FL_DocLayout * docLayout = m_pSection->getDocLayout();
-        docLayout->queueBlockForSpell(m_pBlock, UT_FALSE);
+        docLayout->queueBlockForBackgroundCheck(FL_DocLayout::bgcrSpelling, m_pBlock);
         
         m_pBlock = m_pBlock->getNext();
 

Reply via email to