Search Locate Previous Next Contents

Putting in ‘Proper’ Windows File Behaviour

Virtually all Windows applications now protect their users against accidental replacement of existing data with a new file. Naturally, they also warn users against exiting with unsaved data. When you start to work through the logic needed to implement this in your APL system it all gets surprisingly complicated – for example if you try to clear from an (untitled) file the application must check if you changed anything, prompt for a file name, check that the name you supply does not already exist, and only then write to disk! Here is part of the decision tree:


No -- Clear

/

New -- Dirty? No -- Clear

\ /

Yes -- Wanted? Yes -- Save & Clear

\ /

Yes -- Named? No -- see above

\ /

No -- Get name -- Exists? Yes

^ \ /

| Yes -- Overwrite?

| \

+---------<--------<--------<-No

... and of course there is the option to Cancel at any stage!

This is obviously one of those problems you want to solve once, and never have to think about again! One implementation of the solution is encapsulated in the Causeway NOSE (New-Open-Save-Exit) class – if you want to follow through the logic have a look at the FilePath function with )ed #.Class.NOSE.FilePath. The changes needed in the application code are (fortunately) nil, as we wrote it with Gui-independence in mind. All we need to do is to add a NOSE (under the Special submenu) to the main dialogue box and make some minor changes to the menu calls and tool button actions:


Here is the property browser for the nose – it will update the file name for us (‘file is set as its File property), but it needs to know how to prompt for it in the Windows filebox. This is why you should fill in something like:

'*.con' 'Contacts file'

... in the Specification property. It appears in the form (in the designer only) as a small square which is conventionally stuck in the top left corner, but of course you can put it wherever you like. Naturally, it has no visible caption, so it uses the caption you give it as a hint!

Now to change the main menu, but first a useful trick that you will come across frequently when building complex forms with interacting objects. We are going to want to run several built-in functions (methods) on the nose, and to do this we need its true (Dyalog) name as the left argument for CPro.Do. The easy way is to catch this name on creation, and set it as a local variable on the main form.


Here you can see that I have done the same trick for the status bar, which we will need shortly.

Now set up the event table for the nose itself to look like this:


Now all we need to do is to set the actions on the menu to call the nose rather than running the file functions directly:


[file]
 &New=Ctrl+N;Clear all data : nose ’Do 'New'
 &Open=Ctrl+O;Open an existing file : nose ’Do 'Open'
 &Save=Ctrl+S;Save your work : nose ’Do 'Save'
 Save&As;Save with a new name : nose ’Do 'SaveAs' 
 -------------
 E&xit:’Post 'SC'

... and the same for the action table on the toolbar:

     Disp dbx.tbar[2 3 4;1 2 5]

ÚÎÎÂÎÎÎÎÎÂÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÌ

ÛTLÛ*New ÛÚÎÎÎÎÎÎÎÎÎÂÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÌ Û

Û Û ÛÛBehaviourÛÚÎÎÂÂÎÎÎÎÎÎÎÎÎÎÎÎÎÎÂÎÎÌÛ Û

Û Û ÛÛ ÛÛSLÛÛnose ’Do ‘New’Û{}ÛÛ Û

Û Û ÛÛ ÛÀÎÎÁÁÎÎÎÎÎÎÎÎÎÎÎÎÎÎÁÎÎÙÛ Û

Û Û ÛÀÎÎÎÎÎÎÎÎÎÁÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÙ Û

ÃÎÎÏÎÎÎÎÎÏÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÝ

ÛTLÛ*OpenÛÚÎÎÎÎÎÎÎÎÎÂÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÌÛ

Û Û ÛÛBehaviourÛÚÎÎÂÂÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÂÎÎÌÛÛ

Û Û ÛÛ ÛÛSLÛÛnose ’Do ‘Open’Û{}ÛÛÛ

Û Û ÛÛ ÛÀÎÎÁÁÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÁÎÎÙÛÛ

Û Û ÛÀÎÎÎÎÎÎÎÎÎÁÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÙÛ

ÃÎÎÏÎÎÎÎÎÏÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÝ

ÛTLÛ*SaveÛÚÎÎÎÎÎÎÎÎÎÂÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÌÛ

Û Û ÛÛBehaviourÛÚÎÎÂÂÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÂÎÎÌÛÛ

Û Û ÛÛ ÛÛSLÛÛnose ’Do ‘Save’Û{}ÛÛÛ

Û Û ÛÛ ÛÀÎÎÁÁÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÁÎÎÙÛÛ

Û Û ÛÀÎÎÎÎÎÎÎÎÎÁÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÙÛ

ÀÎÎÁÎÎÎÎÎÁÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÙ

Finally, we must allow the nose to intervene when the user hits File,Exit, or (in Windows 95) accidentally catches the X button at the top right of the form. Causeway always signals a Close Request (CL) event just before the main form exits – if you run an action which rejects this event, then the form will not be closed.


This is the first time you have seen the Condition column used in the event-action table. The nose will check if it is safe to exit, and return 1 if all the conditions are met (nothing to save, or the user hit No).

This leads to the rather odd double negative – if the condition is not true we must reject the event, so preventing the form from closing.


To explain the condition/action columns more formally:

That completes the introduction to the Causeway nose class. It is not simple, and you might well come back to these notes several times in the future – I often find myself checking existing applications as a reminder of how I coded it. Probably what you should now do is to spend some time testing your main dialogue, and exploring all possible branches of the decision-tree to prove that it really is impossible for your users to (accidentally) destroy their data.



Continue to: Adding a ‘Most Recently Used’ List
© Copyright Causeway Graphical Systems Ltd 2001