Back to index

lightning-sunbird  0.9+nobinonly
HelperAppDlg.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: Mozilla-sample-code 1.0
00004  *
00005  * Copyright (c) 2002 Netscape Communications Corporation and
00006  * other contributors
00007  *
00008  * Permission is hereby granted, free of charge, to any person obtaining a
00009  * copy of this Mozilla sample software and associated documentation files
00010  * (the "Software"), to deal in the Software without restriction, including
00011  * without limitation the rights to use, copy, modify, merge, publish,
00012  * distribute, sublicense, and/or sell copies of the Software, and to permit
00013  * persons to whom the Software is furnished to do so, subject to the
00014  * following conditions:
00015  *
00016  * The above copyright notice and this permission notice shall be included
00017  * in all copies or substantial portions of the Software.
00018  *
00019  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00020  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00022  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00023  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00024  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00025  * DEALINGS IN THE SOFTWARE.
00026  *
00027  * Contributor(s):
00028  *   Chak Nanga <chak@netscape.com>
00029  *
00030  * ***** END LICENSE BLOCK ***** */
00031 
00032 #include "stdafx.h"
00033 #include "HelperAppService.h"
00034 #include "HelperAppDlg.h"
00035 #include "nsCOMPtr.h"
00036 #include "nsString.h"
00037 #include "nsILocalFile.h"
00038 #include "nsIURI.h"
00039 #include "nsNetError.h"
00040 #include "nsIMIMEInfo.h"
00041 #include "nsIDOMWindow.h"
00042 #include "nsIEmbeddingSiteWindow.h"
00043 #include "nsIServiceManager.h"
00044 #include "nsIWebBrowserChrome.h"
00045 #include "nsIInterfaceRequestor.h"
00046 #include "nsIInterfaceRequestorUtils.h"
00047 
00048 // This file contains code which overrides the default
00049 // Gecko implementation for helper app dialog handling
00050 // 
00051 // General Overview:
00052 //
00053 //    We register the factory object for overriding helper app dialogs
00054 //    [See OverrideComponents() in mfcembed.cpp]
00055 //
00056 //
00057 //    When Gecko encounters content it cannot handle it will:
00058 //      1. Call CHelperAppLauncherDialog::Show() method
00059 //
00060 //      2. If the user chooses SaveToDisk in the dialog presented by
00061 //         step 1, then CHelperAppLauncherDialog::PromptForSaveToFile()
00062 //         will be called to get the filename to save the content to
00063 //         
00064 //         If the user chooses OpenUsingAnExternalApp option in the
00065 //         dialog box(and subsequnetly specifies the app to use by 
00066 //         clicking on the "Choose..." button), the specified app
00067 //         is run after the content is downloaded
00068 //
00069 //      3. In either case, an instance of nsIProgressDialog will be created
00070 //         which is used to display a download progress
00071 //         dialog box. This dialog box registers itself as a
00072 //         WebProgressListener so that it can receive the progress change
00073 //         messages, using which it can update the progress bar
00074 //
00075 //      4. The downloads can be cancelled by clicking on the "Cancel" button
00076 //         at anytime during the download.
00077 
00078 static HINSTANCE gInstance;
00079 
00080 //*****************************************************************************
00081 // ResourceState
00082 //***************************************************************************** 
00083 
00084 class ResourceState {
00085 public:
00086     ResourceState() {
00087         mPreviousInstance = ::AfxGetResourceHandle();
00088         ::AfxSetResourceHandle(gInstance);
00089     }
00090     ~ResourceState() {
00091         ::AfxSetResourceHandle(mPreviousInstance);
00092     }
00093 private:
00094     HINSTANCE mPreviousInstance;
00095 };
00096 
00097 //*****************************************************************************
00098 // CHelperAppLauncherDialogFactory Creation and Init Functions
00099 //*****************************************************************************   
00100 
00101 void InitHelperAppDlg(HINSTANCE instance) 
00102 {
00103   gInstance = instance;
00104 }
00105 
00106 nsresult NS_NewHelperAppDlgFactory(nsIFactory** aFactory)
00107 {
00108   NS_ENSURE_ARG_POINTER(aFactory);
00109   *aFactory = nsnull;
00110   
00111   CHelperAppLauncherDialogFactory *result = new CHelperAppLauncherDialogFactory;
00112   if (!result)
00113     return NS_ERROR_OUT_OF_MEMORY;
00114     
00115   NS_ADDREF(result);
00116   *aFactory = result;
00117   
00118   return NS_OK;
00119 }
00120 
00121 //*****************************************************************************
00122 // CHelperAppLauncherDialogFactory
00123 //*****************************************************************************   
00124 
00125 NS_IMPL_ISUPPORTS1(CHelperAppLauncherDialogFactory, nsIFactory)
00126 
00127 CHelperAppLauncherDialogFactory::CHelperAppLauncherDialogFactory() 
00128 {
00129 }
00130 
00131 CHelperAppLauncherDialogFactory::~CHelperAppLauncherDialogFactory() {
00132 }
00133 
00134 NS_IMETHODIMP CHelperAppLauncherDialogFactory::CreateInstance(nsISupports *aOuter, const nsIID & aIID, void **aResult)
00135 {
00136   NS_ENSURE_ARG_POINTER(aResult);
00137   
00138   *aResult = NULL;  
00139   CHelperAppLauncherDialog *inst = new CHelperAppLauncherDialog;
00140   if (!inst)
00141     return NS_ERROR_OUT_OF_MEMORY;
00142     
00143   nsresult rv = inst->QueryInterface(aIID, aResult);
00144   if (rv != NS_OK) {  
00145     // We didn't get the right interface, so clean up  
00146     delete inst;  
00147   }  
00148     
00149   return rv;
00150 }
00151 
00152 NS_IMETHODIMP CHelperAppLauncherDialogFactory::LockFactory(PRBool lock)
00153 {
00154   return NS_OK;
00155 }
00156 
00157 //*******************************************************************************
00158 // CHelperAppLauncherDialog - Implements the nsIHelperAppLauncherDialog interface
00159 //*******************************************************************************
00160 
00161 NS_IMPL_ISUPPORTS1(CHelperAppLauncherDialog, nsIHelperAppLauncherDialog)
00162 
00163 CHelperAppLauncherDialog::CHelperAppLauncherDialog() :
00164       mWWatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID))
00165 {
00166 }
00167 
00168 CHelperAppLauncherDialog::~CHelperAppLauncherDialog() 
00169 {
00170 }
00171 
00172 // Returns a CWnd given aWindowContext - the returned CWnd is mainly used as 
00173 // a parent window for the dialog boxes we display
00174 //
00175 CWnd* CHelperAppLauncherDialog::GetParentFromContext(nsISupports *aWindowContext)
00176 {
00177     nsCOMPtr<nsIDOMWindow> domWnd(do_GetInterface(aWindowContext));
00178     if(!domWnd) 
00179         return NULL;
00180 
00181     CWnd *retWnd = NULL;
00182 
00183     nsCOMPtr<nsIWebBrowserChrome> chrome;
00184     if(mWWatch)
00185     {
00186         nsCOMPtr<nsIDOMWindow> fosterParent;
00187         if (!domWnd) 
00188         { // it will be a dependent window. try to find a foster parent.
00189             mWWatch->GetActiveWindow(getter_AddRefs(fosterParent));
00190             domWnd = fosterParent;
00191         }
00192         mWWatch->GetChromeForWindow(domWnd, getter_AddRefs(chrome));
00193     }
00194 
00195     if (chrome) 
00196     {
00197         nsCOMPtr<nsIEmbeddingSiteWindow> site(do_QueryInterface(chrome));
00198         if (site)
00199         {
00200             HWND w;
00201             site->GetSiteWindow(reinterpret_cast<void **>(&w));
00202             retWnd = CWnd::FromHandle(w);
00203         }
00204     }
00205 
00206     return retWnd;
00207 }
00208 
00209 // Displays the "Save To Disk" or "Open Using..." dialog box
00210 // when Gecko encounters a mime type it cannot handle
00211 //
00212 NS_IMETHODIMP CHelperAppLauncherDialog::Show(nsIHelperAppLauncher *aLauncher, 
00213                                              nsISupports *aContext,
00214                                              PRUint32 aReason)
00215 {
00216     ResourceState setState;
00217 
00218     NS_ENSURE_ARG_POINTER(aLauncher);
00219 
00220     CChooseActionDlg dlg(aLauncher, GetParentFromContext(aContext));
00221     if(dlg.DoModal() == IDCANCEL)
00222     {
00223         // User chose Cancel - just cancel the download
00224 
00225         aLauncher->Cancel(NS_BINDING_ABORTED);
00226 
00227         return NS_OK;
00228     }
00229 
00230     // User did not cancel out of the dialog box i.e. OK was chosen
00231 
00232     if(dlg.m_ActionChosen == CONTENT_SAVE_TO_DISK)
00233     {
00234         m_HandleContentOp = CONTENT_SAVE_TO_DISK;
00235 
00236         return aLauncher->SaveToDisk(nsnull, PR_FALSE);
00237     }
00238     else
00239     {
00240         m_HandleContentOp = CONTENT_LAUNCH_WITH_APP;
00241 
00242         m_FileName = dlg.m_OpenWithAppName;
00243 
00244         USES_CONVERSION;
00245         nsCAutoString fileName(T2CA(m_FileName));
00246 
00247         nsCOMPtr<nsILocalFile> openWith;
00248         nsresult rv = NS_NewNativeLocalFile(fileName, PR_FALSE, getter_AddRefs(openWith));
00249         if (NS_FAILED(rv))
00250             return aLauncher->LaunchWithApplication(nsnull, PR_FALSE);
00251         else
00252             return aLauncher->LaunchWithApplication(openWith, PR_FALSE);
00253     }
00254 }
00255 
00256 // User chose the "Save To Disk" option in the dialog before
00257 // We prompt the user for the filename to which the content
00258 // will be saved into
00259 //
00260 NS_IMETHODIMP CHelperAppLauncherDialog::PromptForSaveToFile(nsIHelperAppLauncher* aLauncher,
00261                                                              nsISupports *aWindowContext, 
00262                                                              const PRUnichar *aDefaultFile, 
00263                                                              const PRUnichar *aSuggestedFileExtension, 
00264                                                              nsILocalFile **_retval)
00265 {
00266     USES_CONVERSION;
00267 
00268     NS_ENSURE_ARG_POINTER(_retval);
00269 
00270     TCHAR *lpszFilter = _T("All Files (*.*)|*.*||");
00271     CFileDialog cf(FALSE, W2CT(aSuggestedFileExtension), W2CT(aDefaultFile),
00272                     OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
00273                     lpszFilter, GetParentFromContext(aWindowContext));
00274     if(cf.DoModal() == IDOK)
00275     {
00276         m_FileName = cf.GetPathName(); // Will be like: c:\tmp\junk.exe
00277         USES_CONVERSION;
00278         nsCAutoString fileName(T2CA(m_FileName));
00279         return NS_NewNativeLocalFile(fileName, PR_FALSE, _retval);
00280     }
00281     else
00282         return NS_ERROR_FAILURE;
00283 }
00284 
00285 //*****************************************************************************
00286 // CChooseActionDlg
00287 //***************************************************************************** 
00288 
00289 CChooseActionDlg::CChooseActionDlg(nsIHelperAppLauncher *aLauncher, CWnd* pParent /*=NULL*/)
00290     : CDialog(CChooseActionDlg::IDD, pParent)
00291 {
00292     m_HelperAppLauncher = aLauncher;
00293 }
00294 
00295 void CChooseActionDlg::DoDataExchange(CDataExchange* pDX)
00296 {
00297     CDialog::DoDataExchange(pDX);
00298 
00299     DDX_Control(pDX, IDC_CONTENT_TYPE, m_ContentType);
00300 }
00301 
00302 BOOL CChooseActionDlg::OnInitDialog() 
00303 {
00304        CDialog::OnInitDialog();
00305 
00306     // Get the mimeInfo from nsIHelperAppLauncher
00307     //
00308     nsCOMPtr<nsIMIMEInfo> mimeInfo;
00309     if(m_HelperAppLauncher)
00310         m_HelperAppLauncher->GetMIMEInfo(getter_AddRefs(mimeInfo));
00311 
00312     if(mimeInfo) 
00313     {
00314         // Retrieve and set the Mime type of the content we're downloading
00315         // in the content type field of the dialog box
00316         //
00317         nsCAutoString mimeType;
00318         nsresult rv = mimeInfo->GetMIMEType(mimeType);
00319         if(NS_SUCCEEDED(rv)) 
00320         {
00321             CStatic *pMimeType = (CStatic *)GetDlgItem(IDC_CONTENT_TYPE);
00322             if(pMimeType)
00323             {
00324                 USES_CONVERSION;
00325                 pMimeType->SetWindowText(A2CT(mimeType.get()));
00326             }
00327         }
00328 
00329         // See if we can get the preferred action from the mime info
00330         // and init the controls accordingly
00331         //
00332         InitWithPreferredAction(mimeInfo);
00333     }
00334     else
00335         SelectSaveToDiskOption();
00336     
00337     return FALSE;  // return TRUE unless you set the focus to a control
00338 }
00339 
00340 // See if we can determine the default handling action, if any,
00341 // from aMimeInfo
00342 // If not, simply select SaveToDisk as the default
00343 //
00344 void CChooseActionDlg::InitWithPreferredAction(nsIMIMEInfo* aMimeInfo)
00345 {
00346     // Retrieve and set the specified default action
00347     //
00348     nsMIMEInfoHandleAction prefAction = nsIMIMEInfo::saveToDisk;
00349     aMimeInfo->GetPreferredAction(&prefAction);
00350     if(prefAction == nsIMIMEInfo::saveToDisk)
00351     {
00352         SelectSaveToDiskOption();
00353         return;
00354     }
00355 
00356     // OpenWithApp is the preferred action - select it
00357     //
00358     SelectOpenUsingAppOption();
00359 
00360     // See if we can get the appname
00361     //
00362     nsAutoString appDesc;
00363     nsresult rv = aMimeInfo->GetApplicationDescription(appDesc);
00364     if(NS_SUCCEEDED(rv)) 
00365     {
00366         USES_CONVERSION;
00367         m_OpenWithAppName = W2CT(appDesc.get());
00368 
00369         // Update with the app name
00370         //
00371         UpdateAppNameField(m_OpenWithAppName);
00372     }
00373 }
00374 
00375 void CChooseActionDlg::UpdateAppNameField(CString& appName)
00376 {
00377     CStatic *pAppName = (CStatic *)GetDlgItem(IDC_APP_NAME);
00378     if(pAppName)
00379         pAppName->SetWindowText(appName);    
00380 }
00381 
00382 void CChooseActionDlg::SelectSaveToDiskOption()
00383 {
00384     CButton *pRadioSaveToDisk = (CButton *)GetDlgItem(IDC_SAVE_TO_DISK);
00385     if(pRadioSaveToDisk)
00386     {
00387         pRadioSaveToDisk->SetCheck(1);
00388 
00389         pRadioSaveToDisk->SetFocus();
00390 
00391         OnSaveToDiskRadioBtnClicked();
00392     }
00393 }
00394 
00395 void CChooseActionDlg::SelectOpenUsingAppOption()
00396 {
00397     CButton *pRadioOpenUsing = (CButton *)GetDlgItem(IDC_OPEN_USING);
00398     if(pRadioOpenUsing)
00399     {
00400         pRadioOpenUsing->SetCheck(1);
00401 
00402         pRadioOpenUsing->SetFocus();
00403 
00404         OnOpenUsingRadioBtnClicked();
00405     }
00406 }
00407 
00408 void CChooseActionDlg::EnableChooseBtn(BOOL bEnable)
00409 {
00410     CButton *pChooseBtn = (CButton *)GetDlgItem(IDC_CHOOSE_APP);
00411     if(pChooseBtn)
00412     {
00413         pChooseBtn->EnableWindow(bEnable);
00414     }
00415 }
00416 
00417 void CChooseActionDlg::EnableAppName(BOOL bEnable)
00418 {
00419     CStatic *pAppName = (CStatic *)GetDlgItem(IDC_APP_NAME);
00420     if(pAppName)
00421     {
00422         pAppName->EnableWindow(bEnable);
00423     }
00424 }
00425 
00426 void CChooseActionDlg::OnOpenUsingRadioBtnClicked()
00427 {
00428     EnableChooseBtn(TRUE);
00429     EnableAppName(TRUE);
00430 }
00431 
00432 void CChooseActionDlg::OnSaveToDiskRadioBtnClicked()
00433 {
00434     EnableChooseBtn(FALSE);
00435     EnableAppName(FALSE);
00436 }
00437 
00438 void CChooseActionDlg::OnChooseAppClicked() 
00439 {      
00440     TCHAR *lpszFilter =
00441         _T("EXE Files Only (*.exe)|*.exe|")
00442         _T("All Files (*.*)|*.*||");
00443 
00444     CFileDialog cf(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
00445                     lpszFilter, this);
00446     if(cf.DoModal() == IDOK)
00447     {
00448         m_OpenWithAppName = cf.GetPathName(); // Will be like: c:\tmp\junk.exe
00449 
00450         UpdateAppNameField(m_OpenWithAppName);
00451     }
00452 }
00453 
00454 void CChooseActionDlg::OnOK() 
00455 {      
00456     CButton *pRadioOpenWithApp = (CButton *)GetDlgItem(IDC_OPEN_USING);
00457 
00458     if(pRadioOpenWithApp->GetCheck())
00459     {
00460         // Do not allow to leave the dialog if the OpenWithAnApp option 
00461         // is selected and the the name of the app is unknown/empty
00462         //
00463         if(m_OpenWithAppName.IsEmpty())
00464         {
00465             ::MessageBox(this->m_hWnd,
00466                 _T("You have chosen to open the content with an external application, but,\nno application has been specified.\n\nPlease click the Choose... button to select an application"),
00467                 _T("MfcEmbed"), MB_OK);
00468             return;
00469         }
00470         else
00471             m_ActionChosen = CONTENT_LAUNCH_WITH_APP;
00472     }
00473     else
00474         m_ActionChosen = CONTENT_SAVE_TO_DISK;
00475 
00476     CDialog::OnOK();
00477 }
00478 
00479 void CChooseActionDlg::OnCancel() 
00480 {      
00481     CDialog::OnCancel();
00482 }
00483 
00484 BEGIN_MESSAGE_MAP(CChooseActionDlg, CDialog)
00485     ON_BN_CLICKED(IDC_CHOOSE_APP, OnChooseAppClicked)
00486     ON_BN_CLICKED(IDC_SAVE_TO_DISK, OnSaveToDiskRadioBtnClicked)
00487     ON_BN_CLICKED(IDC_OPEN_USING, OnOpenUsingRadioBtnClicked)
00488 END_MESSAGE_MAP()
00489 
00490 //*****************************************************************************
00491 // CProgressDlg
00492 //***************************************************************************** 
00493 
00494 NS_IMPL_ISUPPORTS2(CProgressDlg, nsIWebProgressListener, nsISupportsWeakReference)
00495 
00496 CProgressDlg::CProgressDlg(nsIHelperAppLauncher *aLauncher, int aHandleContentOp,
00497                            CString& aFileName, CWnd* pParent /*=NULL*/)
00498        : CDialog(CProgressDlg::IDD, pParent)
00499 {
00500     m_HelperAppLauncher = aLauncher;
00501     m_HandleContentOp = aHandleContentOp;
00502     m_FileName = aFileName;
00503 }
00504 
00505 CProgressDlg::~CProgressDlg() 
00506 {
00507 }
00508 
00509 NS_IMETHODIMP CProgressDlg::OnStateChange(nsIWebProgress *aWebProgress, 
00510                                           nsIRequest *aRequest, PRUint32 aStateFlags, 
00511                                           nsresult aStatus)
00512 {
00513     if((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_DOCUMENT))
00514     {
00515         // We've completed the download - close the progress window
00516         
00517         if(m_HelperAppLauncher)
00518             m_HelperAppLauncher->CloseProgressWindow();
00519 
00520         DestroyWindow();
00521     }
00522 
00523     return NS_OK;
00524 }
00525 
00526 NS_IMETHODIMP CProgressDlg::OnProgressChange(nsIWebProgress *aWebProgress, 
00527                                              nsIRequest *aRequest, 
00528                                              PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress, 
00529                                              PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
00530 {
00531     // Update the progress control
00532 
00533     if(::IsWindow(m_ProgressCtrl.m_hWnd))
00534     {
00535         m_ProgressCtrl.SetRange32(0, aMaxTotalProgress);
00536         m_ProgressCtrl.SetPos(aCurTotalProgress);
00537     }
00538 
00539     return NS_OK;
00540 }
00541 
00542 NS_IMETHODIMP CProgressDlg::OnLocationChange(nsIWebProgress *aWebProgress, 
00543                                              nsIRequest *aRequest, nsIURI *location)
00544 {
00545     return NS_OK;
00546 }
00547 
00548 NS_IMETHODIMP CProgressDlg::OnStatusChange(nsIWebProgress *aWebProgress, 
00549                                            nsIRequest *aRequest, nsresult aStatus, 
00550                                            const PRUnichar *aMessage)
00551 {
00552     return NS_OK;
00553 }
00554 
00555 NS_IMETHODIMP CProgressDlg::OnSecurityChange(nsIWebProgress *aWebProgress, 
00556                                              nsIRequest *aRequest, PRUint32 state)
00557 {
00558     return NS_OK;
00559 }
00560 
00561 BOOL CProgressDlg::OnInitDialog() 
00562 {
00563        CDialog::OnInitDialog();
00564 
00565     // Set the "SavingFrom" field
00566     if(m_HelperAppLauncher)
00567     {
00568         nsCOMPtr<nsIURI> srcUri;
00569         nsresult rv = m_HelperAppLauncher->GetSource(getter_AddRefs(srcUri));
00570         if(NS_SUCCEEDED(rv))
00571         {
00572             nsCAutoString uriString;
00573             srcUri->GetSpec(uriString);
00574             USES_CONVERSION;
00575             m_SavingFrom.SetWindowText(A2CT(uriString.get()));
00576         }
00577     }
00578 
00579     // Set the "Action" field
00580     if(m_HandleContentOp == CONTENT_SAVE_TO_DISK)
00581         m_Action.SetWindowText(_T("[Saving file to:] ") + m_FileName);
00582     else if(m_HandleContentOp == CONTENT_LAUNCH_WITH_APP)
00583         m_Action.SetWindowText(_T("[Opening file with:] ") + m_FileName);
00584 
00585     return TRUE;
00586 }
00587 
00588 void CProgressDlg::OnCancel() 
00589 {
00590     if(m_HelperAppLauncher)
00591         m_HelperAppLauncher->Cancel(NS_BINDING_ABORTED);
00592 
00593        DestroyWindow();
00594 }
00595 
00596 void CProgressDlg::DoDataExchange(CDataExchange* pDX)
00597 {
00598     CDialog::DoDataExchange(pDX);
00599 
00600     DDX_Control(pDX, IDC_PROGRESS, m_ProgressCtrl);
00601     DDX_Control(pDX, IDC_SAVING_FROM, m_SavingFrom);
00602     DDX_Control(pDX, IDC_ACTION, m_Action);
00603 }
00604 
00605 BEGIN_MESSAGE_MAP(CProgressDlg, CDialog)
00606 END_MESSAGE_MAP()