summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Lees <adrian@aemulor.com>2009-01-10 00:18:34 +0000
committerAdrian Lees <adrian@aemulor.com>2009-01-10 00:18:34 +0000
commitd67a57c1e94f8b36b2c8f6785b6b7b404f85de21 (patch)
treec4d36bc29eecb315a4bb3bbb9268e9632556a23a
parent4e3951660f5b3b719f79ba66f3d2aafdbee1f424 (diff)
downloadnetsurf-d67a57c1e94f8b36b2c8f6785b6b7b404f85de21.tar.gz
netsurf-d67a57c1e94f8b36b2c8f6785b6b7b404f85de21.tar.bz2
Assorted saving-related changes (WIP)
svn path=/trunk/netsurf/; revision=6010
-rw-r--r--riscos/configure.c4
-rw-r--r--riscos/dialog.c64
-rw-r--r--riscos/dialog.h1
-rw-r--r--riscos/download.c75
-rw-r--r--riscos/gui.c13
-rw-r--r--riscos/query.c49
-rw-r--r--riscos/query.h3
-rw-r--r--riscos/save.c244
8 files changed, 368 insertions, 85 deletions
diff --git a/riscos/configure.c b/riscos/configure.c
index a90a6fc62..c56811cfd 100644
--- a/riscos/configure.c
+++ b/riscos/configure.c
@@ -70,8 +70,8 @@ static bool ro_gui_configure_click(wimp_pointer *pointer);
static void ro_gui_configure_open_window(wimp_open *open);
static void ro_gui_configure_close(wimp_w w);
static bool ro_gui_configure_translate(void);
-static void ro_gui_configure_register(const char *window,
- bool (*initialise)(wimp_w w), void (*finalise)(wimp_w w));
+static void ro_gui_configure_register(const char *window,
+ bool (*initialise)(wimp_w w), void (*finalise)(wimp_w w));
void ro_gui_configure_initialise(void)
{
diff --git a/riscos/dialog.c b/riscos/dialog.c
index 4c870a0f2..d9854f09e 100644
--- a/riscos/dialog.c
+++ b/riscos/dialog.c
@@ -311,13 +311,13 @@ wimp_window * ro_gui_dialog_load_template(const char *template_name)
/**
- * Open a dialog box, centered on the screen.
+ * Open a dialog box, centred on the screen.
*/
void ro_gui_dialog_open(wimp_w w)
{
int screen_x, screen_y, dx, dy;
- wimp_window_state open;
+ wimp_window_state state;
os_error *error;
/* find screen centre in os units */
@@ -326,31 +326,24 @@ void ro_gui_dialog_open(wimp_w w)
screen_y /= 2;
/* centre and open */
- open.w = w;
- error = xwimp_get_window_state(&open);
+ state.w = w;
+ error = xwimp_get_window_state(&state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
return;
}
- dx = (open.visible.x1 - open.visible.x0) / 2;
- dy = (open.visible.y1 - open.visible.y0) / 2;
- open.visible.x0 = screen_x - dx;
- open.visible.x1 = screen_x + dx;
- open.visible.y0 = screen_y - dy;
- open.visible.y1 = screen_y + dy;
- open.next = wimp_TOP;
- error = xwimp_open_window((wimp_open *) &open);
- if (error) {
- LOG(("xwimp_open_window: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("WimpError", error->errmess);
- return;
- }
+ dx = (state.visible.x1 - state.visible.x0) / 2;
+ dy = (state.visible.y1 - state.visible.y0) / 2;
+ state.visible.x0 = screen_x - dx;
+ state.visible.x1 = screen_x + dx;
+ state.visible.y0 = screen_y - dy;
+ state.visible.y1 = screen_y + dy;
+ state.next = wimp_TOP;
+ ro_gui_open_window_request((wimp_open*)&state);
- /* Set the caret position
- */
+ /* Set the caret position */
ro_gui_set_caret_first(w);
}
@@ -486,8 +479,6 @@ bool ro_gui_dialog_open_top(wimp_w w, struct toolbar *toolbar,
void ro_gui_dialog_open_at_pointer(wimp_w w)
{
- int dx, dy;
- wimp_window_state state;
wimp_pointer ptr;
os_error *error;
@@ -500,6 +491,20 @@ void ro_gui_dialog_open_at_pointer(wimp_w w)
return;
}
+ ro_gui_dialog_open_xy(w, ptr.pos.x - 64, ptr.pos.y);
+}
+
+
+/**
+ * Open window at a specified location.
+ */
+
+void ro_gui_dialog_open_xy(wimp_w w, int x, int y)
+{
+ wimp_window_state state;
+ os_error *error;
+ int dx, dy;
+
/* move the window */
state.w = w;
error = xwimp_get_window_state(&state);
@@ -511,10 +516,10 @@ void ro_gui_dialog_open_at_pointer(wimp_w w)
}
dx = (state.visible.x1 - state.visible.x0);
dy = (state.visible.y1 - state.visible.y0);
- state.visible.x0 = ptr.pos.x - 64;
- state.visible.x1 = ptr.pos.x - 64 + dx;
- state.visible.y0 = ptr.pos.y - dy;
- state.visible.y1 = ptr.pos.y;
+ state.visible.x0 = x;
+ state.visible.x1 = x + dx;
+ state.visible.y0 = y - dy;
+ state.visible.y1 = y;
/* if the window is already open, close it first so that it opens fully
* on screen */
@@ -598,7 +603,7 @@ void ro_gui_dialog_open_centre_parent(wimp_w parent, wimp_w child) {
void ro_gui_dialog_open_persistent(wimp_w parent, wimp_w w, bool pointer) {
if (pointer)
- ro_gui_dialog_open_at_pointer(w);
+ ro_gui_dialog_open_at_pointer(w);
else
ro_gui_dialog_open_centre_parent(parent, w);
@@ -608,7 +613,6 @@ void ro_gui_dialog_open_persistent(wimp_w parent, wimp_w w, bool pointer) {
wimp_WINDOW_CLOSE_ICON);
ro_gui_dialog_add_persistent(parent, w);
ro_gui_set_caret_first(w);
-
}
@@ -650,8 +654,8 @@ void ro_gui_dialog_close_persistent(wimp_w parent) {
for (i = 0; i < MAX_PERSISTENT; i++) {
if (persistent_dialog[i].parent == parent &&
persistent_dialog[i].dialog != NULL) {
- if (!ro_gui_wimp_event_close_window(persistent_dialog[i].dialog))
- ro_gui_dialog_close(persistent_dialog[i].dialog);
+ ro_gui_dialog_close(persistent_dialog[i].dialog);
+ ro_gui_wimp_event_close_window(persistent_dialog[i].dialog);
persistent_dialog[i].parent = NULL;
persistent_dialog[i].dialog = NULL;
}
diff --git a/riscos/dialog.h b/riscos/dialog.h
index 63a53d68c..29c2e5024 100644
--- a/riscos/dialog.h
+++ b/riscos/dialog.h
@@ -35,6 +35,7 @@ void ro_gui_dialog_close(wimp_w close);
bool ro_gui_dialog_open_top(wimp_w w, struct toolbar *toolbar,
int width, int height);
void ro_gui_dialog_open_at_pointer(wimp_w w);
+void ro_gui_dialog_open_xy(wimp_w, int x, int y);
void ro_gui_dialog_open_centre_parent(wimp_w parent, wimp_w w);
void ro_gui_dialog_open_persistent(wimp_w parent, wimp_w w, bool pointer);
diff --git a/riscos/download.c b/riscos/download.c
index c18c487a7..55496451f 100644
--- a/riscos/download.c
+++ b/riscos/download.c
@@ -125,6 +125,9 @@ static int download_progress_x0;
static int download_progress_y0;
static int download_progress_y1;
+/** Current download directory. */
+static char *download_dir = NULL;
+static size_t download_dir_len;
static const char *ro_gui_download_temp_name(struct gui_download_window *dw);
@@ -136,6 +139,7 @@ static bool ro_gui_download_check_space(struct gui_download_window *dw,
const char *dest_file, const char *orig_file);
static os_error *ro_gui_download_move(struct gui_download_window *dw,
const char *dest_file, const char *src_file);
+static void ro_gui_download_remember_dir(const char *path);
static bool ro_gui_download_save(struct gui_download_window *dw,
const char *file_name, bool force_overwrite);
static void ro_gui_download_send_dataload(struct gui_download_window *dw);
@@ -221,6 +225,7 @@ struct gui_download_window *gui_download_window_create(const char *url,
url_func_result res;
char *local_path;
utf8_convert_ret err;
+ size_t leaf_ofst;
size_t i;
dw = malloc(sizeof *dw);
@@ -329,20 +334,36 @@ struct gui_download_window *gui_download_window_create(const char *url,
download_template->icons[ICON_DOWNLOAD_ICON].data.indirected_sprite.id =
(osspriteop_id) dw->sprite_name;
+ if (download_dir) {
+ memcpy(dw->path, download_dir, download_dir_len);
+ dw->path[download_dir_len] = '.';
+ leaf_ofst = download_dir_len + 1;
+ }
+ else
+ leaf_ofst = 0;
+
if ((res = url_nice(url, &nice, option_strip_extensions)) ==
URL_FUNC_OK) {
- for (i = 0; nice[i]; i++) {
+ int imax = sizeof dw->path - (leaf_ofst + 1);
+ for (i = 0; i < imax && nice[i]; i++) {
if (nice[i] == '.')
nice[i] = '/';
else if (nice[i] <= ' ' ||
strchr(":*#$&@^%\\", nice[i]))
nice[i] = '_';
}
- strncpy(dw->path, nice, sizeof dw->path);
+ memcpy(dw->path + leaf_ofst, nice, i);
+ dw->path[leaf_ofst + i] = '\0';
free(nice);
}
- else
- strcpy(dw->path, messages_get("SaveObject"));
+ else {
+ const char *leaf = messages_get("SaveObject");
+ size_t len = strlen(leaf);
+ if (len >= sizeof dw->path - leaf_ofst)
+ len = sizeof dw->path - leaf_ofst - 1;
+ memcpy(dw->path + leaf_ofst, leaf, len);
+ dw->path[leaf_ofst + len] = '\0';
+ }
err = utf8_to_local_encoding(dw->path, 0, &local_path);
if (err != UTF8_CONVERT_OK) {
@@ -772,9 +793,21 @@ bool ro_gui_download_click(wimp_pointer *pointer)
if (pointer->i == ICON_DOWNLOAD_ICON && !dw->error &&
!dw->saved) {
const char *sprite = ro_gui_get_icon_string(pointer->w, pointer->i);
+ int x = pointer->pos.x, y = pointer->pos.y;
+ wimp_window_state wstate;
+ wimp_icon_state istate;
+ /* start the drag from the icon's exact location, rather than the pointer */
+ istate.w = wstate.w = pointer->w;
+ istate.i = pointer->i;
+ if (!xwimp_get_window_state(&wstate) && !xwimp_get_icon_state(&istate)) {
+ x = (istate.icon.extent.x1 + istate.icon.extent.x0)/2 +
+ wstate.visible.x0 - wstate.xscroll;
+ y = (istate.icon.extent.y1 + istate.icon.extent.y0)/2 +
+ wstate.visible.y1 - wstate.yscroll;
+ }
gui_current_drag_type = GUI_DRAG_DOWNLOAD_SAVE;
download_window_current = dw;
- ro_gui_drag_icon(pointer->pos.x, pointer->pos.y, sprite);
+ ro_gui_drag_icon(x, y, sprite);
} else if (pointer->i == ICON_DOWNLOAD_DESTINATION) {
strncpy(command + 14, dw->path, 242);
@@ -1153,6 +1186,34 @@ os_error *ro_gui_download_move(struct gui_download_window *dw,
/**
+ * Remember the directory containing the given file,
+ * for use in further downloads.
+ *
+ * \param path pathname of downloaded file
+ * \return none
+ */
+
+void ro_gui_download_remember_dir(const char *path)
+{
+ char *lastdot = NULL;
+ char *p = path;
+ while (*p >= 0x20) {
+ if (*p == '.') lastdot = p;
+ p++;
+ }
+ if (lastdot) {
+ /* remember the directory */
+ char *new_dir = realloc(download_dir, (lastdot+1)-path);
+ if (new_dir) {
+ download_dir_len = lastdot - path;
+ memcpy(new_dir, path, download_dir_len);
+ new_dir[download_dir_len] = '\0';
+ download_dir = new_dir;
+ }
+ }
+}
+
+/**
* Start of save operation, user has specified where the file should be saved.
*
* \param dw download window
@@ -1174,7 +1235,7 @@ bool ro_gui_download_save(struct gui_download_window *dw,
temp_name = ro_gui_download_temp_name(dw);
/* does the user want to check for collisions when saving? */
- if (true && !force_overwrite) {
+ if (!force_overwrite) {
/* check whether the destination file/dir already exists */
error = xosfile_read_stamped(file_name, &obj_type,
NULL, NULL, NULL, NULL, NULL);
@@ -1236,6 +1297,8 @@ bool ro_gui_download_save(struct gui_download_window *dw,
dw->saved = true;
strncpy(dw->path, file_name, sizeof dw->path);
+ ro_gui_download_remember_dir(file_name);
+
/* grey out file icon */
error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_ICON,
wimp_ICON_SHADED, wimp_ICON_SHADED);
diff --git a/riscos/gui.c b/riscos/gui.c
index 2f01f7881..348db5d0e 100644
--- a/riscos/gui.c
+++ b/riscos/gui.c
@@ -1292,10 +1292,17 @@ void ro_gui_drag_end(wimp_dragged *drag)
void ro_gui_keypress(wimp_key *key)
{
- os_error *error;
+ if (key->c == wimp_KEY_ESCAPE &&
+ (gui_current_drag_type == GUI_DRAG_SAVE ||
+ gui_current_drag_type == GUI_DRAG_DOWNLOAD_SAVE)) {
- if (!ro_gui_wimp_event_keypress(key)) {
- error = xwimp_process_key(key->c);
+ /* Allow Escape key to be used for cancelling a drag save
+ (easier than finding somewhere safe to abort the drag) */
+ ro_gui_drag_box_cancel();
+ gui_current_drag_type = GUI_DRAG_NONE;
+ }
+ else if (!ro_gui_wimp_event_keypress(key)) {
+ os_error *error = xwimp_process_key(key->c);
if (error) {
LOG(("xwimp_process_key: 0x%x: %s",
error->errnum, error->errmess));
diff --git a/riscos/query.c b/riscos/query.c
index afab8b185..3cf18ac63 100644
--- a/riscos/query.c
+++ b/riscos/query.c
@@ -94,7 +94,9 @@ struct gui_query_window *ro_gui_query_window_lookup_id(query_id id)
/**
- * Display a query to the user, requesting a response.
+ * Display a query to the user, requesting a response, near the current
+ * pointer position to keep the required mouse travel small, but also
+ * protecting against spurious mouse clicks.
*
* \param query message token of query
* \param detail parameter used in expanding tokenised message
@@ -109,13 +111,44 @@ query_id query_user(const char *query, const char *detail,
const query_callback *cb, void *pw,
const char *yes, const char *no)
{
+ wimp_pointer pointer;
+ if (xwimp_get_pointer_info(&pointer))
+ pointer.pos.y = pointer.pos.x = -1;
+
+ return query_user_xy(query, detail, cb, pw, yes, no,
+ pointer.pos.x, pointer.pos.y);
+}
+
+
+/**
+ * Display a query to the user, requesting a response, at a specified
+ * screen position (x,y). The window is positioned relative to the given
+ * location such that the required mouse travel is small, but non-zero
+ * for protection spurious double-clicks.
+ *
+ * \param query message token of query
+ * \param detail parameter used in expanding tokenised message
+ * \param cb table of callback functions to be called when user responds
+ * \param pw handle to be passed to callback functions
+ * \param yes text to use for 'Yes' button' (or NULL for default)
+ * \param no text to use for 'No' button (or NULL for default)
+ * \param x x position in screen coordinates (-1 = centred on screen)
+ * \param y y position in screen coordinates (-1 = centred on screen)
+ * \return id number of the query (or QUERY_INVALID if it failed)
+ */
+
+query_id query_user_xy(const char *query, const char *detail,
+ const query_callback *cb, void *pw,
+ const char *yes, const char *no,
+ int x, int y)
+{
struct gui_query_window *qw;
char query_buffer[300];
os_error *error;
wimp_icon *icn;
int width;
int len;
- int x;
+ int tx;
char *local_text = NULL;
utf8_convert_ret err;
@@ -164,7 +197,7 @@ query_id query_user(const char *query, const char *detail,
width += 44;
if (width < query_yes_width)
width = query_yes_width;
- icn->extent.x0 = x = icn->extent.x1 - width;
+ icn->extent.x0 = tx = icn->extent.x1 - width;
/* set the text of the 'No' button and size accordingly */
err = utf8_to_local_encoding(no, 0, &local_text);
@@ -185,7 +218,7 @@ query_id query_user(const char *query, const char *detail,
local_text = NULL;
if (!query_no_width) query_no_width = icn->extent.x1 - icn->extent.x0;
- icn->extent.x1 = x - 16;
+ icn->extent.x1 = tx - 16;
error = xwimptextop_string_width(icn->data.indirected_text.text, len, &width);
if (error) {
LOG(("xwimptextop_string_width: 0x%x:%s",
@@ -214,7 +247,13 @@ query_id query_user(const char *query, const char *detail,
xwimp_set_icon_state(qw->window, ICON_QUERY_HELP,
wimp_ICON_DELETED, wimp_ICON_DELETED);
- ro_gui_dialog_open(qw->window);
+ if (x >= 0 && y >= 0) {
+ x -= tx - 8;
+ y += (query_template->visible.y1 - query_template->visible.y0) / 2;
+ ro_gui_dialog_open_xy(qw->window, x, y);
+ }
+ else
+ ro_gui_dialog_open(qw->window);
ro_gui_wimp_event_set_user_data(qw->window, qw);
ro_gui_wimp_event_register_mouse_click(qw->window, ro_gui_query_click);
diff --git a/riscos/query.h b/riscos/query.h
index 7105bef8e..92e3e292e 100644
--- a/riscos/query.h
+++ b/riscos/query.h
@@ -23,6 +23,9 @@
#include "oslib/wimp.h"
#include "utils/utils.h"
+query_id query_user_xy(const char *query, const char *detail,
+ const query_callback *cb, void *pw, const char *yes, const char *no,
+ int x, int y);
void ro_gui_query_init(void);
void ro_gui_query_window_bring_to_front(query_id id);
diff --git a/riscos/save.c b/riscos/save.c
index 37818590d..b866097d7 100644
--- a/riscos/save.c
+++ b/riscos/save.c
@@ -46,6 +46,7 @@
#include "riscos/menus.h"
#include "riscos/message.h"
#include "riscos/options.h"
+#include "riscos/query.h"
#include "riscos/save.h"
#include "riscos/save_complete.h"
#include "riscos/save_draw.h"
@@ -61,11 +62,25 @@
#include "utils/utf8.h"
#include "utils/utils.h"
+//typedef enum
+//{
+// QueryRsn_Quit,
+// QueryRsn_Abort,
+// QueryRsn_Overwrite
+//} query_reason;
+
+
+/**todo - much of the state information for a save should probably be moved into a structure
+ now since we could have multiple saves outstanding */
static gui_save_type gui_save_current_type;
static struct content *gui_save_content = NULL;
static struct selection *gui_save_selection = NULL;
static int gui_save_filetype;
+static query_id gui_save_query;
+static bool gui_save_send_dataload;
+static wimp_message gui_save_message;
+static bool gui_save_close_after = true;
static bool dragbox_active = false; /** in-progress Wimp_DragBox/DragASprite op */
static bool using_dragasprite = true;
@@ -75,16 +90,29 @@ static wimp_w gui_save_sourcew = (wimp_w)-1;
#define LEAFNAME_MAX 200
static char save_leafname[LEAFNAME_MAX];
+/** Current save directory (updated by and used for dialog-based saving) */
+static char *save_dir = NULL;
+static size_t save_dir_len;
+
typedef enum { LINK_ACORN, LINK_ANT, LINK_TEXT } link_format;
static bool ro_gui_save_complete(struct content *c, char *path);
-static bool ro_gui_save_content(struct content *c, char *path);
+static bool ro_gui_save_content(struct content *c, char *path, bool force_overwrite);
+static void ro_gui_save_done(void);
static void ro_gui_save_bounced(wimp_message *message);
static void ro_gui_save_object_native(struct content *c, char *path);
static bool ro_gui_save_link(struct content *c, link_format format, char *path);
static void ro_gui_save_set_state(struct content *c, gui_save_type save_type,
char *leaf_buf, char *icon_buf);
static bool ro_gui_save_create_thumbnail(struct content *c, const char *name);
+static void ro_gui_save_overwrite_confirmed(query_id, enum query_response res, void *p);
+static void ro_gui_save_overwrite_cancelled(query_id, enum query_response res, void *p);
+
+static const query_callback overwrite_funcs =
+{
+ ro_gui_save_overwrite_confirmed,
+ ro_gui_save_overwrite_cancelled
+};
/** An entry in gui_save_table. */
@@ -180,7 +208,7 @@ wimp_w ro_gui_saveas_create(const char *template_name)
/**
- * Clean-up function that releases our sprite area.
+ * Clean-up function that releases our sprite area and memory.
*/
void ro_gui_saveas_quit(void)
@@ -193,6 +221,9 @@ void ro_gui_saveas_quit(void)
}
saveas_area = NULL;
}
+
+ free(save_dir);
+ save_dir = NULL;
}
/**
@@ -209,7 +240,8 @@ void ro_gui_saveas_quit(void)
void ro_gui_save_prepare(gui_save_type save_type, struct content *c)
{
- char name_buf[LEAFNAME_MAX];
+ char name_buf[FILENAME_MAX];
+ size_t leaf_offset = 0;
char icon_buf[20];
assert((save_type == GUI_SAVE_HOTLIST_EXPORT_HTML) ||
@@ -218,7 +250,13 @@ void ro_gui_save_prepare(gui_save_type save_type, struct content *c)
gui_save_current_type = save_type;
gui_save_content = c;
- ro_gui_save_set_state(c, save_type, name_buf, icon_buf);
+ if (save_dir) {
+ leaf_offset = save_dir_len;
+ memcpy(name_buf, save_dir, leaf_offset);
+ name_buf[leaf_offset++] = '.';
+ }
+
+ ro_gui_save_set_state(c, save_type, name_buf + leaf_offset, icon_buf);
ro_gui_set_icon_sprite(dialog_saveas, ICON_SAVE_ICON, saveas_area,
icon_buf);
@@ -234,12 +272,25 @@ void ro_gui_save_prepare(gui_save_type save_type, struct content *c)
*/
void ro_gui_save_start_drag(wimp_pointer *pointer)
{
- if (pointer->buttons == wimp_DRAG_SELECT) {
+ if (pointer->buttons & (wimp_DRAG_SELECT | wimp_DRAG_ADJUST)) {
const char *sprite = ro_gui_get_icon_string(pointer->w, pointer->i);
+ int x = pointer->pos.x, y = pointer->pos.y;
+ wimp_window_state wstate;
+ wimp_icon_state istate;
+ /* start the drag from the icon's exact location, rather than the pointer */
+ istate.w = wstate.w = pointer->w;
+ istate.i = pointer->i;
+ if (!xwimp_get_window_state(&wstate) && !xwimp_get_icon_state(&istate)) {
+ x = (istate.icon.extent.x1 + istate.icon.extent.x0)/2 +
+ wstate.visible.x0 - wstate.xscroll;
+ y = (istate.icon.extent.y1 + istate.icon.extent.y0)/2 +
+ wstate.visible.y1 - wstate.yscroll;
+ }
gui_current_drag_type = GUI_DRAG_SAVE;
gui_save_sourcew = pointer->w;
saving_from_dialog = true;
- ro_gui_drag_icon(pointer->pos.x, pointer->pos.y, sprite);
+ gui_save_close_after = !(pointer->buttons & wimp_DRAG_ADJUST);
+ ro_gui_drag_icon(x, y, sprite);
}
}
@@ -253,6 +304,7 @@ void ro_gui_save_start_drag(wimp_pointer *pointer)
bool ro_gui_save_ok(wimp_w w)
{
const char *name = ro_gui_get_icon_string(w, ICON_SAVE_PATH);
+ wimp_pointer pointer;
char path[256];
if (!strrchr(name, '.')) {
@@ -263,7 +315,14 @@ bool ro_gui_save_ok(wimp_w w)
ro_gui_convert_save_path(path, sizeof path, name);
gui_save_sourcew = w;
saving_from_dialog = true;
- return ro_gui_save_content(gui_save_content, path);
+ gui_save_close_after = xwimp_get_pointer_info(&pointer)
+ || !(pointer.buttons & wimp_CLICK_ADJUST);
+ if (!ro_gui_save_content(gui_save_content, path, !option_confirm_overwrite)) {
+ memcpy(&gui_save_message.data.data_xfer.file_name, path, 1 + strlen(path));
+ gui_save_send_dataload = false;
+ return false;
+ }
+ return true;
}
@@ -626,13 +685,15 @@ void ro_gui_save_bounced(wimp_message *message)
/**
- * Handle Message_DataSaveAck for a drag from the save dialog or browser window.
+ * Handle Message_DataSaveAck for a drag from the save dialog or browser window,
+ * or Clipboard protocol.
*/
void ro_gui_save_datasave_ack(wimp_message *message)
{
char *path = message->data.data_xfer.file_name;
struct content *c = gui_save_content;
+ bool force_overwrite;
switch (gui_save_current_type) {
case GUI_SAVE_HOTLIST_EXPORT_HTML:
@@ -653,31 +714,18 @@ void ro_gui_save_datasave_ack(wimp_message *message)
ro_gui_set_icon_string(gui_save_sourcew, ICON_SAVE_PATH,
path, true);
- if (ro_gui_save_content(c, path)) {
- os_error *error;
-
- /* Ack successful save with message_DATA_LOAD */
- message->action = message_DATA_LOAD;
- message->your_ref = message->my_ref;
- error = xwimp_send_message(wimp_USER_MESSAGE, message,
- message->sender);
- if (error) {
- LOG(("xwimp_send_message: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("SaveError", error->errmess);
- }
+ gui_save_send_dataload = true;
+ memcpy(&gui_save_message, message, sizeof(gui_save_message));
- /* Close the save window */
- ro_gui_dialog_close(dialog_saveas);
- error = xwimp_create_menu(wimp_CLOSE_MENU, 0, 0);
- if (error) {
- LOG(("xwimp_create_menu: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("MenuError", error->errmess);
- }
+ /* if saving/pasting to another application, don't request user
+ confirmation; a ScrapFile almost certainly exists already */
+ if (message->data.data_xfer.est_size == -1)
+ force_overwrite = true;
+ else
+ force_overwrite = !option_confirm_overwrite;
- gui_save_content = 0;
- }
+ if (ro_gui_save_content(c, path, force_overwrite))
+ ro_gui_save_done();
}
@@ -685,15 +733,48 @@ void ro_gui_save_datasave_ack(wimp_message *message)
/**
* Does the actual saving
*
- * \param c content to save (or NULL for other)
- * \param path path to save as
- * \return true on success, false on error and error reported
+ * \param c content to save (or NULL for other)
+ * \param path path to save as
+ * \param force_overwrite true iff required to overwrite without prompting
+ * \return true on success,
+ * false on (i) error and error reported
+ * or (ii) deferred awaiting user confirmation
*/
-bool ro_gui_save_content(struct content *c, char *path)
+bool ro_gui_save_content(struct content *c, char *path, bool force_overwrite)
{
os_error *error;
+ /* does the user want to check for collisions when saving? */
+ if (!force_overwrite) {
+ fileswitch_object_type obj_type;
+ /* check whether the destination file/dir already exists */
+ error = xosfile_read_stamped(path, &obj_type,
+ NULL, NULL, NULL, NULL, NULL);
+ if (error) {
+ LOG(("xosfile_read_stamped: 0x%x:%s", error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ return false;
+ }
+
+ switch (obj_type) {
+ case osfile_NOT_FOUND:
+ break;
+
+ case osfile_IS_FILE:
+ gui_save_query = query_user("OverwriteFile", NULL, &overwrite_funcs, NULL,
+ messages_get("Replace"), messages_get("DontReplace"));
+// gui_save_query_rsn = QueryRsn_Overwrite;
+ return false;
+
+ default:
+ error = xosfile_make_error(path, obj_type);
+ assert(error);
+ warn_user("SaveError", error->errmess);
+ return false;
+ }
+ }
+
switch (gui_save_current_type) {
#ifdef WITH_DRAW_EXPORT
case GUI_SAVE_DRAW:
@@ -784,6 +865,67 @@ bool ro_gui_save_content(struct content *c, char *path)
/**
+ * Save completed, inform recipient and close our 'save as' dialog.
+ */
+
+void ro_gui_save_done(void)
+{
+ os_error *error;
+
+ if (gui_save_send_dataload) {
+ /* Ack successful save with message_DATA_LOAD */
+ wimp_message *message = &gui_save_message;
+ message->action = message_DATA_LOAD;
+ message->your_ref = message->my_ref;
+ error = xwimp_send_message(wimp_USER_MESSAGE, message,
+ message->sender);
+ if (error) {
+ LOG(("xwimp_send_message: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ }
+ }
+
+ if (saving_from_dialog) {
+ /* */
+ char *sp = gui_save_message.data.data_xfer.file_name;
+ char *ep = sp + sizeof(gui_save_message.data.data_xfer.file_name);
+ char *lastdot = NULL;
+ char *p = sp;
+
+ while (p < ep && *p >= 0x20) {
+ if (*p == '.') lastdot = p;
+ p++;
+ }
+ if (lastdot) {
+ /* remember the directory */
+ char *new_dir = realloc(save_dir, (lastdot+1)-sp);
+ if (new_dir) {
+ save_dir_len = lastdot - sp;
+ memcpy(new_dir, sp, save_dir_len);
+ new_dir[save_dir_len] = '\0';
+ save_dir = new_dir;
+ }
+ }
+
+ if (gui_save_close_after) {
+ /* Close the save window */
+ ro_gui_dialog_close(dialog_saveas);
+ error = xwimp_create_menu(wimp_CLOSE_MENU, 0, 0);
+ if (error) {
+ LOG(("xwimp_create_menu: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("MenuError", error->errmess);
+ }
+ }
+ }
+
+ if (!saving_from_dialog || gui_save_close_after)
+ gui_save_content = 0;
+}
+
+
+/**
* Prepare an application directory and save_complete() to it.
*
* \param c content of type CONTENT_HTML to save
@@ -808,7 +950,7 @@ bool ro_gui_save_complete(struct content *c, char *path)
char *dot;
int i;
- /* Create dir */
+ /* Create dir */
error = xosfile_create_dir(path, 0);
if (error) {
LOG(("xosfile_create_dir: 0x%x: %s",
@@ -817,7 +959,7 @@ bool ro_gui_save_complete(struct content *c, char *path)
return false;
}
- /* Save !Run file */
+ /* Save !Run file */
snprintf(buf, sizeof buf, "%s.!Run", path);
fp = fopen(buf, "w");
if (!fp) {
@@ -850,8 +992,8 @@ bool ro_gui_save_complete(struct content *c, char *path)
memcpy(sprite->name, dot, len);
memset(sprite->name + len, 0, 12 - len);
for (i = 0; i < 12; i++) /* convert to lower case */
- if (sprite->name[i] != '\0')
- sprite->name[i] = tolower(sprite->name[i]);
+ if (sprite->name[i] != '\0')
+ sprite->name[i] = tolower(sprite->name[i]);
/* Create !Sprites */
snprintf(buf, sizeof buf, "%s.!Sprites", path);
@@ -1140,3 +1282,27 @@ bool ro_gui_save_create_thumbnail(struct content *c, const char *name)
return true;
}
+
+
+/**
+ * User has opted not to overwrite the existing file.
+ */
+
+void ro_gui_save_overwrite_cancelled(query_id id, enum query_response res, void *p)
+{
+ if (!saving_from_dialog) {
+// ro_gui_save_prepare(gui_save_current_type, gui_save_content);
+// ro_gui_dialog_open_persistent(g->window, dialog_saveas, true);
+ }
+}
+
+
+/**
+ * Overwrite of existing file confirmed, proceed with the save.
+ */
+
+void ro_gui_save_overwrite_confirmed(query_id id, enum query_response res, void *p)
+{
+ if (ro_gui_save_content(gui_save_content, gui_save_message.data.data_xfer.file_name, true))
+ ro_gui_save_done();
+}