www.riscos.com Technical Support: |
|
www.riscos.com Technical Support: |
|
A Save As Dialogue object is used to allow the user to drag an icon representing a document from a dialogue box to another application or to a directory display.
When a Save As Dialogue object is created, it has a number of components:
It is possible to specify the following:
The default Save As dialogue box, has a draggable sprite to represent the data to be saved, a writable field giving the name to save the data under, a Save (default) action button, a Cancel action button, and an option button saying whether the whole data or just a selection should be saved. If the client wishes to customise the dialogue box, then the above components must be present in that dialogue box, and must have the same component ids.
If the dialogue box is opened as a transient dialogue box, then it closes when the user clicks outside the box.
The user can interact with the Save As dialogue box in the following ways:
When the Selection option button is clicked on, then the filename will change to the string 'Selection'.
Once the Save As dialogue box is on display, the Save As module handles much of the messaging protocols associated with saving to another application or to a directory display. The client no longer deals in the normal Wimp protocols for data transfer, but instead responds to Toolbox events raised by the Save As module. In fact in the very simplest of cases, the client does no more than just provide a pointer to the data to be saved, and leaves the rest up to the Save As module.
A Save As object has the following attributes which are specified in its object template and can be manipulated at run-time by the client application:
Attributes | Description | |
---|---|---|
flags | Bit | Meaning |
0 | when set, this bit indicates that a SaveAs_AboutToBeShown event should be raised when SWI Toolbox_ShowObject is called for this object. | |
1 | when set, this bit indicates that a SaveAs_DialogueCompleted event should be raised when the Save As object has been removed from the screen. | |
2 | when set, do not include the Selection option button in the dialogue box. This is used by clients where there is no concept of a current selection. | |
3 | when set, handle the SaveAs operation entirely in the SaveAs module, from the supplied buffer | |
4 | when set, client is willing to support RAM transfers | |
filename | a message string which gives the default filename to use in the writable field | |
filetype | an integer giving the RISC OS type of the file being saved | |
title | a string to use for the Save As dialogue box title bar, instead of 'Save as' (0 means use the default string) | |
max title length | this gives the maximum length in bytes of title text which will be used for this object | |
window | an alternative window template to use instead of the default one (null implies default) |
A SaveAs object is created using SWI Toolbox_CreateObject.
When this object is created it has no attached objects (see Attached objects).
A SaveAs object is deleted using SWI Toolbox_DeleteObject.
The setting of the non-recursive delete bit does not have a meaning for SaveAs objects.
When a SaveAs object is displayed on the screen using SWI Toolbox_ShowObject it has the following behaviour:
Show type | Position | ||
---|---|---|---|
0 (default) | the underlying window is shown at the last place shown on the screen, or the coordinates given in its template, if it has not already been shown | ||
1 (full spec) | R3 + 0 | visible area minimum x coordinate | |
R3 + 4 | visible area minimum y coordinate | ||
R3 + 8 | visible area maximum x coordinate | ||
R3 + 12 | visible area maximum y coordinate | ||
R3 + 16 | scroll x offset relative to work area | ||
R3 + 20 | scroll y offset relative to work area | ||
R3 + 24 | Wimp window handle of window to open behind | ||
-1 | means top of stack | ||
-2 | means bottom of stack | ||
-3 | means the window behind the Wimp's backwindow | ||
2 (topleft) | R3 + 0 | visible area minimum x coordinate | |
R3 + 4 | visible area minimum y coordinate |
When a SaveAs Dialogue object is created, it is given the filename from its template to use in its writable field, and a filetype which will be used to look up and use a sprite (from the Wimp sprite pool) whose name is file_ HHH , where HHH is a 3-digit hex representation of the filetype. If such a sprite does not exist then a sprite called file_xxx is used instead. For saving directories and applications the filetype values 0x1000 and 0x2000 should be used. In the latter case, the standard 'App' sprite is used.
Both of these attributes can be set and read dynamically using the SaveAs_SetFileName/SaveAs_GetFileName and SaveAs_SetFileType/ SaveAs_GetFileType methods.
There are essentially three sorts of application:
Let us look at how a client should react to each Toolbox event which it will receive. Notice that these are the only events which the client needs to watch for to achieve the SaveAs operation; there is no need to watch for user drags and window events, and no need to watch for Message_RAMFetch events. The following is some pseudo-C showing how a client might process Toolbox events delivered to it:
switch(toolbox_event_code) { case SaveAs_AboutToBeShown: /* call SaveAs_SetFileSize, SaveAs_SetFileName, SaveAs_SetFileType and SaveAs_SelectionAvailable if necessary. Also call SaveAs_SetDataAddress to tell the Toolbox the address and size of data to be saved. */ break; case SaveAs_SaveCompleted: /* maybe mark a document as 'unmodified' */ break; case SaveAs_DialogueCompleted: /* do any tidying up maybe delete the SaveAs object if desired */ break; default: break; }
switch(toolbox_event_code) { case SaveAs_AboutToBeShown: /* call SaveAs_SetFileSize, SaveAs_SetFileName, SaveAs_SetFileType and SaveAs_SelectionAvailable if necessary */ break; case SaveAs_SaveToFile: /* save the data to the given filename and call SaveAs_FileSaveCompleted */ break; case SaveAs_SaveCompleted: /* maybe mark a document as 'unmodified' */ break; case SaveAs_DialogueCompleted: /* do any tidying up maybe delete the SaveAs object if desired */ break; default: break; }
switch(toolbox_event_code) { case SaveAs_AboutToBeShown: /* SaveAs_SetFileSize, call SaveAs_SetFileName, SaveAs_SetFileType and SaveAs_SelectionAvailable if necessary */ break; case SaveAs_SaveToFile: /* save the data to the given filename and call SaveAs_FileSaveCompleted */ break; case SaveAs_FillBuffer: /* if (address of buffer == 0) allocate a buffer for RAM transfer if (more data to go) { fill buffer with data call SaveAs_BufferFilled } */ break; case SaveAs_SaveCompleted: /* maybe mark a document as 'unmodified' */ break; case SaveAs_DialogueCompleted: /* do any tidying up maybe delete the SaveAs object if desired */ break; default: break; }
In the file transfer protocol under RISC OS, the sender of a file must specify an estimated size in bytes of the file being saved. This should be set using the SaveAs_SetFileSize method, and can be read using the SaveAs_GetFileSize method. This value will be used in the initial Message_DataSave message which will be sent by the SaveAs module when the file icon is dragged to its destination.
In the dialogue box used to implement the SaveAs Dialogue object, there is an option button which is used to show whether the Save operation is to be done on the whole file or just a selection. Handling this button is done entirely by the SaveAs module. It is, however, the responsibility of the client to either enable or disable this option button, depending on whether there is a selection currently in existence. This will cause the button to appear greyed out when no selection exists.
The SaveAs module provides the method SaveAs_SelectionAvailable for this use. The client should typically use this method in response to the SaveAs_AboutToBeShown Toolbox event.
Once a SaveAs dialogue has been started by using Toolbox_ShowObject on a SaveAs Dialogue object, a SaveAs dialogue box will appear on the screen. By setting an appropriate bit in the SaveAs Dialogue object's flags word, the client will be sent a SaveAs_AboutToBeShown Toolbox event before the dialogue box appears. This allows the client to set any relevant state like a different filename, or filetype etc.
If the user clicks on the Cancel button or presses Escape (or clicks outside the SaveAs dialogue box if it was transient), then the SaveAs module delivers a SaveAs_DialogueCompleted Toolbox event to the client application (if enabled). This allows the client to update any of its data structures and to clean up any state associated with this dialogue.
If the client is able to supply the data to be saved in a contiguous block of memory (i.e. client type 1), then by setting bit 3 in the SaveAs object's flags word, the client can request that the SaveAs module handles the entire Save operation itself. To do this, the client must supply the address of the data (and its size), using the SaveAs_SetDataAddress method. Typically the client will do this when it receives the SaveAs_AboutToBeShown Toolbox event.
The SaveAs module will then conduct the rest of the dialogue. If it receives a Message_RAMFetch message from the receiver, it will do a RAM transfer on behalf of the client; otherwise it will do a scrap transfer (or save directly to file if the destination is a filing system). All of this is transparent to the client if bit 3 is set in the SaveAs object's flags word.
If bit 3 of the SaveAs object's flags word is not set (thus indicating that the Toolbox cannot do a save operation on the client's behalf), then when the SaveAs module wants the application to save to a file, it will deliver a SaveAs_SaveToFile Toolbox event. On receipt of this event, the client (type 2 always and type 3 when necessary) should save its data into the file whose name is given in the event block. The client should then use the SaveAs_FileSaveCompleted method to inform the SaveAs module whether the Save was successful or not. This must be done before the next call to SWI Wimp_Poll, since the SaveAs module will assume this.
The SaveAs_SaveToFile event will be delivered if
If bit 3 of the SaveAs object's flags word is not set (thus indicating that the Toolbox cannot do a save operation on the client's behalf), then the client (type 3 only) may wish to help support RAM transfers if they are requested by the receiving task. This is indicated by setting bit 4 of the SaveAs object's flags word.
The client must supply a buffer, into which it places data ready for transmission to the receiving task.
The SaveAs module will deal with all subsequent RAMFetch requests, and will call SWI Wimp_TransferBlock to do the data transfer, and will reply to the receiver using Message_RAMTransmit.
The client will receive SaveAs_FillBuffer Toolbox events when the buffer has been transmitted, and on receipt of such events should fill the buffer and call the SaveAs_BufferFilled method. If the field in the SaveAs_FillBuffer event giving the address of the buffer is 0, then the client has not yet supplied a buffer, and they should allocate one. Each SaveAs_FillBuffer Toolbox event contains an indication of how many bytes have been transmitted so far during the transfer. As soon as the number of bytes which the client writes into the buffer is less than the size of the buffer, the SaveAs module assumes that the transfer is complete.
When a Save operation has been successfully completed (i.e. the data has been saved), the SaveAs module will send a SaveAs_SaveCompleted Toolbox event to the client, and will hide the SaveAs object, unless the user has clicked Adjust on the Save button.
One field in the event block passed back to the client is a one-word indication of whether the destination was a 'safe' place (like a filing system) or 'unsafe' (like another application). The client may choose to use this value to decide whether to mark the data as 'un-modified', if the client is an editor.
If the original save operation was started by the user dragging the file icon from the SaveAs dialogue box, then the SaveAs_SaveCompleted event block also contains the Wimp message reference number of the Message_DataSave sent by the SaveAs module, to allow the client to use in conjunction with any Message_DataSaved replies.
When the SaveAs module has hidden its dialogue box at the end of a dialogue, it delivers a SaveAs_DialogueCompleted Toolbox event to the client, with an indication of whether a successful save occurred during the dialogue.
Any errors referring to the SaveAs dialogue box itself will be reported to the user by the SaveAs module. For example, if there is only a leafname in the writable field, and the user clicks on Save, then the SaveAs module will display an error box saying 'To save, drag the icon to a directory display'.
The SaveAs module will also report any errors which occur while it is carrying out a Save operation.
The client should report (via SWI Wimp_ReportError), any errors which occur if it is requested to save to a given filename.
The following methods are all invoked by calling SWI Toolbox_ObjectMiscOp with:
R0 | holding a flags word |
R1 | being a Save As Dialogue object id |
R2 | being the method code which distinguishes this method |
R3-R9 | potentially holding method-specific data |
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 0 |
R0 | = | Window object id for this Save As object |
This method returns the id of the underlying Window object used to implement this Save As object.
extern _kernel_oserror *saveas_get_window_id ( unsigned int flags, ObjectId saveas, ObjectId *window );
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 1 |
R3 | = | pointer to text string to use |
R1-R9 preserved |
This method sets the text which is to be used in the title bar of the given Save As dialogue.
extern _kernel_oserror *saveas_set_title ( unsigned int flags, ObjectId saveas, char *title );
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 2 |
R3 | = | pointer to buffer to return the text in (or 0) |
R4 | = | size of buffer |
R4 | = | size of buffer required to hold the text (if R3 was 0)
else Buffer pointed to by R3 contains title text R4 holds number of bytes written to buffer |
This method returns the text string used in a Save As dialogue's title bar.
extern _kernel_oserror *saveas_get_title ( unsigned int flags, ObjectId saveas, char *buffer, int buff_size, int *nbytes );
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 3 |
R3 | = | pointer to filename to use in writable field |
R1-R9 preserved |
This method sets the filename which is to be used in the Save As object's writable field.
extern _kernel_oserror *saveas_set_file_name ( unsigned int flags, ObjectId saveas, char *file_name );
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 4 |
R3 | = | pointer to buffer to return the filename in (or 0) R4 = size of buffer |
R4 | = | size of buffer required to hold the filename (if R3 was 0)
else Buffer pointed to by R3 contains filename R4 holds number of bytes written to buffer |
This method returns the filename displayed in this Save As object's writable field.
extern _kernel_oserror *saveas_get_file_name ( unsigned int flags, ObjectId saveas, char *buffer, int buff_size, int *nbytes );
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 5 |
R3 | = | filetype |
R1-R9 preserved |
This method is used to set the filetype for this Save As object, and hence the sprite which will be displayed in the dialogue box.
extern _kernel_oserror *saveas_set_file_type ( unsigned int flags, ObjectId saveas, int file_type );
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 6 |
R0 | = | filetype |
This method is used to get the filetype of this Save As object.
extern _kernel_oserror *saveas_get_file_type ( unsigned int flags, ObjectId saveas, int *file_type );
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 7 |
R3 | = | file size in bytes |
R1-R9 preserved |
This method is used to set the estimated file size in bytes for this Save As Dialogue. This will be used in a Message_DataSave message when the file icon is dragged to its destination.
extern _kernel_oserror *saveas_set_file_size ( unsigned int flags, ObjectId saveas, int file_size );
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 8 |
R0 | = | file size |
This method is used to get the file size of this Save As object.
extern _kernel_oserror *saveas_get_file_size ( unsigned int flags, ObjectId saveas, int *file_size );
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 9 |
R3 | = | non-zero means selection is available, otherwise it is not available |
R1-R9 preserved |
This method is used to indicate to the Save As module whether there is a current selection in existence. If there is a selection, then the Selection option button will be enabled (i.e. the user can click on it), if not the Selection option button will be greyed out.
If the Save As object has no Selection option button then an error is returned.
extern _kernel_oserror *saveas_selection_available ( unsigned int flags, ObjectId saveas, int selection );
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 10 |
R3 | = | address of contiguous block of data which is to be saved |
R4 | = | size of data |
R5 | = | address of contiguous block of data, which is the current selection |
R6 | = | size of selection |
R1-R9 preserved |
This method indicates to the Save As module the address of a contiguous block of memory containing the data to be saved. It is used if the client wishes the entire Save operation to be carried out by the Save As module. It is typically called in response to a SaveAs_SaveAboutToBeShown Toolbox event. If there is a current selection, then its address and size should also be passed to this method.
Note: This method is only suitable for Type 1 clients.
extern _kernel_oserror *saveas_set_data_address ( unsigned int flags, ObjectId saveas, void *data, int data_size, void *selection, int selection_size );
R0 | = | flags |
R1 | = | Save As object id |
R2 | = | 11 |
R3 | = | address of buffer which has been filled |
R4 | = | number of bytes written into buffer |
R1-R9 preserved |
This method is used to respond to a SaveAs_FillBuffer Toolbox event; it confirms that the requested buffer fill has taken place, and states the number of bytes written to the buffer.
extern _kernel_oserror *saveas_buffer_filled ( unsigned int flags, ObjectId saveas, void *buffer, int bytes_written );
R0 | = | flags bit 0 set means that the save was successful |
R1 | = | Save As object id |
R2 | = | 12 |
R3 | = | filename where the client tried to save the data |
R1-R9 preserved |
This method is used by the client to report whether an attempt to save the data to file as a result of a SaveAs_SaveToFile Toolbox event was successful or not.
If this SWI is called with bit 0 of R0 clear, then it will return an error.
Note: This method is only suitable for Type 2 and Type 3 clients.
extern _kernel_oserror *saveas_file_save_completed ( unsigned int flags, ObjectId saveas, char *filename );
+ 8 | 0x82bc0 |
+ 12 | flags (as passed in to Toolbox_ShowObject) |
+ 16 | value which will be passed in R2 to ToolBox_ShowObject |
+ 20... | block which will be passed in R3 to ToolBox_ShowObject for the
underlying dialogue box |
This Toolbox event is raised just before the Save As module is going to show its underlying Window object, to enable the client to set its filename and filetype appropriately.
typedef struct { ToolboxEventHeader hdr; int show_type; union { TopLeft pos; WindowShowObjectBlock full; } info; } SaveAsAboutToBeShownEvent;
+ 8 | 0x82bc1 |
+ 12 | flags
bit 0 set means that a successful save was done during this dialogue |
This Toolbox event is raised after the Save As object has been hidden, either by a Cancel click, or after a successful save, or by the user clicking outside the dialogue box or pressing Escape. It allows the client to tidy up its own state associated with this dialogue.
Note that if the dialogue was cancelled, a successful save may still have been done, for example if the user clicked Adjust on Save, and then cancelled the dialogue.
typedef struct { ToolboxEventHeader hdr; } SaveAsDialogueCompletedEvent;
+ 8 | 0x82bc2 |
+ 12 | flags bit 0 set means save only the current selection |
+ 16... | nul-terminated filename to which the data should be saved |
This Toolbox event is raised by the Save As module to request that the client should save its data to the given filename. If bit 0 of the flags word is set, then only the current selection should be saved.
typedef struct { ToolboxEventHeader hdr; char filename [212]; } SaveAsSaveToFileEvent;
+ 8 | 0x82bc3 |
+ 12 | flags
bit 0 set means a selection is being saved |
+ 16 | size of buffer being used |
+ 20 | address of buffer |
+ 24 | number of bytes already transmitted |
This Toolbox event is raised by the Save As module to request that the client should fill the given buffer (which is the one which the client will have allocated).
If the address returned by this event is 0, then the client application needs to do one of the following:
typedef struct { ToolboxEventHeader hdr; int size; char *address; int no_bytes; } SaveAsFillBufferEvent;
+ 8 | 0x82bc4 |
+ 12 | flags
bit 0 set means a selection was saved bit 1 set means the destination was safe (e.g. a filing system) |
+ 16 | Wimp message number of original Message_DataSave
(or 0 if the save operation was not started via a drag) |
+ 20... | if bit 1 is set in the flags word (i.e. safe save), then this field indicates the
full pathname of the place where the save was done. |
This Toolbox event is raised when the Save is successfully completed. Bit 0 of the flags word indicates whether just a selection was saved; bit 1 means that the Save was to a place where the data is safe (e.g. it is in a real file, on a filing system).
typedef struct { ToolboxEventHeader hdr; int wimp_message_no; char filename [208]; } SaveAsSaveCompletedEvent;
The layout of a Save As template is shown below. Fields which have types MsgReference and StringReference are those which will require relocation when they are loaded from a resource file. If the template is being constructed in memory, then these fields should be real pointers (i.e. they do not require relocation).
For more details on relocation, see Resource File Formats.
Field | Size in bytes | Type |
---|---|---|
flags | 4 | word |
filename | 4 | MsgReference |
filetype | 4 | word |
title | 4 | MsgReference |
max_title | 4 | word |
window | 4 | StringReference |
The Window object used to implement a Save As dialogue, has the following characteristics. These must be reproduced if the Window is replaced by a client-specified alternative Window template.
Title bar must be indirected.
Component ids are derived by adding to 0x82bc00.
Component id | Details | |
---|---|---|
0 | draggable (file icon) | must be sprite only |
1 | writable field (filename) | |
2 | action button (Cancel) | must be marked as a Cancel action button |
3 | action button (Save) | must be marked as the Default action button |
4 (if required) | option button (Selection) |
Wimp event | Action |
---|---|
Mouse Click | if this is a drag event on the file icon, then set up an appropriate Wimp drag box |
ActionButton_Selected | on the Save button then start save operation
on the Cancel button then hide the dialogue box, and raise a SaveAs_DialogueCompleted Toolbox event |
Draggable_DragEnded (Toolbox event) | start save operation to the destination of the drag (i.e. send a Message_DataSave to the destination window/icon pair. |
Key Pressed | if dialogue box has the input focus, and the key pressed is Return, then the Save Button is activated, and a save operation is started
if key is Escape act as if Cancel had been pressed. |
User Message
User Message Recorded | Message_DataSaveAck
if (a SaveAs dialogue is in progress) { if (the save can be done entirely by the SaveAs module) { do the save send Message_DataLoad to destination } else { raise a SaveAs_SaveToFile Toolbox event } } Message_DataLoadAck if (a SaveAs dialogue is in progress) { raise a SaveAs_SaveCompleted Toolbox event If (not an Adjust click on OK) ( hide the dialogue box raise a SaveAs_DialogueCompleted Toolbox event ) } Message_RAMFetch if (a SaveAs dialogue is in progress) { transfer current buffer contents send Message_RAMTransmit to destination if (save cannot be done entirely by the Toolbox module) raise SaveAs_FillBuffer Toolbox event } If (a SaveAs dialogue is in progress) { raise a SaveAs_DialogueCompleted Toolbox event } |