Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Integrating FoxSpell with VFP Applications

Developer Tools

Integrating FoxSpell with VFP Applications

by  GriffMG  Posted    (Edited  )
FoxSpell is a wholly VFP source code based spelling checker, developed by David Elliot Lewis PHD and available from Hallogram. It may also be available from StrategicEdge, but, at the time of writing, no web site could be found to match that address.

In order to write this FAQ, I've tried not to show the copyrighted code - if you want it, buy it - and restricted myself to showing the activation of the spellchecker by a command button.

The software is currently supplied by e-mail in two zip files:

ACAWORDS.ZIP
FS_VFP.ZIP

The first contains an alternative (larger) dictionary, the second contains the source code, a few forms and a smaller more manageable dictionary.

My first suggestion is to create a folder for the original source code and extract all the files there - including unzipping the smaller dictionary to create the three WORDSn.DBF files.

From here, the docmentation that comes with FoxSpell makes it pretty simple to get your first project up and running... but before you go ahead and do that, here are a few thoughts for you:

For distributing the dictionary files, I would recommend that you use a free table included within your project, call it BINARIES and give it a structure like the one below:

You can create the table by clicking on the 'free tables' branch on the project manager, under the data tab, save the completed table into your project development folder.

Code:
Field   Field Name       Type               Width    Dec  Index   Collate  Nulls
1        NAME            Character          10                             No
2        BINARY          Memo (binary)       4                             No

Browse the new table and append one record to it for each of the dictionary files, replacing the NAME field in each case with the name of the file, and using a FILETOSTR call to replace the BINARY field with the entire contents of the dictionary.

Code:
APPEND BLANK
REPLACE NAME WITH "WORDS1", BINARY WITH FILETOSTR("C:\DEV\MYPROJECT\WORDS1.DBF")

I've been using this approach for a while now to distribute sound files, FBZIP.EXE and other files which I don't need users to know about, but need to be 'resupplied' or 'updated' on demand from time to time.

Having created the table, and made doubly sure that it has been included in the project, I would suggest that you modify your existing projects source code to test for the presence of the three files on loading (placing them somewhere appropriate to your application) and should they not exist extract them from the BINARIES table and create the indexes for them.

Note here that you would be better off NOT using the built-in VFP FILE() function, as it can be confused by finding files of a similar name anywhere in the current 'PATH' setting!

I use a UDF called MyFile() (code below)
Code:
FUNCTION MYFILE
	PARAMETER m.FILENAME
	PRIVATE m.FILENAME,m.FLG
	M.FLG = .F.
	IF !EMPTY(m.FILENAME)
		IF ADIR(TMPDIRFILES,m.FILENAME) > 0
			M.FLG = .T.
		ENDIF
	ENDIF
	RETURN(m.FLG)

This is probably not the most elegant of approaches, but it works for me.

To extract and index the dictionary files, you could use code like that below:

Code:
public m.DOCLOCATION,m.CCAPTION
m.DOCLOCATION = "P:\PROJECTLIST\"
m.CCAPTION = ""

IF !MYFILE(m.DOCLOCATION+"WORDS1.DBF")
	SELECT 0
	USE ("C:\DEV\MYPROJECT\BINARIES")
	LOCATE FOR BINARIES.NAME = "WORDS1"
	STRTOFILE(BINARIES.BINARY,m.DOCLOCATION+"WORDS1.DBF")
	USE
	USE (m.DOCLOCATION+"WORDS1.DBF") EXCLUSIVE
	DELETE TAG ALL
	INDEX ON WORD TAG TEXT
	INDEX ON SOUNDEX(WORD) TAG SOUND
	USE
ENDIF

IF !MYFILE(m.DOCLOCATION+"WORDS2.DBF")
	SELECT 0
	USE ("C:\DEV\MYPROJECT\BINARIES")
	LOCATE FOR BINARIES.NAME = "WORDS2"
	STRTOFILE(BINARIES.BINARY,m.DOCLOCATION+"WORDS2.DBF")
	USE
	USE (m.DOCLOCATION+"WORDS2.DBF") EXCLUSIVE
	DELETE TAG ALL
	INDEX ON WORD TAG TEXT
	INDEX ON SOUNDEX(WORD) TAG SOUND
	USE
ENDIF

IF !MYFILE(m.DOCLOCATION+"WORDS3.DBF")
	SELECT 0
	USE ("C:\DEV\MYPROJECT\BINARIES")
	LOCATE FOR BINARIES.NAME = "WORDS3"
	STRTOFILE(BINARIES.BINARY,m.DOCLOCATION+"WORDS3.DBF")
	USE
	USE (m.DOCLOCATION+"WORDS3.DBF") EXCLUSIVE
	DELETE TAG ALL
	INDEX ON WORD TAG TEXT
	INDEX ON SOUNDEX(WORD) TAG SOUND
	USE
ENDIF

Note in the above example, the reference to C:\DEV\MYPROJECT\BINARIES will need to be changed to point to the original location of your BINARIES.DBF free table.
Also note that m.DOCLOCATION is a public variable holding the path to where you want to store the dictionaries.
By indexing the files after creating them, you save a lot of space in your deliverable executable.

You could/should check for and/or create the folder specified in m.DOCLOCATION before atempting to copy the files there:

Code:
IF !DIRECTORY(m.DOCLOCATION)
	MD (m.DOCLOCATION)
ENDIF

I can't speak for anyone else, but most of the applications I develop support the creation of a number of databases (call them companies, projects, locations or whatever) each
able to exist in complete isolation from one another - i.e. apart from a bit of shared set-up libraries (which can diverge later) there is no cross-linking between databases. This environment, combined with the ability for more than one machine to share a LIST of databases for a given application, provides an opportunity to store the dictionary files in the same place as the list (if you follow me).

Having created the code for extracting the dictionaries, we can look to the rest of the installation.

You need to include just three forms in your project for FoxSpell:
Code:
fs_ad2_d.scx
fs_del.scx
fs_main.scx

And, in practice just one piece of source code:
Code:
fs_spell.prg

I would recommend modifying the three forms slightly, to include your own project icon on each one and to put the following code close to the beginning of the INIT method of FS_MAIN.SCX (just after the 'private' statements works well).

Code:
	IF TYPE("M.cCaption") = "C"
		THISFORM.CAPTION = m.CCAPTION
	ENDIF

This tests for the existence of a (public) variable m.CCAPTION on loading - enabling you to control the forms caption when spell checking (to indicate which field is being checked for example).

The only other modification to the FoxSpell code I would suggest is to the bit opening the dictionaries on loading, this is contained in the FS_SPELL.PRG file and is near the beginning - you can identify the section by the snippet I've included below:

Code:
	* Created dictionary indexes, if missing------------------------------------- *
	* Open/select the dictionaries----------------------------------------------- *
	IF USED("WORDS1")  && If spelling dictionary #1 isn't open, then open it.
		SELECT WORDS1
	ELSE
		SELECT 0
		USE (m.DOCLOCATION+"WORDS1")
	ENDIF
	SET ORDER TO TAG TEXT

	IF USED("WORDS2")  && If spelling dictionary #2 isn't open, then open it.
		SELECT WORDS2
	ELSE
		SELECT 0
		USE (m.DOCLOCATION+"WORDS2")
	ENDIF
	SET ORDER TO TAG TEXT

	IF USED("WORDS3")  && If spelling dictionary #3 isn't open, then open it.
		SELECT WORDS3
	ELSE
		SELECT 0
		USE (m.DOCLOCATION+"WORDS3")
	ENDIF
	SET ORDER TO TAG TEXT
	* --------------------------------------------------------------------------- *

	* If checking a file, then open it------------------------------------------- *

If you replace everything from
Code:
* Created dictionary indexes, if missing------------------------------------- *
to
Code:
* If checking a file, then open it------------------------------------------- *

With the snippet above you will be relying on the code in your existing application to extract and index the dictionaries and the FS_SPELL.PRG program to find and use them.

Now you are ready to implement a spell check!

Select a form with a text or edit box that has text that needs checking, for the purposes of this exercise we'll assume the field is called COMMENTS.

Add a command button with no caption to the form and find yourself a nice spellcheck bitmap to place on it as a picture - there are dozens available on the internet for free download - then put the following code in the buttons CLICK procedure:

Code:
	PRIVATE m.STRING
	M.STRING = THISFORM.COMMENTS.VALUE
	M.CCAPTION = "Checking Spelling in 'Comments'"
	IF FS_SPELL("",@m.STRING,.T.)
		IF m.STRING <> THISFORM.COMMENTS.VALUE
			THISFORM.COMMENTS.VALUE = m.STRING
			THISFORM.COMMENTS.SETFOCUS
		ENDIF
	ENDIF

This will result in, when the button is clicked, the contents of the forms comments edit box being copied to a variable, a caption being set-up and the spellchecker being invoked.
Should the resultant string differ from the original, it is used to replace the contents of the edit box, and focus set to it (to force any valid or lostfocus events).

Simple as that.

The author provides a bunch of useful features, for importing text files and spell checking whole tables or files, if I use them - I'll try and write another FAQ!

Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top