Back to index

lightning-sunbird  0.9+nobinonly
nsXInstaller.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Samir Gehani <sgehani@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nscore.h"
00041 #include "nsXInstaller.h"
00042 #include "logo.xpm"
00043 
00044 nsXIContext *gCtx = NULL;
00045 static GtkWidget *sErrDlg = NULL;
00046 
00047 nsXInstaller::nsXInstaller()
00048 {
00049 }
00050 
00051 nsXInstaller::~nsXInstaller()
00052 {
00053     XI_IF_DELETE(gCtx);
00054 }
00055 
00056 int 
00057 nsXInstaller::ParseArgs(int aArgc, char **aArgv)
00058 {
00059     if (aArgc <= 0 || !aArgv)
00060         return E_PARAM;
00061 
00062     for (int argNum = 1; argNum < aArgc; ++argNum)
00063     {
00064         /* Print usage
00065          */
00066         if (strcmp(aArgv[argNum], "-h") == 0 ||
00067             strcmp(aArgv[argNum], "--help") == 0)
00068         {
00069            if (gCtx->Res("USAGE_MSG"))
00070                 fprintf (stderr, gCtx->Res("USAGE_MSG"), aArgv[0], "\n", 
00071                       "\n", "\n", "\n", "\n", "\n", "\n", "\n");
00072             return E_USAGE_SHOWN;
00073         }
00074 
00075         /* mode: auto  (show progress UI but assume defaults
00076          *              without user intervention)
00077          */
00078         else if (strcmp(aArgv[argNum], "-ma") == 0)
00079         {
00080             gCtx->opt->mMode = nsXIOptions::MODE_AUTO;
00081         }
00082         
00083         /* mode: silent (show no UI and have no user
00084          *               intervention)
00085          */
00086         else if (strcmp(aArgv[argNum], "-ms") == 0)
00087         {
00088             gCtx->opt->mMode = nsXIOptions::MODE_SILENT;
00089         }
00090 
00091         /* ignore [RunAppX] sections
00092          */
00093         else if (strcmp(aArgv[argNum], "-ira") == 0)
00094         {
00095             gCtx->opt->mShouldRunApps = FALSE;
00096         }
00097     }
00098 
00099     return OK;
00100 }
00101 
00102 int
00103 nsXInstaller::ParseConfig()
00104 {
00105     int err = OK;
00106     nsINIParser *parser = NULL; 
00107     char *cfg = NULL;
00108 
00109     XI_ERR_BAIL(InitContext());
00110     err = gCtx->LoadResources();
00111     if (err != OK)
00112         return err;
00113 
00114     cfg = nsINIParser::ResolveName(CONFIG);
00115     if (!cfg)
00116         return E_INVALID_PTR;
00117 
00118     parser = new nsINIParser(cfg);
00119     if (!parser)
00120     {
00121         err = E_MEM;    
00122         goto BAIL;
00123     }
00124 
00125     err = parser->GetError();
00126     if (err != nsINIParser::OK)
00127         return err;
00128 
00129     XI_ERR_BAIL(ParseGeneral(parser));
00130     XI_ERR_BAIL(gCtx->ldlg->Parse(parser));
00131     XI_ERR_BAIL(gCtx->wdlg->Parse(parser));
00132     XI_ERR_BAIL(gCtx->cdlg->Parse(parser)); // components before setup type
00133     XI_ERR_BAIL(gCtx->sdlg->Parse(parser));
00134     XI_ERR_BAIL(gCtx->idlg->Parse(parser));
00135 
00136 BAIL:
00137     XI_IF_FREE(cfg);
00138     if (err != OK)
00139         ErrorHandler(err);
00140     return err;
00141 }
00142 
00143 int 
00144 nsXInstaller::InitContext()
00145 {
00146     int err = OK;
00147 
00148     gCtx = new nsXIContext();
00149     if (!gCtx)
00150         return E_MEM;
00151 
00152     gCtx->me = this;
00153 
00154     gCtx->ldlg = new nsLicenseDlg();
00155     gCtx->wdlg = new nsWelcomeDlg();
00156     gCtx->sdlg = new nsSetupTypeDlg();
00157     gCtx->cdlg = new nsComponentsDlg();
00158     gCtx->idlg = new nsInstallDlg();
00159     if (!gCtx->ldlg || !gCtx->wdlg || !gCtx->sdlg || 
00160         !gCtx->cdlg || !gCtx->idlg )
00161     {
00162         err = E_MEM;
00163         goto BAIL;
00164     }
00165 
00166     return OK;
00167     
00168 BAIL:
00169     XI_IF_DELETE(gCtx->ldlg);
00170     XI_IF_DELETE(gCtx->wdlg);
00171     XI_IF_DELETE(gCtx->sdlg);
00172     XI_IF_DELETE(gCtx->cdlg);
00173     XI_IF_DELETE(gCtx->idlg);
00174     XI_IF_DELETE(gCtx);
00175 
00176     return err;
00177 }
00178 
00179 int 
00180 nsXInstaller::RunWizard(int argc, char **argv)
00181 {
00182     int err = OK;
00183     GtkWidget *logovbox;
00184 
00185     XI_VERIFY(gCtx);
00186 
00187     // create the dialog window
00188     if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT) {
00189         gtk_set_locale();
00190         gtk_init(&argc, &argv);
00191         gdk_rgb_init();
00192 
00193         gCtx->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00194         XI_VERIFY(gCtx->window);
00195 
00196         gtk_window_set_position(GTK_WINDOW(gCtx->window), GTK_WIN_POS_CENTER);
00197         gtk_signal_connect(GTK_OBJECT(gCtx->window), "delete_event",
00198                            GTK_SIGNAL_FUNC(Kill), NULL);
00199 
00200         gtk_widget_set_usize(gCtx->window, XI_WIN_WIDTH, XI_WIN_HEIGHT);
00201         gtk_container_set_border_width(GTK_CONTAINER(gCtx->window), 5);
00202         gtk_window_set_title(GTK_WINDOW(gCtx->window), gCtx->opt->mTitle);
00203         gtk_widget_show(gCtx->window);
00204 
00205         // create and display the logo and cancel button
00206         logovbox = DrawLogo();
00207         if (logovbox)
00208             DrawCancelButton(logovbox);
00209 
00210         // create and display the nav buttons
00211         XI_ERR_BAIL(DrawNavButtons());
00212 
00213         // create the notebook whose pages are dlgs
00214         gCtx->notebook = gtk_notebook_new();
00215         XI_VERIFY(gCtx->notebook);
00216         gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gCtx->notebook), FALSE);
00217         gtk_notebook_set_show_border(GTK_NOTEBOOK(gCtx->notebook), FALSE);
00218         gtk_notebook_set_scrollable(GTK_NOTEBOOK(gCtx->notebook), FALSE);
00219         gtk_widget_show(gCtx->notebook);
00220         gtk_container_add(GTK_CONTAINER(gCtx->canvas), gCtx->notebook);
00221     }
00222 
00223     if (gCtx->opt->mMode == nsXIOptions::MODE_DEFAULT)
00224     {
00225         // show welcome dlg
00226         gCtx->wdlg->Show(); 
00227 
00228         // pop over to main event loop
00229         gtk_main();
00230 
00231     }
00232     else
00233     {
00234         // jump to the SetupType dialog to check destination directory
00235         gCtx->sdlg->Next((GtkWidget *)NULL, (gpointer) gCtx->sdlg);
00236     }
00237 
00238     return OK;
00239 
00240 BAIL:
00241     return err;
00242 }
00243 
00244 gint
00245 nsXInstaller::Kill(GtkWidget *widget, GtkWidget *event, gpointer data)
00246 {
00247     gtk_main_quit();
00248     return FALSE;
00249 }
00250 
00251 GtkWidget *
00252 nsXInstaller::DrawLogo()
00253 {
00254     GtkWidget *logo = NULL;
00255     GdkPixmap *pixmap = NULL;
00256     GdkBitmap *mask = NULL;
00257     GtkStyle *style = NULL;
00258     GtkWidget *mainhbox = NULL;
00259     GtkWidget *logovbox = NULL;
00260     GtkWidget *canvasvbox = NULL;
00261 
00262     style = gtk_widget_get_style(gCtx->window);
00263     pixmap = gdk_pixmap_create_from_xpm_d(gCtx->window->window, &mask,
00264                                           &style->bg[GTK_STATE_NORMAL],
00265                                           (gchar **)logo_xpm);
00266 
00267     logo = gtk_pixmap_new(pixmap, mask);
00268     gtk_widget_show(logo);
00269 
00270     mainhbox = gtk_hbox_new(FALSE, 10);
00271     logovbox = gtk_vbox_new(FALSE, 30);
00272     canvasvbox = gtk_vbox_new(FALSE, 10);
00273 
00274     gtk_box_pack_start(GTK_BOX(logovbox), logo, FALSE, FALSE, 0);
00275     gtk_widget_show(logovbox);
00276     gtk_widget_show(canvasvbox);
00277 
00278     gtk_box_pack_start(GTK_BOX(mainhbox), logovbox, FALSE, FALSE, 0);
00279     gtk_box_pack_start(GTK_BOX(mainhbox), canvasvbox, TRUE, TRUE, 0);
00280     gtk_widget_show(mainhbox);
00281 
00282     gtk_container_add(GTK_CONTAINER(gCtx->window), mainhbox);
00283 
00284     gCtx->mainbox = canvasvbox; /* canvasvbox = canvas + nav btns' box */
00285 
00286     return logovbox;
00287 }
00288 
00289 int
00290 nsXInstaller::DrawCancelButton(GtkWidget *aLogoVBox)
00291 {
00292     int err = OK;
00293     GtkWidget *hbox;
00294 
00295     gCtx->cancel = gtk_button_new_with_label(gCtx->Res("CANCEL"));
00296     hbox = gtk_hbox_new(FALSE, 0);
00297     gtk_box_pack_start(GTK_BOX(hbox), gCtx->cancel, TRUE, TRUE, 0);
00298     gtk_box_pack_end(GTK_BOX(aLogoVBox), hbox, FALSE, TRUE, 10);
00299     gCtx->cancelID = gtk_signal_connect(GTK_OBJECT(gCtx->cancel), "clicked",
00300                         GTK_SIGNAL_FUNC(Kill), NULL);
00301     gtk_widget_show(hbox);
00302     gtk_widget_show(gCtx->cancel);
00303 
00304     return err;
00305 }
00306 
00307 int
00308 nsXInstaller::DrawNavButtons()
00309 {
00310     int err = OK;
00311     
00312     GtkWidget *navbtnhbox;
00313     GtkWidget *canvasvbox;
00314     GtkWidget *navbtntable;
00315 
00316     XI_VERIFY(gCtx->mainbox);
00317 
00318     gCtx->next = gtk_button_new();  
00319     gCtx->back = gtk_button_new(); 
00320     XI_VERIFY(gCtx->next);
00321     XI_VERIFY(gCtx->back);
00322     
00323     navbtnhbox = gtk_hbox_new(TRUE, 10);
00324     canvasvbox = gtk_vbox_new(TRUE, 10);
00325     gtk_box_pack_start(GTK_BOX(gCtx->mainbox), canvasvbox, TRUE, TRUE, 0); 
00326     gtk_box_pack_start(GTK_BOX(gCtx->mainbox), navbtnhbox, FALSE, FALSE, 0); 
00327 
00328     // put a table in the nav btn box
00329     navbtntable = gtk_table_new(1, 4, TRUE);
00330     gtk_box_pack_start(GTK_BOX(navbtnhbox), navbtntable, TRUE, TRUE, 0);
00331 
00332     gtk_table_attach(GTK_TABLE(navbtntable), gCtx->back, 2, 3, 0, 1, 
00333         static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
00334                static_cast<GtkAttachOptions>(GTK_SHRINK),
00335                5, 5);
00336     gtk_table_attach(GTK_TABLE(navbtntable), gCtx->next, 3, 4, 0, 1,
00337         static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
00338                static_cast<GtkAttachOptions>(GTK_SHRINK),
00339                5, 5);
00340 
00341     gtk_widget_show(navbtntable); 
00342     gtk_widget_show(navbtnhbox); 
00343     gtk_widget_show(canvasvbox);
00344 
00345     GTK_WIDGET_SET_FLAGS(gCtx->next, GTK_CAN_DEFAULT);
00346     gtk_widget_grab_default(gCtx->next);
00347     gtk_widget_grab_focus(gCtx->next);
00348     gtk_widget_show(gCtx->mainbox);
00349 
00350     XI_VERIFY(canvasvbox);
00351     gCtx->canvas = canvasvbox; 
00352 
00353     return err;
00354 }
00355 
00356 int
00357 nsXInstaller::ParseGeneral(nsINIParser *aParser)
00358 {
00359     int     err = OK;
00360     char    *dest = NULL, *title = NULL;
00361     int     size = 0;
00362  
00363     /* optional: destination directory can be specified in config.ini */
00364     err = aParser->GetStringAlloc(GENERAL, DEFAULT_LOCATION, &dest, &size);
00365     if (err == OK && size > 0)
00366     {
00367         /* malloc MAXPATHLEN for consistency in behavior if destination
00368          * directory is not specified in the config.ini
00369          */
00370         gCtx->opt->mDestination = (char *)malloc(MAXPATHLEN * sizeof(char));
00371         strncpy(gCtx->opt->mDestination, dest, size);
00372         XI_IF_FREE(dest);
00373     }
00374     else
00375         err = OK; /* optional so no error if we didn't find it */
00376 
00377     /* optional: installer app window title */
00378     size = 0;
00379     err = aParser->GetStringAlloc(GENERAL, TITLE, &title, &size);
00380     if (err == OK && size > 0)
00381         gCtx->opt->mTitle = title;
00382     else
00383     {
00384         err = OK; /* optional so no error if we didn't find it */
00385         gCtx->opt->mTitle = strdup(gCtx->Res("DEFAULT_TITLE"));
00386     }
00387 
00388     return err;
00389 }
00390 
00391 int
00392 main(int argc, char **argv)
00393 {
00394     nsXInstaller *installer = new nsXInstaller();
00395     int err = OK;
00396 
00397     if (installer)
00398     {
00399         if ( (err = installer->ParseConfig()) == OK)
00400         {
00401             if (installer->ParseArgs(argc, argv) == OK)
00402                 err = installer->RunWizard(argc, argv);
00403         }
00404     }
00405     else
00406         err = E_MEM;
00407 
00408     XI_IF_DELETE(installer);
00409 
00410     exit(err);
00411 }
00412 
00413 /*------------------------------------------------------------------*
00414  *   Default Error Handler
00415  *------------------------------------------------------------------*/
00416 int 
00417 ErrorHandler(int aErr, const char* aErrMsg)
00418 {
00419     GtkWidget *okButton, *label;
00420     char msg[256];
00421     char newmsg[256];
00422     char errStr[16];
00423     
00424     sprintf(errStr, "%d", aErr); 
00425     if (aErrMsg != NULL)
00426        sprintf(newmsg, gCtx->Res(errStr), aErrMsg);
00427     else
00428        strcpy(newmsg, gCtx->Res(errStr));
00429 
00430     if (!IsErrFatal(aErr))
00431         sprintf(msg, gCtx->Res("ERROR"), aErr, newmsg);
00432     else
00433         sprintf(msg, gCtx->Res("FATAL_ERROR"), aErr, newmsg);
00434     
00435     // lack of gCtx->window indicates we have not yet run RunWizard 
00436     // and gtk_init
00437     if (gCtx->opt->mMode == nsXIOptions::MODE_SILENT || !gCtx->window)
00438     {
00439         fprintf (stderr, "%s\n", msg);
00440         if (IsErrFatal(aErr))
00441             exit(aErr);
00442         return aErr;
00443     }
00444     sErrDlg = gtk_dialog_new();
00445     gtk_window_set_modal(GTK_WINDOW(sErrDlg), TRUE);
00446     gtk_window_set_title(GTK_WINDOW(sErrDlg), gCtx->Res("ERROR_TITLE"));
00447     okButton = gtk_button_new_with_label(gCtx->Res("OK_LABEL"));
00448     label = gtk_label_new(msg);
00449 
00450     gtk_window_set_position(GTK_WINDOW(sErrDlg), GTK_WIN_POS_CENTER);
00451     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(sErrDlg)->action_area), 
00452                       okButton);
00453     gtk_signal_connect(GTK_OBJECT(okButton), "clicked",
00454                        GTK_SIGNAL_FUNC(ErrDlgOK), NULL);
00455     gtk_signal_connect(GTK_OBJECT(sErrDlg), "delete_event",
00456                        GTK_SIGNAL_FUNC(ErrDlgOK), NULL);
00457 
00458     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(sErrDlg)->vbox), label);
00459     
00460     GTK_WIDGET_SET_FLAGS(okButton, GTK_CAN_DEFAULT);
00461     gtk_widget_grab_default(okButton);
00462     gtk_widget_show_all(sErrDlg);
00463 
00464     gtk_main();
00465 
00466     if (IsErrFatal(aErr))
00467         exit(aErr);
00468 
00469     return aErr;
00470 }
00471 
00472 void
00473 ErrDlgOK(GtkWidget *aWidget, gpointer aData)
00474 {
00475     gtk_widget_destroy(sErrDlg);
00476     sErrDlg = NULL;
00477 
00478     gtk_main_quit();
00479 }
00480 
00481 int
00482 IsErrFatal(int aErr)
00483 {
00484     int bFatal = TRUE;
00485 
00486     /* non-fatal errors */
00487     switch (aErr)
00488     {
00489         case E_XPI_FAIL:
00490         case E_INSTALL:
00491         case E_MKDIR_FAIL:
00492         case E_OLD_INST:
00493         case E_DIR_NOT_EMPTY:
00494         case E_INVALID_PROXY:
00495             bFatal = FALSE;
00496         default:
00497             break; 
00498     }
00499 
00500     return bFatal;
00501 }