RetroZilla/toolkit/mozapps/installer/unix/wizard/nsInstallDlg.cpp
2015-10-20 23:03:22 -04:00

1454 lines
41 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Samir Gehani <sgehani@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsSocket.h"
#include "nsHTTPConn.h"
#include "nsInstallDlg.h"
#include "nsXInstaller.h"
#include "nsXIEngine.h"
#include <signal.h>
#include <gtk/gtk.h>
#include <errno.h>
#define NUM_PS_ENTRIES 4
typedef struct _DLProgress
{
// progress widgets
GtkWidget *vbox;
GtkWidget *compName;
GtkWidget *URL;
GtkWidget *localPath;
GtkWidget *status;
GtkWidget *progBar;
// progress info
int downloadedBytes;
int totalKB;
}
DLProgress;
static char *sXPInstallEngine;
static nsRunApp *sRunAppList = NULL;
static DLProgress sDLProgress;
static GtkWidget *sDLTable = NULL;
static GtkWidget *sMsg0Label;
static GtkWidget *sTextBox;
static GtkWidget *sMajorLabel;
static GtkWidget *sMinorLabel;
static GtkWidget *sRateLabel;
static GtkWidget *sMajorProgBar;
static GtkWidget *sMinorProgBar;
static GtkWidget *sPSTextEntry[NUM_PS_ENTRIES];
static int bDownload = FALSE;
static struct timeval sDLStartTime;
static int bDLPause = FALSE;
static int bDLCancel = FALSE;
nsInstallDlg::nsInstallDlg() :
mMsg0(NULL)
{
}
nsInstallDlg::~nsInstallDlg()
{
XI_IF_FREE(mMsg0);
}
void
nsInstallDlg::Back(GtkWidget *aWidget, gpointer aData)
{
DUMP("Back");
if (aData != gCtx->idlg) return;
// hide this notebook page
gCtx->idlg->Hide(nsXInstallerDlg::BACKWARD_MOVE);
// disconnect this dlg's nav btn signal handlers
gtk_signal_disconnect(GTK_OBJECT(gCtx->back), gCtx->backID);
gtk_signal_disconnect(GTK_OBJECT(gCtx->next), gCtx->nextID);
// show the last dlg
if (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1))
gCtx->cdlg->Show(nsXInstallerDlg::BACKWARD_MOVE);
else
gCtx->sdlg->Show(nsXInstallerDlg::BACKWARD_MOVE);
}
void
nsInstallDlg::Next(GtkWidget *aWidget, gpointer aData)
{
DUMP("Next");
int bCus;
nsComponentList *comps = NULL;
if (aData != gCtx->idlg) return;
bCus = (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1));
comps = gCtx->sdlg->GetSelectedSetupType()->GetComponents();
// initialize progress bar cleanly
int totalComps = 0;
if (nsXIEngine::ExistAllXPIs(bCus, comps, &totalComps))
bDownload = FALSE;
else
bDownload = TRUE;
if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT) {
gtk_progress_set_activity_mode(GTK_PROGRESS(sMajorProgBar), FALSE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sMajorProgBar), (gfloat) 0);
gtk_label_set_text(GTK_LABEL(sMajorLabel), "");
if (bDownload)
{
InitDLProgress( TRUE );
gtk_button_set_label(GTK_BUTTON(gCtx->back), gCtx->Res("PAUSE"));
gtk_button_set_label(GTK_BUTTON(gCtx->next), gCtx->Res("RESUME"));
gtk_signal_disconnect(GTK_OBJECT(gCtx->back), gCtx->backID);
gtk_signal_disconnect(GTK_OBJECT(gCtx->next), gCtx->nextID);
gtk_signal_disconnect(GTK_OBJECT(gCtx->cancel), gCtx->cancelID);
// disable resume button
gtk_widget_set_sensitive(gCtx->next, FALSE);
XI_GTK_UPDATE_UI();
// hook up buttons with callbacks
gCtx->backID = gtk_signal_connect(GTK_OBJECT(gCtx->back), "clicked",
GTK_SIGNAL_FUNC(DLPause), NULL);
gCtx->nextID = gtk_signal_connect(GTK_OBJECT(gCtx->next), "clicked",
GTK_SIGNAL_FUNC(DLResume), NULL);
gCtx->cancelID = gtk_signal_connect(GTK_OBJECT(gCtx->cancel), "clicked",
GTK_SIGNAL_FUNC(DLCancel), NULL);
}
else
{
gtk_widget_show(sMajorLabel);
gtk_widget_show(sMajorProgBar);
gtk_widget_set_sensitive(gCtx->back, FALSE);
gtk_widget_set_sensitive(gCtx->next, FALSE);
gtk_widget_set_sensitive(gCtx->cancel, FALSE);
}
gtk_widget_hide(sMsg0Label);
gtk_widget_hide(sTextBox);
if (bDownload && sDLTable)
gtk_widget_hide(sDLTable);
XI_GTK_UPDATE_UI();
}
PerformInstall();
// mode auto has no call to gtk_main()
if (gCtx->opt->mMode == nsXIOptions::MODE_DEFAULT)
gtk_main_quit();
return;
}
int
nsInstallDlg::Parse(nsINIParser *aParser)
{
int err = OK;
int bufsize = 0;
char *showDlg = NULL;
char secName[64];
int i;
char *app = NULL, *args = NULL;
nsRunApp *newRunApp = NULL;
/* compulsory keys */
XI_ERR_BAIL(aParser->GetStringAlloc(DLG_START_INSTALL, XPINSTALL_ENGINE,
&sXPInstallEngine, &bufsize));
if (bufsize == 0 || !sXPInstallEngine)
return E_INVALID_KEY;
/* optional keys */
err = aParser->GetStringAlloc(DLG_START_INSTALL, TITLE, &mTitle, &bufsize);
if (err != OK && err != nsINIParser::E_NO_KEY) goto BAIL; else err = OK;
if (bufsize == 0)
XI_IF_FREE(mTitle);
aParser->GetStringAlloc(DLG_START_INSTALL, SUBTITLE, &mSubTitle, &bufsize);
if (bufsize == 0)
XI_IF_FREE(mSubTitle);
bufsize = 0;
err = aParser->GetStringAlloc(DLG_START_INSTALL, MSG0, &mMsg0, &bufsize);
if (err != OK && err != nsINIParser::E_NO_KEY) goto BAIL; else err = OK;
bufsize = 5;
XI_ERR_BAIL(aParser->GetStringAlloc(DLG_START_INSTALL, SHOW_DLG,
&showDlg, &bufsize));
if (bufsize != 0 && showDlg)
{
if (0 == strncmp(showDlg, "TRUE", 4))
mShowDlg = nsXInstallerDlg::SHOW_DIALOG;
else if (0 == strncmp(showDlg, "FALSE", 5))
mShowDlg = nsXInstallerDlg::SKIP_DIALOG;
}
bufsize = 0;
XI_ERR_BAIL(aParser->GetStringAlloc(DLG_START_INSTALL, TITLE,
&mTitle, &bufsize));
if (bufsize == 0)
XI_IF_FREE(mTitle);
for (i = 0; err == OK; i++)
{
/* construct RunAppX section name */
sprintf(secName, RUNAPPd, i);
err = aParser->GetStringAlloc(secName, TARGET, &app, &bufsize);
if (err == OK && bufsize > 0)
{
/* "args" is optional: this may return E_NO_KEY which we ignore */
err = aParser->GetStringAlloc(secName, ARGS, &args, &bufsize);
newRunApp = new nsRunApp(app, args);
if (!newRunApp)
return E_MEM;
err = AppendRunApp(newRunApp);
}
}
err = OK; /* reset error since RunAppX sections are optional
and we could have gotten a parse error (E_NO_SEC) */
return err;
BAIL:
return err;
}
int
nsInstallDlg::AppendRunApp(nsRunApp *aNewRunApp)
{
int err = OK;
nsRunApp *currRunApp = NULL, *nextRunApp = NULL;
/* param check */
if (!aNewRunApp)
return E_PARAM;
/* special case: list is empty */
if (!sRunAppList)
{
sRunAppList = aNewRunApp;
return OK;
}
/* list has at least one element */
currRunApp = sRunAppList;
while (currRunApp)
{
if (!(nextRunApp = currRunApp->GetNext()))
{
currRunApp->SetNext(aNewRunApp);
break;
}
currRunApp = nextRunApp;
}
return err;
}
void
nsInstallDlg::FreeRunAppList()
{
nsRunApp *currRunApp = NULL, *nextRunApp = NULL;
currRunApp = sRunAppList;
while (currRunApp)
{
nextRunApp = currRunApp->GetNext();
delete currRunApp;
currRunApp = nextRunApp;
}
}
void
nsInstallDlg::RunApps()
{
nsRunApp *currRunApp = sRunAppList;
char *argv[3], *dest;
char apppath[MAXPATHLEN];
extern NS_IMPORT_(char **) environ; /* globally available to all processes */
int pid;
dest = gCtx->opt->mDestination;
if (chdir(dest) < 0)
fprintf(stderr,"chdir(%s): %s\n",dest,strerror(errno));
while (currRunApp)
{
/* run application with supplied args */
if ((pid = fork()) == 0)
{
/* child */
if (*(dest + strlen(dest)) == '/') /* trailing slash */
sprintf(apppath, "%s%s", dest, currRunApp->GetApp());
else /* no trailing slash */
sprintf(apppath, "%s/%s", dest, currRunApp->GetApp());
argv[0] = apppath;
argv[1] = currRunApp->GetArgs();
argv[2] = NULL; /* null-terminate arg vector */
execve(apppath, argv, environ);
/* shouldn't reach this but in case execve fails we will */
exit(0);
}
/* parent continues running to finish installation */
currRunApp = currRunApp->GetNext();
}
}
int
nsInstallDlg::Show(int aDirection)
{
int err = OK;
int totalComps = 0;
GtkWidget *hbox = NULL;
GtkWidget *vbox = NULL;
GtkWidget *dlFrame, *dlCheckbox, *dlProxyBtn;
XI_VERIFY(gCtx);
XI_VERIFY(gCtx->notebook);
if (mWidgetsInit == FALSE)
{
int bCus =
(gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1));
nsComponentList *comps =
gCtx->sdlg->GetSelectedSetupType()->GetComponents();
// create a new table and add it as a page of the notebook
mTable = gtk_table_new(5, 1, FALSE);
gtk_notebook_append_page(GTK_NOTEBOOK(gCtx->notebook), mTable, NULL);
mPageNum = gtk_notebook_get_current_page(GTK_NOTEBOOK(gCtx->notebook));
gtk_widget_show(mTable);
// Show the text:
// Setup will now install the following components:
// [component1]
// [component2]
// to the following location:
// [install path]
//
// Click next to continue.
sTextBox = gtk_vbox_new(FALSE, 6);
gtk_container_set_border_width(GTK_CONTAINER(sTextBox), 12);
gtk_table_attach(GTK_TABLE(mTable), sTextBox, 0, 1, 0, 1,
GtkAttachOptions(GTK_FILL | GTK_EXPAND),
GtkAttachOptions(0), 0, 0);
GtkWidget *msg = gtk_label_new(gCtx->Res("WILL_INSTALL"));
gtk_misc_set_alignment(GTK_MISC(msg), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(sTextBox), msg, FALSE, FALSE, 0);
nsComponent *currComp;
for (currComp = comps->GetHead(); currComp;
currComp = comps->GetNext()) {
if (currComp->IsMainComponent() ||
(!currComp->IsInvisible() && currComp->IsSelected())) {
msg = gtk_label_new(currComp->GetDescShort());
gtk_misc_set_alignment(GTK_MISC(msg), 0.0, 0.5);
gtk_misc_set_padding(GTK_MISC(msg), 20, 0);
gtk_box_pack_start(GTK_BOX(sTextBox), msg, FALSE, FALSE, 0);
}
}
msg = gtk_label_new(gCtx->Res("TO_LOCATION"));
gtk_misc_set_alignment(GTK_MISC(msg), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(sTextBox), msg, FALSE, FALSE, 0);
msg = gtk_label_new(gCtx->opt->mDestination);
gtk_misc_set_alignment(GTK_MISC(msg), 0.0, 0.5);
gtk_misc_set_padding(GTK_MISC(msg), 20, 0);
gtk_box_pack_start(GTK_BOX(sTextBox), msg, FALSE, FALSE, 0);
gtk_widget_show_all(sTextBox);
if (!nsXIEngine::ExistAllXPIs(bCus, comps, &totalComps))
{
// insert a [ x ] heterogenous table
sDLTable = gtk_table_new(2, 2, FALSE);
gtk_widget_show(sDLTable);
gtk_table_attach(GTK_TABLE(mTable), sDLTable, 0, 1, 1, 4,
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
GtkAttachOptions(0), 20, 20);
// download settings groupbox
dlFrame = gtk_frame_new(gCtx->Res("DL_SETTINGS"));
gtk_table_attach_defaults(GTK_TABLE(sDLTable), dlFrame, 0, 2, 0, 2);
gtk_widget_show(dlFrame);
// save installer modules checkbox and label
dlCheckbox = gtk_check_button_new_with_label(
gCtx->Res("SAVE_MODULES"));
gtk_widget_show(dlCheckbox);
gtk_table_attach(GTK_TABLE(sDLTable), dlCheckbox, 0, 2, 0, 1,
GTK_FILL, GTK_FILL, 10, 20);
gtk_signal_connect(GTK_OBJECT(dlCheckbox), "toggled",
GTK_SIGNAL_FUNC(SaveModulesToggled), NULL);
// proxy settings button
dlProxyBtn = gtk_button_new_with_label(gCtx->Res("PROXY_SETTINGS"));
gtk_widget_show(dlProxyBtn);
gtk_table_attach(GTK_TABLE(sDLTable), dlProxyBtn, 0, 1, 1, 2,
GTK_FILL, GTK_FILL, 10, 10);
gtk_signal_connect(GTK_OBJECT(dlProxyBtn), "clicked",
GTK_SIGNAL_FUNC(ShowProxySettings), NULL);
}
// vbox with two widgets packed in: label0 / progmeter0 (major)
vbox = gtk_vbox_new(FALSE, 0);
hbox = gtk_hbox_new(FALSE, 0);
sMajorLabel = gtk_label_new("");
sRateLabel = gtk_label_new("");
gtk_box_pack_start(GTK_BOX(hbox), sMajorLabel, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), sRateLabel, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show(hbox);
gtk_widget_show(sMajorLabel);
gtk_widget_show(sRateLabel);
sMajorProgBar = gtk_progress_bar_new();
gtk_box_pack_start(GTK_BOX(vbox), sMajorProgBar, FALSE, FALSE, 0);
// gtk_widget_show(sMajorProgBar);
gtk_table_attach(GTK_TABLE(mTable), vbox, 0, 1, 2, 3,
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
GtkAttachOptions(0), 20, 20);
gtk_widget_show(vbox);
// vbox with two widgets packed in: label1 / progmeter1 (minor)
vbox = gtk_vbox_new(FALSE, 0);
hbox = gtk_hbox_new(FALSE, 0);
sMinorLabel = gtk_label_new("");
gtk_box_pack_start(GTK_BOX(hbox), sMinorLabel, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show(hbox);
gtk_widget_show(sMinorLabel);
sMinorProgBar = gtk_progress_bar_new();
gtk_box_pack_start(GTK_BOX(vbox), sMinorProgBar, FALSE, FALSE, 0);
// gtk_widget_show(sMinorProgBar);
gtk_table_attach(GTK_TABLE(mTable), vbox, 0, 1, 3, 4,
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
GtkAttachOptions(0), 20, 20);
gtk_widget_show(vbox);
vbox = gtk_vbox_new(FALSE, 0);
sMsg0Label = gtk_label_new(mMsg0);
gtk_misc_set_alignment(GTK_MISC(sMsg0Label), 0.0, 1.0);
gtk_misc_set_padding(GTK_MISC(sMsg0Label), 6, 12);
gtk_box_pack_start(GTK_BOX(vbox), sMsg0Label, TRUE, TRUE, 0);
gtk_table_attach(GTK_TABLE(mTable), vbox, 0, 1, 4, 5,
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
GtkAttachOptions(GTK_FILL | GTK_EXPAND), 0, 0);
gtk_widget_show(sMsg0Label);
gtk_widget_show(vbox);
mWidgetsInit = TRUE;
}
else
{
gtk_notebook_set_page(GTK_NOTEBOOK(gCtx->notebook), mPageNum);
gtk_widget_show(mTable);
}
// <b>title</b>\0
char *titleBuf = new char[strlen(mTitle) + 9];
sprintf(titleBuf, "<b>%s</b>", mTitle);
gtk_label_set_markup(GTK_LABEL(gCtx->header_title), titleBuf);
gtk_label_set_text(GTK_LABEL(gCtx->header_subtitle), mSubTitle);
delete[] titleBuf;
// signal connect the buttons
gCtx->backID = gtk_signal_connect(GTK_OBJECT(gCtx->back), "clicked",
GTK_SIGNAL_FUNC(nsInstallDlg::Back), gCtx->idlg);
gCtx->nextID = gtk_signal_connect(GTK_OBJECT(gCtx->next), "clicked",
GTK_SIGNAL_FUNC(nsInstallDlg::Next), gCtx->idlg);
if (gCtx->opt->mSetupType != (gCtx->sdlg->GetNumSetupTypes() - 1))
gtk_widget_set_sensitive(gCtx->back, TRUE);
// always change title of next button to "Install"
gtk_button_set_label(GTK_BUTTON(gCtx->next), gCtx->Res("INSTALL"));
return err;
}
int
nsInstallDlg::Hide(int aDirection)
{
gtk_widget_hide(mTable);
return OK;
}
int
nsInstallDlg::ShowTable()
{
if (!mTable)
return E_PARAM;
gtk_widget_show(mTable);
return OK;
}
int
nsInstallDlg::HideTable()
{
if (!mTable)
return E_PARAM;
gtk_widget_hide(mTable);
return OK;
}
int
nsInstallDlg::SetMsg0(char *aMsg)
{
if (!aMsg)
return E_PARAM;
mMsg0 = aMsg;
return OK;
}
char *
nsInstallDlg::GetMsg0()
{
if (mMsg0)
return mMsg0;
return NULL;
}
int
nsInstallDlg::PerformInstall()
{
DUMP("PerformInstall");
int err = OK;
// perform the installation
nsXIEngine *engine = new nsXIEngine();
if (!engine)
{
ErrorHandler(E_MEM);
return E_MEM;
}
// get the component list for the current setup type
nsComponentList *comps = NULL;
nsComponent *xpiengine = NULL;
int bCus = (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1));
comps = gCtx->sdlg->GetSelectedSetupType()->GetComponents();
if (!comps)
{
ErrorHandler(E_NO_COMPONENTS);
return E_NO_COMPONENTS;
}
if (!sXPInstallEngine) return E_PARAM;
xpiengine = comps->GetCompByArchive(sXPInstallEngine);
// 1> download
err = engine->Download(bCus, comps);
if (err == E_DL_DROP_CXN)
{
ShowCxnDroppedDlg();
if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT)
DLPause(NULL, NULL);
return err;
}
else if (err == E_CRC_FAILED)
{
ShowCRCFailedDlg();
goto BAIL;
}
else if (err == E_DL_PAUSE || err == E_DL_CANCEL)
{
DUMP("Pause or Cancel pressed");
goto BAIL;
}
else if (err != OK)
{
DUMP("dammit... hopped into the wrong hole!");
ErrorHandler(err);
goto BAIL;
}
// prepare install UI
if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT)
{
InitInstallProgress();
HideNavButtons();
}
// 2> extract engine
XI_ERR_BAIL(engine->Extract(xpiengine));
// 3> install .xpis
XI_ERR_BAIL(engine->Install(bCus, comps, gCtx->opt->mDestination));
// delete xpis if user didn't request saving them
if (bDownload && !gCtx->opt->mSaveModules)
{
engine->DeleteXPIs(bCus, comps);
}
// run all specified applications after installation
if (sRunAppList)
{
if (gCtx->opt->mShouldRunApps)
RunApps();
FreeRunAppList();
}
BAIL:
// destroy installer engine thread object
XI_IF_DELETE(engine);
return err;
}
void
nsInstallDlg::XPIProgressCB(const char *aMsg, int aVal, int aMax)
{
if (gCtx->opt->mMode == nsXIOptions::MODE_SILENT)
return;
// DUMP("XPIProgressCB");
if (!aMsg)
return;
static int updates = 0;
char msg[64];
const char *colon = NULL, *lastSlash = NULL;
if (aMax > 0)
{
// reset for next component
if (updates)
updates = 0;
gfloat percent = (gfloat)((gfloat)aVal/(gfloat)aMax);
#if 0
printf("progress percent: %f\taVal: %d\taMax: %d\n", percent, aVal, aMax);
#endif
gtk_progress_set_activity_mode(GTK_PROGRESS(sMinorProgBar), FALSE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sMinorProgBar), percent);
gtk_widget_show(sMinorProgBar);
sprintf(msg, gCtx->Res("PROCESSING_FILE"), aVal, aMax);
}
else
{
updates++;
if (updates > 5)
updates = 0;
gfloat percent = (gfloat)((gfloat)updates/(gfloat)5);
gtk_progress_set_activity_mode(GTK_PROGRESS(sMinorProgBar), TRUE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sMinorProgBar), percent);
gtk_widget_show(sMinorProgBar);
/* tack on XPInstall action */
memset(msg, 0, 64);
colon = strchr(aMsg, ':');
if (colon)
strncpy(msg, aMsg, colon - aMsg);
strncat(msg, " ", 1);
/* tack on leaf name */
lastSlash = strrchr(aMsg, '/');
if (lastSlash)
strncat(msg, lastSlash + 1, strlen(lastSlash) - 1);
strncat(msg, "\0", 1);
}
gtk_label_set_text(GTK_LABEL(sMinorLabel), msg);
gtk_widget_draw(sMinorLabel, NULL);
XI_GTK_UPDATE_UI();
}
void
nsInstallDlg::MajorProgressCB(char *aName, int aNum, int aTotal, int aActivity)
{
// DUMP("MajorProgressCB");
char msg[256];
if (!aName)
return;
#ifdef DEBUG
printf("%s %d: Name = %s\tNum = %d\tTotal = %d\tAct = %d\n",
__FILE__, __LINE__, aName, aNum, aTotal, aActivity);
#endif
switch (aActivity)
{
case ACT_DOWNLOAD:
if (!bDownload)
sprintf(msg, gCtx->Res("PREPARING"), aName);
break;
case ACT_EXTRACT:
sprintf(msg, gCtx->Res("EXTRACTING"), aName);
break;
case ACT_INSTALL:
sprintf(msg, gCtx->Res("INSTALLING_XPI"), aName);
break;
default:
break;
}
gtk_label_set_text(GTK_LABEL(sMajorLabel), msg);
gtk_widget_show(sMajorLabel);
if (aTotal <= 0)
{
XI_ASSERT(0, "aTotal was <= 0");
XI_GTK_UPDATE_UI();
return;
}
gfloat percent = (gfloat)((gfloat)aNum/(gfloat)aTotal);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sMajorProgBar), percent);
gtk_widget_show(sMajorProgBar);
// reset minor progress ui
if (aActivity == ACT_INSTALL)
{
gtk_label_set_text(GTK_LABEL(sMinorLabel), "");
gtk_progress_bar_update(GTK_PROGRESS_BAR(sMinorProgBar), (gfloat)0);
gtk_widget_show(sMinorLabel);
gtk_widget_show(sMinorProgBar);
}
XI_GTK_UPDATE_UI();
}
const int kCharsInDLLabel = 50;
void
nsInstallDlg::SetDownloadComp(nsComponent *aComp, int aURLIndex,
int aNum, int aTotal)
{
static char xpiDir[MAXPATHLEN];
static int bHaveXPIDir = FALSE;
char label[MAXPATHLEN];
char localPath[MAXPATHLEN];
if (!aComp)
return;
if (!bHaveXPIDir)
{
getcwd(xpiDir, MAXPATHLEN);
strcat(xpiDir, "/xpi");
bHaveXPIDir = TRUE;
}
// update comp name
sprintf(label, "%s [%d/%d]", aComp->GetDescShort(), aNum, aTotal);
gtk_label_set_text(GTK_LABEL(sDLProgress.compName), label);
// update from URL
label[0] = 0;
CompressToFit(aComp->GetURL(aURLIndex), label, kCharsInDLLabel);
gtk_label_set_text(GTK_LABEL(sDLProgress.URL), label);
// to local path
label[0] = 0;
sprintf(localPath, "%s/%s", xpiDir, aComp->GetArchive());
CompressToFit(localPath, label, kCharsInDLLabel);
gtk_label_set_text(GTK_LABEL(sDLProgress.localPath), label);
gettimeofday(&sDLStartTime, NULL);
}
#define SHOW_EVERY_N_KB 16
int
nsInstallDlg::DownloadCB(int aBytesRd, int aTotal)
{
struct timeval now;
char label[64];
int rate;
gfloat percent = 0;
static int timesCalled = 0;
static int activityCount = 0;
int dlKB;
static int lastTotal = 0;
static int lastBytesRd = 0;
// new component being downloaded
if (lastTotal != aTotal)
{
lastBytesRd = 0; // reset
lastTotal = aTotal;
}
if ((aBytesRd - lastBytesRd) > 0)
{
sDLProgress.downloadedBytes += aBytesRd - lastBytesRd;
lastBytesRd = aBytesRd;
}
if (bDLPause || bDLCancel)
{
return nsHTTPConn::E_USER_CANCEL;
}
if (++timesCalled < SHOW_EVERY_N_KB)
return 0;
else
timesCalled = 0;
gettimeofday(&now, NULL);
rate = (int) nsSocket::CalcRate(&sDLStartTime, &now, aBytesRd);
// update the status -- bytes thus far, rate, percent in prog bar
dlKB = sDLProgress.downloadedBytes/1024;
sprintf(label, gCtx->Res("DL_STATUS_STR"), dlKB, sDLProgress.totalKB, rate);
gtk_label_set_text(GTK_LABEL(sDLProgress.status), label);
/*
// only update rate in major label line
XXX remove this: DLRATE no longer exists
sprintf(label, gCtx->Res("DLRATE"), rate);
gtk_label_set_text(GTK_LABEL(sRateLabel), label);
*/
if (sDLProgress.totalKB <= 0)
{
// show some activity
if (activityCount >= 5) activityCount = 0;
percent = (gfloat)( (gfloat)activityCount++/ (gfloat)5 );
gtk_progress_set_activity_mode(GTK_PROGRESS(sDLProgress.progBar), TRUE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sDLProgress.progBar), percent);
}
else
{
percent = (gfloat)dlKB/(gfloat)sDLProgress.totalKB;
#ifdef DEBUG
printf("DLProgress: %d of %d (%f percent) at %d KB/sec\n", dlKB,
sDLProgress.totalKB, percent, rate);
#endif
gtk_progress_set_activity_mode(GTK_PROGRESS(sDLProgress.progBar),
FALSE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sDLProgress.progBar), percent);
}
XI_GTK_UPDATE_UI();
return 0;
}
void
nsInstallDlg::ClearRateLabel()
{
gtk_label_set_text(GTK_LABEL(sRateLabel), "");
gtk_progress_set_activity_mode(GTK_PROGRESS(sMajorProgBar), FALSE);
XI_GTK_UPDATE_UI();
}
void
nsInstallDlg::SaveModulesToggled(GtkWidget *aWidget, gpointer aData)
{
if (GTK_TOGGLE_BUTTON(aWidget)->active)
{
DUMP("Save modules toggled on");
gCtx->opt->mSaveModules = TRUE;
}
else
{
DUMP("Save modules toggled off");
gCtx->opt->mSaveModules = FALSE;
}
}
void
nsInstallDlg::ShowProxySettings(GtkWidget *aWidget, gpointer aData)
{
GtkWidget *psDlg, *psTable;
GtkWidget *okButton, *cancelButton;
GtkWidget *psLabel[NUM_PS_ENTRIES];
int i;
char resName[16], *text = nsnull;
psDlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(psDlg), gCtx->opt->mTitle);
gtk_window_set_position(GTK_WINDOW(psDlg), GTK_WIN_POS_CENTER);
psTable = gtk_table_new(5, 2, FALSE);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(psDlg)->vbox), psTable);
gtk_widget_show(psTable);
// create labels
for (i = 0; i < NUM_PS_ENTRIES; ++i)
{
sprintf(resName, "PS_LABEL%d", i);
psLabel[i] = gtk_label_new(gCtx->Res(resName));
gtk_widget_show(psLabel[i]);
gtk_table_attach_defaults(GTK_TABLE(psTable), psLabel[i],
0, 1, i, i + 1);
}
// create text entry fields
for (i = 0; i < NUM_PS_ENTRIES; ++i)
{
sPSTextEntry[i] = gtk_entry_new();
gtk_entry_set_editable(GTK_ENTRY(sPSTextEntry[i]), TRUE);
// reset text if we already opened this dlg before
if (i == 0) text = gCtx->opt->mProxyHost;
if (i == 1) text = gCtx->opt->mProxyPort;
if (i == 2) text = gCtx->opt->mProxyUser;
if (i == 3) text = gCtx->opt->mProxyPswd;
if (text)
gtk_entry_set_text(GTK_ENTRY(sPSTextEntry[i]), text);
// password field
if (i + 1 == NUM_PS_ENTRIES)
gtk_entry_set_visibility(GTK_ENTRY(sPSTextEntry[i]), FALSE);
gtk_widget_show(sPSTextEntry[i]);
gtk_table_attach(GTK_TABLE(psTable), sPSTextEntry[i],
1, 2, i, i + 1,
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), 5, 5);
}
// pre-populate text entry fields if data already stored
okButton = gtk_button_new_with_label(gCtx->Res("OK_LABEL"));
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(psDlg)->action_area),
okButton);
gtk_signal_connect(GTK_OBJECT(okButton), "clicked",
GTK_SIGNAL_FUNC(PSDlgOK), psDlg);
gtk_widget_show(okButton);
cancelButton = gtk_button_new_with_label(gCtx->Res("CANCEL_LABEL"));
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(psDlg)->action_area),
cancelButton);
gtk_signal_connect(GTK_OBJECT(cancelButton), "clicked",
GTK_SIGNAL_FUNC(PSDlgCancel), psDlg);
gtk_widget_show(cancelButton);
gtk_widget_show(psDlg);
}
void
nsInstallDlg::PSDlgOK(GtkWidget *aWidget, gpointer aData)
{
GtkWidget *dlg = (GtkWidget *) aData;
char *text;
// grab proxy host field
if (sPSTextEntry[0])
{
text = gtk_editable_get_chars(GTK_EDITABLE(sPSTextEntry[0]), 0, -1);
if (text)
{
XI_IF_FREE(gCtx->opt->mProxyHost);
gCtx->opt->mProxyHost = text;
}
}
// grab proxy port field
if (sPSTextEntry[1])
{
text = gtk_editable_get_chars(GTK_EDITABLE(sPSTextEntry[1]), 0, -1);
if (text)
{
XI_IF_FREE(gCtx->opt->mProxyPort);
gCtx->opt->mProxyPort = text;
}
}
// grab proxy user field
if (sPSTextEntry[2])
{
text = gtk_editable_get_chars(GTK_EDITABLE(sPSTextEntry[2]), 0, -1);
if (text)
{
XI_IF_FREE(gCtx->opt->mProxyUser);
gCtx->opt->mProxyUser = text;
}
}
// grab proxy pswd field
if (sPSTextEntry[3])
{
text = gtk_editable_get_chars(GTK_EDITABLE(sPSTextEntry[3]), 0, -1);
if (text)
{
XI_IF_FREE(gCtx->opt->mProxyPswd);
gCtx->opt->mProxyPswd = text;
}
}
if (dlg)
gtk_widget_destroy(dlg);
}
void
nsInstallDlg::PSDlgCancel(GtkWidget *aWidget, gpointer aData)
{
GtkWidget *dlg = (GtkWidget *) aData;
if (dlg)
gtk_widget_destroy(dlg);
}
void
nsInstallDlg::DLPause(GtkWidget *aWidget, gpointer aData)
{
DUMP("DLPause");
// set pause for download callback to return to libxpnet
bDLPause = TRUE;
// disbale pause button
gtk_widget_set_sensitive(gCtx->back, FALSE);
// enable resume button
gtk_widget_set_sensitive(gCtx->next, TRUE);
gtk_main();
}
void
nsInstallDlg::DLResume(GtkWidget *aWidget, gpointer aData)
{
DUMP("DLResume");
if (!bDLPause)
{
DUMP("Not paused");
return;
}
DUMP("Unsetting bDLPause");
bDLPause = FALSE;
// disable resume button
gtk_widget_set_sensitive(gCtx->next, FALSE);
// enable pause button
gtk_widget_set_sensitive(gCtx->back, TRUE);
gtk_main_quit();
PerformInstall();
return;
}
void
nsInstallDlg::DLCancel(GtkWidget *aWidget, gpointer aData)
{
DUMP("DLCancel");
// show cancellation confirm dialog
// XXX TO DO
// set cancel for download callback to return to libxpnet
bDLCancel = TRUE;
#ifdef DEBUG
printf("%s %d: bDLPause: %d\tbDLCancel: %d\n", __FILE__, __LINE__,
bDLPause, bDLCancel);
#endif
// already paused then take explicit action to quit
if (bDLPause)
{
gtk_main_quit();
}
}
int
nsInstallDlg::CancelOrPause()
{
int err = OK;
if (bDLPause)
{
err = E_DL_PAUSE;
}
else if (bDLCancel)
{
err = E_DL_CANCEL;
}
return err;
}
static GtkWidget *crcDlg = (GtkWidget *) NULL;
void
nsInstallDlg::ShowCRCDlg()
{
GtkWidget *label;
if (gCtx->opt->mMode == nsXIOptions::MODE_SILENT) {
ErrorHandler(E_CRC_FAILED);
return;
}
if ( crcDlg == (GtkWidget *) NULL ) {
// throw up dialog informing user to press resume
// or to cancel out
crcDlg = gtk_dialog_new_with_buttons(gCtx->opt->mTitle, NULL,
(GtkDialogFlags) 0,
GTK_STOCK_OK,
GTK_RESPONSE_NONE,
NULL);
label = gtk_label_new(gCtx->Res("CRC_CHECK"));
g_signal_connect_swapped(GTK_OBJECT(crcDlg), "response",
G_CALLBACK(CRCOKCb), GTK_OBJECT(crcDlg));
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(crcDlg)->vbox), label);
gtk_widget_show_all(crcDlg);
}
XI_GTK_UPDATE_UI();
}
int
nsInstallDlg::ShowCRCFailedDlg()
{
GtkWidget *crcFailedDlg, *label;
// throw up dialog informing user to press resume
// or to cancel out
if (gCtx->opt->mMode == nsXIOptions::MODE_SILENT) {
ErrorHandler(E_CRC_FAILED);
return OK;
}
crcFailedDlg = gtk_dialog_new_with_buttons(gCtx->opt->mTitle, NULL,
GTK_DIALOG_MODAL,
GTK_STOCK_OK,
GTK_RESPONSE_NONE,
NULL);
label = gtk_label_new(gCtx->Res("CRC_FAILED"));
g_signal_connect_swapped(GTK_OBJECT(crcFailedDlg), "response",
G_CALLBACK(CRCFailedOK), GTK_OBJECT(crcFailedDlg));
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(crcFailedDlg)->vbox), label);
gtk_widget_show_all(crcFailedDlg);
XI_GTK_UPDATE_UI();
return OK;
}
int
nsInstallDlg::ShowCxnDroppedDlg()
{
GtkWidget *cxnDroppedDlg, *label;
// throw up dialog informing user to press resume
// or to cancel out
if (gCtx->opt->mMode == nsXIOptions::MODE_SILENT) {
ErrorHandler(E_NO_DOWNLOAD);
return OK;
}
cxnDroppedDlg = gtk_dialog_new_with_buttons(gCtx->opt->mTitle, NULL,
GTK_DIALOG_MODAL,
GTK_STOCK_OK,
GTK_RESPONSE_NONE,
NULL);
label = gtk_label_new(gCtx->Res("CXN_DROPPED"));
g_signal_connect_swapped(GTK_OBJECT(cxnDroppedDlg), "response",
G_CALLBACK(CxnDroppedOK), GTK_OBJECT(cxnDroppedDlg));
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(cxnDroppedDlg)->vbox), label);
gtk_widget_show_all(cxnDroppedDlg);
XI_GTK_UPDATE_UI();
return OK;
}
void
nsInstallDlg::CRCFailedOK(GtkWidget *aWidget, gpointer aData)
{
gtk_main_quit();
return;
}
void
nsInstallDlg::DestroyCRCDlg()
{
CRCOKCb( (GtkWidget *) NULL, (gpointer) NULL );
}
void
nsInstallDlg::CRCOKCb(GtkWidget *aWidget, gpointer aData)
{
if (crcDlg != (GtkWidget *) NULL)
gtk_widget_destroy(crcDlg);
crcDlg = (GtkWidget *) NULL;
return;
}
void
nsInstallDlg::CxnDroppedOK(GtkWidget *aWidget, gpointer aData)
{
GtkWidget *cxnDroppedDlg = (GtkWidget *) aData;
if (cxnDroppedDlg)
gtk_widget_destroy(cxnDroppedDlg);
return;
}
void
nsInstallDlg::HideNavButtons()
{
gtk_signal_disconnect(GTK_OBJECT(gCtx->back), gCtx->backID);
gtk_signal_disconnect(GTK_OBJECT(gCtx->next), gCtx->nextID);
gtk_signal_disconnect(GTK_OBJECT(gCtx->cancel), gCtx->cancelID);
gtk_widget_set_sensitive(gCtx->back, FALSE);
gtk_widget_set_sensitive(gCtx->next, FALSE);
gtk_widget_set_sensitive(gCtx->cancel, FALSE);
}
void
nsInstallDlg::InitDLProgress( int isFirst )
{
GtkWidget *titles[4];
GtkWidget *hbox;
GtkWidget *table;
gCtx->idlg->HideTable();
if ( isFirst == TRUE ) {
sDLProgress.vbox = gtk_vbox_new(FALSE, 10);
gtk_notebook_append_page(GTK_NOTEBOOK(gCtx->notebook),
sDLProgress.vbox, NULL);
gtk_widget_show(sDLProgress.vbox);
table = gtk_table_new(5, 2, FALSE);
gtk_box_pack_start(GTK_BOX(sDLProgress.vbox), table, FALSE,
FALSE, 0);
gtk_widget_show(table);
// setup static title progress labels in table left column
titles[0] = gtk_label_new(gCtx->Res("DOWNLOADING"));
titles[1] = gtk_label_new(gCtx->Res("FROM"));
titles[2] = gtk_label_new(gCtx->Res("TO"));
titles[3] = gtk_label_new(gCtx->Res("STATUS"));
// setup dynamic progress labels in right column
sDLProgress.compName = gtk_label_new(gCtx->Res("UNKNOWN"));
sDLProgress.URL = gtk_label_new(gCtx->Res("UNKNOWN"));
sDLProgress.localPath = gtk_label_new(gCtx->Res("UNKNOWN"));
sDLProgress.status = gtk_label_new(gCtx->Res("UNKNOWN"));
// pack and show titles
for (int i = 0; i < 4; ++i)
{
hbox = gtk_hbox_new(FALSE, 10);
gtk_box_pack_end(GTK_BOX(hbox), titles[i], FALSE, FALSE, 0);
gtk_table_attach(GTK_TABLE(table), hbox,
0, 1, i, i + 1, GTK_FILL, GTK_FILL, 5, 5);
gtk_widget_show(titles[i]);
gtk_widget_show(hbox);
}
// pack and show dynamic labels
hbox = gtk_hbox_new(FALSE, 10);
gtk_box_pack_start(GTK_BOX(hbox), sDLProgress.compName, FALSE, FALSE, 0);
gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 0, 1,
GTK_FILL, GTK_FILL, 5, 5);
gtk_widget_show(sDLProgress.compName);
gtk_widget_show(hbox);
hbox = gtk_hbox_new(FALSE, 10);
gtk_box_pack_start(GTK_BOX(hbox), sDLProgress.URL, FALSE, FALSE, 0);
gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 1, 2,
GTK_FILL, GTK_FILL, 5, 5);
gtk_widget_show(sDLProgress.URL);
gtk_widget_show(hbox);
hbox = gtk_hbox_new(FALSE, 10);
gtk_box_pack_start(GTK_BOX(hbox), sDLProgress.localPath, FALSE,
FALSE, 0);
gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 2, 3,
GTK_FILL, GTK_FILL, 5, 5);
gtk_widget_show(sDLProgress.localPath);
gtk_widget_show(hbox);
hbox = gtk_hbox_new(FALSE, 10);
gtk_box_pack_start(GTK_BOX(hbox), sDLProgress.status, FALSE,
FALSE, 0);
gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 3, 4,
GTK_FILL, GTK_FILL, 5, 5);
gtk_widget_show(sDLProgress.status);
gtk_widget_show(hbox);
// init and show prog bar
sDLProgress.progBar = gtk_progress_bar_new();
// show prog bar
hbox = gtk_hbox_new(TRUE, 10);
gtk_box_pack_start(GTK_BOX(hbox), sDLProgress.progBar, FALSE,
TRUE, 0);
gtk_box_pack_start(GTK_BOX(sDLProgress.vbox), hbox, FALSE,
FALSE, 0);
gtk_widget_show(sDLProgress.progBar);
gtk_widget_show(hbox);
}
// set to non-activity mode and initialize
gtk_progress_set_activity_mode(GTK_PROGRESS(sDLProgress.progBar), FALSE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sDLProgress.progBar), (gfloat) 0);
// compute total download size
sDLProgress.downloadedBytes = 0;
sDLProgress.totalKB = TotalDLSize();
XI_GTK_UPDATE_UI();
}
void
nsInstallDlg::InitInstallProgress()
{
if ( sDLProgress.vbox )
gtk_widget_hide(sDLProgress.vbox);
gCtx->idlg->ShowTable();
}
int
nsInstallDlg::TotalDLSize()
{
int total = 0; // in KB
int bCustom;
nsComponentList *comps;
nsComponent *currComp;
int archiveSize, currentSize;
bCustom = (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1));
comps = gCtx->sdlg->GetSelectedSetupType()->GetComponents();
currComp = comps->GetHead();
// loop through all components
while (currComp)
{
if ((bCustom && currComp->IsSelected()) || (!bCustom))
{
// if still have to download
if (!currComp->IsDownloaded())
{
// find archive size - amount downloaded already
archiveSize = currComp->GetArchiveSize();
currentSize = currComp->GetCurrentSize();
#ifdef DEBUG
printf("%s ar sz = %d cu sz = %d\n", currComp->GetArchive(),
archiveSize, currentSize);
#endif
total += (archiveSize - currentSize);
}
}
currComp = currComp->GetNext();
}
return total;
}
void
nsInstallDlg::CompressToFit(char *aOrigStr, char *aOutStr, int aOutStrLen)
{
int origStrLen;
int halfOutStrLen;
char *lastPart; // last aOrigStr part start
if (!aOrigStr || !aOutStr || aOutStrLen <= 0)
return;
origStrLen = strlen(aOrigStr);
halfOutStrLen = (aOutStrLen/2) - 2; // minus 2 since ellipsis is 3 chars
lastPart = aOrigStr + origStrLen - halfOutStrLen;
strncpy(aOutStr, aOrigStr, halfOutStrLen);
*(aOutStr + halfOutStrLen) = 0;
strcat(aOutStr, "...");
strncat(aOutStr, lastPart, strlen(lastPart));
*(aOutStr + aOutStrLen + 1) = 0;
}
void
nsInstallDlg::ReInitUI( void )
{
InitDLProgress( FALSE );
}