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
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 RETURNThe 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 0040Line 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 0380This 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 0540The 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 RETURNLines 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 RETURNLines 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