Skip to content

Commit

Permalink
Let the UI ask "Yes/No/Always/Never" questions, and use it to stop na…
Browse files Browse the repository at this point in the history
…gging

 about overwriting every file.
  • Loading branch information
icculus committed May 17, 2007
1 parent e9b7209 commit 8d071ac
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 9 deletions.
7 changes: 7 additions & 0 deletions docs.txt
Expand Up @@ -747,6 +747,13 @@ Your config file is a Lua script, and as such, has access to all of Lua's
if they clicked "NO".


MojoSetup.promptynan(str)

Show (str) to the user with a GUI message box, and wait until they click
either a "YES", "NO", "ALWAYS" or "NEVER" button. Returns the string
"yes", "no", "always", or "never".


MojoSetup.stackwalk()

This writes a backtrace of the current Lua callstack to the installation
Expand Down
15 changes: 15 additions & 0 deletions gui.h
Expand Up @@ -26,6 +26,16 @@ typedef enum
} MojoGuiPluginPriority;


typedef enum
{
MOJOGUI_NO,
MOJOGUI_YES,
MOJOGUI_ALWAYS,
MOJOGUI_NEVER
} MojoGuiYNAN;



/*
* Abstract GUI interfaces.
*/
Expand All @@ -43,6 +53,7 @@ struct MojoGuiSetupOptions
MojoGuiSetupOptions *child;
};


#define MOJOGUI_ENTRY_POINT MojoSetup_Gui_GetInterface
#define MOJOGUI_ENTRY_POINT_STR DEFINE_TO_STR(MOJOGUI_ENTRY_POINT)

Expand All @@ -58,6 +69,7 @@ struct MojoGui
void (*deinit)(void);
void (*msgbox)(const char *title, const char *text);
boolean (*promptyn)(const char *title, const char *text);
MojoGuiYNAN (*promptynan)(const char *title, const char *text);
boolean (*start)(const char *title, const char *splash);
void (*stop)(void);
int (*readme)(const char *name, const uint8 *data, size_t len,
Expand Down Expand Up @@ -97,6 +109,8 @@ static boolean MojoGui_##module##_init(void); \
static void MojoGui_##module##_deinit(void); \
static void MojoGui_##module##_msgbox(const char *title, const char *text); \
static boolean MojoGui_##module##_promptyn(const char *t1, const char *t2); \
static MojoGuiYNAN MojoGui_##module##_promptynan(const char *t1, \
const char *t2); \
static boolean MojoGui_##module##_start(const char *t, const char *s); \
static void MojoGui_##module##_stop(void); \
static int MojoGui_##module##_readme(const char *name, const uint8 *data, \
Expand All @@ -120,6 +134,7 @@ const MojoGui *MojoGuiPlugin_##module(int rev, const MojoSetupEntryPoints *e) \
MojoGui_##module##_deinit, \
MojoGui_##module##_msgbox, \
MojoGui_##module##_promptyn, \
MojoGui_##module##_promptynan, \
MojoGui_##module##_start, \
MojoGui_##module##_stop, \
MojoGui_##module##_readme, \
Expand Down
50 changes: 46 additions & 4 deletions gui_gtkplus2.c
Expand Up @@ -183,7 +183,8 @@ static void MojoGui_gtkplus2_deinit(void)


static gint do_msgbox(const char *title, const char *text,
GtkMessageType mtype, GtkButtonsType btype)
GtkMessageType mtype, GtkButtonsType btype,
void (*addButtonCallback)(GtkWidget *_msgbox))
{
gint retval = 0;
if (msgbox != NULL)
Expand All @@ -192,6 +193,10 @@ static gint do_msgbox(const char *title, const char *text,
mtype, btype, "%s", title);
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msgbox),
"%s", text);

if (addButtonCallback != NULL)
addButtonCallback(msgbox);

retval = gtk_dialog_run(GTK_DIALOG(msgbox));
gtk_widget_destroy(msgbox);
msgbox = NULL;
Expand All @@ -201,17 +206,52 @@ static gint do_msgbox(const char *title, const char *text,

static void MojoGui_gtkplus2_msgbox(const char *title, const char *text)
{
do_msgbox(title, text, GTK_MESSAGE_INFO, GTK_BUTTONS_OK);
do_msgbox(title, text, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, NULL);
} // MojoGui_gtkplus2_msgbox


static boolean MojoGui_gtkplus2_promptyn(const char *title, const char *text)
{
gint rc = do_msgbox(title, text, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO);
gint rc = do_msgbox(title, text, GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO, NULL);
return (rc == GTK_RESPONSE_YES);
} // MojoGui_gtkplus2_promptyn


static void promptynanButtonCallback(GtkWidget *_msgbox)
{
char *always = entry->xstrdup(entry->_("Always"));
char *never = entry->xstrdup(entry->_("Never"));
gtk_dialog_add_buttons(GTK_DIALOG(_msgbox),
GTK_STOCK_YES, GTK_RESPONSE_YES,
GTK_STOCK_NO, GTK_RESPONSE_NO,
always, 1,
never, 0,
NULL, GTK_RESPONSE_NONE);

free(always);
free(never);
} // promptynanButtonCallback


static MojoGuiYNAN MojoGui_gtkplus2_promptynan(const char *title,
const char *text)
{
MojoGuiYNAN retval;
const gint rc = do_msgbox(title, text, GTK_MESSAGE_QUESTION,
GTK_BUTTONS_NONE, promptynanButtonCallback);
switch (rc)
{
case GTK_RESPONSE_YES: return MOJOGUI_YES;
case GTK_RESPONSE_NO: return MOJOGUI_NO;
case GTK_RESPONSE_ALWAYS: return MOJOGUI_ALWAYS;
case GTK_RESPONSE_NEVER: return MOJOGUI_NEVER;
} // switch

return MOJOGUI_NO; // just in case.
} // MojoGui_gtkplus2_promptynan


static GtkWidget *create_button(GtkWidget *box, const char *iconname,
const char *text)
{
Expand Down Expand Up @@ -575,6 +615,7 @@ static char *MojoGui_gtkplus2_destination(const char **recommends, int recnum,

static boolean MojoGui_gtkplus2_insertmedia(const char *medianame)
{
gint rc = 0;
// !!! FIXME: Use stock GTK icon for "media"?
// !!! FIXME: better text.
const char *title = entry->_("Media change");
Expand All @@ -583,7 +624,8 @@ static boolean MojoGui_gtkplus2_insertmedia(const char *medianame)
size_t len = strlen(fmt) + strlen(medianame) + 1;
char *text = (char *) entry->xmalloc(len);
snprintf(text, len, fmt, medianame);
gint rc = do_msgbox(title, text, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL);
rc = do_msgbox(title, text, GTK_MESSAGE_WARNING,
GTK_BUTTONS_OK_CANCEL, NULL);
return (rc == GTK_RESPONSE_OK);
} // MojoGui_gtkplus2_insertmedia

Expand Down
8 changes: 8 additions & 0 deletions gui_macosx.c
Expand Up @@ -131,6 +131,14 @@ static boolean MojoGui_macosx_promptyn(const char *title, const char *text)
} // MojoGui_macosx_promptyn


static MojoGuiYNAN MojoGui_macosx_promptynan(const char *title,
const char *text)
{
STUBBED("ynan");
return MojoGui_macosx_promptyn(title, text); // !!! FIXME
} // MojoGui_macosx_promptynan


static boolean MojoGui_macosx_start(const char *title, const char *splash)
{
return true; // !!! FIXME
Expand Down
45 changes: 45 additions & 0 deletions gui_stdio.c
Expand Up @@ -130,6 +130,51 @@ static boolean MojoGui_stdio_promptyn(const char *title, const char *text)
} // MojoGui_stdio_promptyn


static MojoGuiYNAN MojoGui_stdio_promptynan(const char *title, const char *txt)
{
MojoGuiYNAN retval = MOJOGUI_NO;
if (!feof(stdin))
{
const char *localized_no = entry->xstrdup(entry->_("N"));
const char *localized_yes = entry->xstrdup(entry->_("Y"));
const char *localized_always = entry->xstrdup(entry->_("Always"));
const char *localized_never = entry->xstrdup(entry->_("Never"));
boolean getout = false;
char buf[128];
while (!getout)
{
printf(entry->_("%s\n[y/n/Always/Never]: "), txt);
fflush(stdout);
if (read_stdin(buf, sizeof (buf)) < 0)
getout = true;
else if (strcasecmp(buf, localized_no) == 0)
getout = true;
else if (strcasecmp(buf, localized_yes) == 0)
{
retval = MOJOGUI_YES;
getout = true;
} // else if
else if (strcasecmp(buf, localized_always) == 0)
{
retval = MOJOGUI_ALWAYS;
getout = true;
} // else if
else if (strcasecmp(buf, localized_never) == 0)
{
retval = MOJOGUI_NEVER;
getout = true;
} // else if
} // while
free((void *) localized_no);
free((void *) localized_yes);
free((void *) localized_always);
free((void *) localized_never);
} // if

return retval;
} // MojoGui_stdio_promptynan


static boolean MojoGui_stdio_start(const char *title, const char *splash)
{
printf("%s\n", title);
Expand Down
25 changes: 25 additions & 0 deletions lua_glue.c
Expand Up @@ -520,6 +520,30 @@ static int luahook_promptyn(lua_State *L)
} // luahook_promptyn


static int luahook_promptynan(lua_State *L)
{
MojoGuiYNAN rc = MOJOGUI_NO;
if (GGui != NULL)
{
const char *title = luaL_checkstring(L, 1);
const char *text = luaL_checkstring(L, 2);
rc = GGui->promptynan(title, text);
} // if

// Never localize these strings!
switch (rc)
{
case MOJOGUI_YES: return retvalString(L, "yes");
case MOJOGUI_NO: return retvalString(L, "no");
case MOJOGUI_ALWAYS: return retvalString(L, "always");
case MOJOGUI_NEVER: return retvalString(L, "never");
} // switch

assert(false && "BUG: unhandled case in switch statement");
return 0; // shouldn't hit this.
} // luahook_promptynan


static int luahook_logwarning(lua_State *L)
{
logWarning(luaL_checkstring(L, 1));
Expand Down Expand Up @@ -1289,6 +1313,7 @@ boolean MojoLua_initLua(void)
set_cfunc(luaState, luahook_fatal, "fatal");
set_cfunc(luaState, luahook_msgbox, "msgbox");
set_cfunc(luaState, luahook_promptyn, "promptyn");
set_cfunc(luaState, luahook_promptynan, "promptynan");
set_cfunc(luaState, luahook_stackwalk, "stackwalk");
set_cfunc(luaState, luahook_logwarning, "logwarning");
set_cfunc(luaState, luahook_logerror, "logerror");
Expand Down
12 changes: 12 additions & 0 deletions scripts/localization.lua
Expand Up @@ -49,6 +49,10 @@ MojoSetup.localization = {
["%s\n[y/n]"] = {
};

-- stdio GUI plugin says this for yes/no/always/never prompts (printf format string).
["%s\n[y/n/Always/Never]: "] = {
};

-- This is utf8casecmp()'d for "yes" answers in stdio GUI's promptyn().
["Y"] = {
};
Expand All @@ -57,6 +61,14 @@ MojoSetup.localization = {
["N"] = {
};

-- This is utf8casecmp()'d for "always" answers in stdio GUI's promptyn().
["Always"] = {
};

-- This is utf8casecmp()'d for "never" answers in stdio GUI's promptyn().
["Never"] = {
};

["Yes"] = {
};

Expand Down
30 changes: 25 additions & 5 deletions scripts/mojosetup_mainline.lua
Expand Up @@ -305,13 +305,31 @@ local function permit_write(dest, entinfo, file)
if entinfo.type == "dir" then
allowoverwrite = false
else
allowoverwrite = file.allowoverwrite
if not allowoverwrite then
-- !!! FIXME: language and formatting.
MojoSetup.loginfo("File '" .. dest .. "' already exists.")
allowoverwrite = MojoSetup.promptyn(_("Conflict!"), _("File already exists! Replace?"))
if MojoSetup.forceoverwrite ~= nil then
allowoverwrite = MojoSetup.forceoverwrite
else
-- !!! FIXME: option/package-wide overwrite?
allowoverwrite = file.allowoverwrite
if not allowoverwrite then
-- !!! FIXME: language and formatting.
MojoSetup.loginfo("File '" .. dest .. "' already exists.")
local ynan = MojoSetup.promptynan(_("Conflict!"), _("File already exists! Replace?"))
if ynan == "always" then
MojoSetup.forceoverwrite = true
allowoverwrite = true
elseif ynan == "never" then
MojoSetup.forceoverwrite = false
allowoverwrite = false
elseif ynan == "yes" then
allowoverwrite = true
elseif ynan == "no" then
allowoverwrite = false
end
end
end

-- !!! FIXME: Setup.File.mustoverwrite to override "never"?

if allowoverwrite then
local id = #MojoSetup.rollbacks + 1
local f = MojoSetup.rollbackdir .. "/" .. id
Expand Down Expand Up @@ -509,6 +527,7 @@ end


local function do_install(install)
MojoSetup.forceoverwrite = nil
MojoSetup.written = 0
MojoSetup.totalwrite = 0
MojoSetup.downloaded = 0
Expand Down Expand Up @@ -910,6 +929,7 @@ local function do_install(install)
MojoSetup.scratchdir = nil
MojoSetup.rollbackdir = nil
MojoSetup.downloaddir = nil
MojoSetup.forceoverwrite = nil
MojoSetup.stages = nil
MojoSetup.files = nil
MojoSetup.media = nil
Expand Down

0 comments on commit 8d071ac

Please sign in to comment.