The code for save-as-file is as follows:
define method save-as-file
(gadget :: <gadget>, #key filename) => ()
let frame = sheet-frame(gadget);
let task-list = frame-task-list(frame);
let filename
= filename
| choose-file(frame: frame,
default: task-list.task-list-filename,
direction: #"output");
if (filename)
if (save-task-list(task-list, filename: filename))
frame.frame-task-list := task-list;
refresh-task-frame(frame)
else
notify-user(format-to-string
("Failed to save file %s", filename),
owner: frame)
end
end
end method save-as-file;
Add this code to frame.dylan.
Like open-file and save-file, this method takes a gadget as an argument and returns no values. This argument is the gadget which is used to invoke it. In addition, an optional keyword argument, a filename, can be passed.
This method is a little unusual; as well as being the activate callback for the save-as-menu-button (the command File > Save As), it is also called by the save-file method.
filename argument is not passed to save-as-file. Instead, the user is prompted to supply it. In addition, the gadget is save-as-menu-button.
save-file, a filename may be passed, if the associated task list has been saved before. In addition, the gadget is either save-button or save-menu-button.
As with open-file, save-as-file sets three local variables:
frameThis is the frame containing the gadget passed as an argument.
task-list This contains the value of the frame-task-list slot for frame, and identifies the instance of <task-list> to be saved.
filename The filename to which the instance of <task-list> is saved.
Unless filename is passed as an optional argument, the user is prompted to supply a filename in which the task list information is to be saved. As with open-file, the choose-file method is used to do this. In fact, the call to choose-file here is identical to the call to choose-file in open-file, with the exception of the direction argument, which is set to #"output".
The rest of the save-as-file method deals with saving the task list information safely. It is similar to the equivalent code in open-file, and consists of two nested if statements as shown below.
if (filename)
if (save-task-list(task-list, filename: filename))
frame.frame-task-list := task-list;
refresh-task-frame(frame)
else
notify-user(format-to-string("Failed to save file %s", filename),
owner: frame)
end
end
As with open-file, the clause
if (filename) ... end
is necessary in case the user cancels the Save file dialog: on cancelling the dialog, save-as-file should fail silently with no side effects.
The second if statement is more interesting. The body of the if statement is like the body of the equivalent if statement in open-file:
frame.frame-task-list := task-list; refresh-task-frame(frame)
This sets the frame-task-list slot of frame and then calls refresh-task-frame to ensure that the correct information is shown on the screen.
Similarly, the body of the else clause warns that the task list could not be saved, when the if condition does not return true:
notify-user(format-to-string("Failed to save file %s", filename),
owner: frame)
The interesting part of this if statement is the if condition itself:
save-task-list(task-list, filename: filename)
As well as providing a test for whether the task list frame should be updated, it actually performs the save operation, by calling the function save-task-list with the required arguments.
The function save-task-list is described in Section 5.3.1.5 on page 58 and the method refresh-task-frame is described in Section 5.3.3 on page 64.