These articles are excerpted from various 1996 issues of PDA Developers magazine. Copyright (C) 1996 by Creative Digital, Inc. All Rights Reserved.

For a sample copy of PDA Developers, contact Creative Digital at info© cdpubs.com or visit their web site at http://www.cdpubs.com.

NS BASIC CORNER - RECENT ITEM EDITOR
John Schettino
GTE Laboratories, Inc.
js12© gte.com



Copyright(C) 1996 by Creative Digital Publishing Inc. All rights reserved.

In the last column I said that I'd get started on the first version of a Newton-like NS BASIC program. The program I'm going to develop will eventually end up with a Newton user interface, but I'm going to build it first with a plain-character interface. This is easier to program and lets me focus on solving the problem before I spend a lot of time creating the interface. So in this column and the next, I'll create the Recent Item Editor (RIE). The RIE is a handy little utility that you can use to remove those recent items that appear in several pick lists in Newton 2.0.

WARNINGS AND WHATNOT
This program, which modifies System information, only works with Newton 2.0. As with any programming project, you can delete something unintentionally due to a programming error. Always be sure to have a recent backup.

The program also uses features of NS BASIC 3.x such as IF...ELSE...END IF and DO WHILE...LOOP statements. If you are using an older version of NS BASIC, you need to modify the programs to use GOTOs. Here is an example:

REM	***	3.x version ***
260 DO WHILE FSTAT <> 1 AND
		STREQUAL(SUBSTR(riFrame.tag,0,3), "_M_")
270   IF HASSLOT(riFrame, 'items) THEN
280     numItems = LENGTH(riFrame.items)
290     IF numItems > 0 THEN
300       ADDARRAYSLOT(itemArray, riFrame.tag)
310       PRINT itemNo; ") ";
			SUBSTR(riFrame.tag,3, STRLEN(riFrame.tag))
320       itemNo = itemNo + 1
330     END IF
340   END IF
350   GET ch, riFrame
360 LOOP
370 IF itemNo = 1 THEN RETURN

REM	*** 2.x version ***
260 IF NOT (FSTAT <> 1 AND STREQUAL(SUBSTR
			(riFrame.tag,0,3),"_M_")) THEN GOTO 370
270 IF NOT (HASSLOT(riFrame, 'items)) THEN GOTO 340
280 numItems = LENGTH(riFrame.items)
290 IF NOT (numItems > 0) THEN GOTO 330
300 ADDARRAYSLOT(itemArray, riFrame.tag)
310 PRINT itemNo; ") ";
			SUBSTR(riFrame.tag,3, STRLEN(riFrame.tag))
320 itemNo = itemNo + 1
330 REM END IF
340 REM END IF
350 GET ch, riFrame
360 GOTO 260
370 IF itemNo = 1 THEN RETURN

The two versions above do exactly the same thing. As you can see, the 3.x version is a lot easier to understand.

Recent Items
When you tap the assist Please picker, the To: picker for e-mail, the Name picker for Faxing and other pickers that retain previous selections, Newton 2.0 includes the previous ten entries for that picker in the pop-up (see Figure 1). These values are stored in the System file which, incidentally, has a key named tag. You can identify entries in this file because they use a tag value that begins with "_M_", and they have a field named items. You can use this information to locate the existing recent-item entries in your Newton.

THE RIE DESIGN
The RIE is able to do three very useful things:

Since I use a text interface for the first version of this application, I use menus to present command choices and get user selections. I also want to provide a way for the user to change their mind before deleting all the recent items.

GETTING STARTED
When the program starts up, it needs to do some preparation work and then display the main menu:

10 REM RIE - recent items editor
20 REM Version 1.0 by John Schettino
30 OPEN ch, "System", tag
40 PRINT "Recent Items Editor"
50 PRINT
60 PRINT "1) Edit a single Recent Items entry"
70 PRINT "2) List all Recent Items entries"
80 PRINT "3) Delete all Recent Item entries"
90 PRINT
100 PRINT "Enter selection (1-3, Q to Quit): "
110 INPUT selection$
120 IF STRLEN(selection$) = 1 AND
			STRPOS("123Q", selection$, 0) THEN
130   IF selection$ = "Q" THEN
140     CLOSE ch
150     END
160   END IF
170   ON STRINGTONUMBER(selection$) GOSUB 0220,0690,0850
180 ELSE
190   PRINT selection$; " is not a correct entry."
200 END IF
210 GOTO 0040

Line 30 opens the System file using the tag key. The file channel is stored in ch. Lines 40-110 display the main menu and then get the user's selection. Line 120 tests the entry to make sure it's valid. I then test to make sure that exactly one character is entered and that it is one of the valid selections. Lines 130-160 close the file and end the program if the user entered "Q". If not, line 170 GOSUBs to one of three subroutines. Each subroutine performs a specific function and then returns. If the input is not valid, line 190 prints an error message. Line 210 returns execution to the beginning of the main menu display. This block continues to loop, displaying the main menu, getting the user selection and doing the user's selection until the user enters "Q".

EDITING A SINGLE RECENT ITEM ENTRY
The function starting at line 220, which lets the user edit a recent entry item, first displays all recent-item entries that contain data. The user selects one of these entries. A menu of that entry's items is displayed next. The user selects one to delete or enters "A" to delete all the items.


220 REM Edit recent items for an entry
230 itemArray := []
240 itemNo = 1
250 GET ch, riFrame, "_M_"
260 DO WHILE FSTAT <> 1 AND
			STREQUAL(SUBSTR(riFrame.tag,0,3), "_M_")
270   IF HASSLOT(riFrame, 'items) THEN
280     numItems = LENGTH(riFrame.items)
290     IF numItems > 0 THEN
300       ADDARRAYSLOT(itemArray, riFrame.tag)
310       PRINT itemNo; ") ";
						SUBSTR(riFrame.tag,3,STRLEN(riFrame.tag))
320       itemNo = itemNo + 1
330     END IF
340   END IF
350   GET ch, riFrame
360 LOOP
370 IF itemNo = 1 THEN RETURN
380 PRINT
390 PRINT "Enter selection (1-";itemNo -1;",
			R to Return): "
400 INPUT selection$
410 IF selection$ = "R" THEN RETURN
420 ON ERROR GOTO 0460
430 selItem := itemArray[FLOOR
			(STRINGTONUMBER(selection$))-1]
440 ON ERROR GOTO 0000
450 GOTO 0480
460 PRINT selection$; " is not a correct entry."
470 GOTO 0380

This first block of code displays the names of each recent-item entry as a menu and then gets the user's selection. Lines 250-360 get every entry in the System file that has a key that begins with "_M_". Line 250 gets the first entry. The DO WHILE...LOOP block in 260-360 is executed for each entry. Line 270 tests to see if the entry contains an items field. Line 290 tests to see if the items array has at least one element. If it does, then I add the key to an array of all keys and print the entry name (without the "_M_" prefix). Line 350 moves to the next entry in the System file.

Line 370 returns from this subroutine if there are no recent item entries. If there are then in lines 380-400 a user selection prompt is printed and the selection is input. If the user enters "R", indicating they want to return to the first menu, the program returns in line 410. Since I don't know ahead of time all of the valid entries, I use error handling to detect invalid input in line 420. I try to retrieve the key from the array of keys in line 430. If the entry is not valid, an error is raised and an invalid selection message is printed in line 440. If it is valid I end up with the selected key string in selItem.


480 GET ch, riFrame, selItem
490 PRINT "Recent items for: ";
			SUBSTR(selItem,3, STRLEN(selItem))
500 FOR i = 0 TO LENGTH(riFrame.items) -1
510   PRINT i+1; ") ", riFrame.items[i].item
520 NEXT i
530 PRINT
540 PRINT "Enter recent item to delete (1-";i;",
			A for All, D when Done): "
550 INPUT selection$
560 IF selection$ = "D" THEN GOTO 0220
570 IF STREQUAL(selection$, "A") OR i = 1 THEN
580   DEL ch, riFrame
590   GOTO 0220
600 END IF
610 ON ERROR GOTO 0670
620 delItem = FLOOR(STRINGTONUMBER(selection$))
630 ARRAYREMOVECOUNT(riFrame.items,delItem-1,1)
640 PUT ch, riFrame
650 ON ERROR GOTO 0000
660 GOTO 0490
670 PRINT selection$; " is not a correct entry."
680 GOTO 0540

The next block of code starts by retrieving the selected entry. Each item in the entry is printed as a menu in lines 490-520. The user selection is entered and processed in lines 530-680. I use error handling similar to that used in the previous code block to detect invalid selections. Line 570 determines if the delete-all-items choice is made. When the user deletes all items I delete the complete entry. This happens when they enter "A" or they delete the last item. In both cases line 580 deletes the entry and I GOTO the section of code that displays all entries.

If the user deletes a specific item, lines 620-640 compute the item number to remove, remove the item from the items array, and then update the System file by replacing the entry. The remaining items are displayed by branching to line 490.

LISTING ALL ENTRIES
This subroutine lists all the recent-item entries. This is an easy way to locate recent item entries that need to be trimmed.


690 REM list all entries
700 GET ch, riFrame, "_M_"
710 DO WHILE FSTAT <> 1 AND
			STREQUAL(SUBSTR(riFrame.tag,0,3), "_M_")
720   IF HASSLOT(riFrame, 'items) THEN
730     numItems = LENGTH(riFrame.items)
740     itemStr := " item"
750     IF numItems > 1 THEN itemStr := itemStr & "s"
760     PRINT SUBSTR(riFrame.tag,3,STRLEN(riFrame.tag));
					" has "; numItems; itemStr
770     FOR i = 0 TO LENGTH(riFrame.items) -1
780       PRINT "  ", i+1; ") "; riFrame.items[i].item
790     NEXT i
800   END IF
810   GET ch, riFrame
820 LOOP
830 PRINT "------------------------"
840 RETURN

Lines 700-820 retrieve all the recent item entries from the System file. Lines 760-790 print each entry name, followed by all its items. Each item is a frame that contains a field named item. This field is usually the string that is displayed in the pop-up. Once all the entries are displayed this subroutine returns back to the main menu code.

DELETING ALL ENTRIES
This function makes very sure the user wants to proceed and then deletes every recent-item entry in the System file.


850 REM delete all entries
860 PRINT "Are you sure? Y/N: "
870 INPUT doIt$
880 IF doIt$ <> "Y" THEN RETURN
890 PRINT "This will DELETE all recent items.
			It CANNOT be undone. Please be sure you have a
			current backup!"
900 PRINT "Confirm to Delete ALL recent items: Y/N:"
910 INPUT doIt$
920 IF doIt$ <> "Y" THEN RETURN
930 PRINT "Deleting all recent items."
940 GET ch, riFrame, "_M_"
950 DO WHILE FSTAT <> 1 AND
			STREQUAL(SUBSTR(riFrame.tag,0,3), "_M_")
960   PRINT "Deleting: "; SUBSTR(riFrame.tag,3,
				STRLEN(riFrame.tag))
970   DEL ch, riFrame
980   GET ch, riFrame, "_M_"
990 LOOP
1000 PRINT "------------------------"
1010 RETURN

Lines 850-920 give the user plenty of warning and information about what is about to happen. If the user enters "Y" twice, then each entry is located and deleted from the System file. Line 970 deletes the entry. Line 980 must use a GET with the "_M_" key to reposition the file. A GET without a key does not work because the current entry is deleted.

TEST DRIVE
Running this program on my cluttered Newton produced a lot of interesting output. I was able to remove the recent items for assist, and for some meetings that I entered during testing of another program. Here's a sample session:


* run
Recent Items Editor

1) Edit a single Recent Items entry
2) List all Recent Items entries
3) Delete all Recent Item entries

Enter selection (1-3, Q to Quit):
? 2
addressee has 1 item
          1) John Doe
assistant has 8 items
          1) ng tom
          2) ng Schett
          3) ng Ab
          4) ng tlanning
          5) ng John
          6) find sch
          7) Did not compute
          8) 6
caller has 1 item
          1) Acton Toyota
cityName has 7 items
          1) Anytown
          2) 91400 Orsay
          3) Chestnut Hill
          4) Cambridge
          5) Reading
          6) Burlington
          7) NY
..
------------------------
Recent Items Editor

1) Edit a single Recent Items entry
2) List all Recent Items entries
3) Delete all Recent Item entries

Enter selection (1-3, Q to Quit):
?1
1) addressee
2) assistant
3) caller
..
21) scheduleMtgTitle
22) todoTitle

Enter selection (1-22, R to Return):
? 22
Recent items for: todoTitle
1)        y
2)        test
3)        x
4)        finish reviews!
5)        call mortgages Call APP

Enter recent item to delete (1-5, A for All, D when Done):
? A
1) addressee
2) assistant
..

NEXT TIME
This version is the beginning of a useful application. It contains a bit of the error handling you need to do if you use INPUT statements. It also uses the file commands to do something useful on Newton 2.0 systems. Next time I use the guts of this program over but put a nice Newton user interface on it with widgets. I also turn it into a package and have a complete, stand-alone application.


Return to the NS Basic Corner
Return to the product information main page