Back to index

lightning-sunbird  0.9+nobinonly
nsPrintDialogUtil.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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  *
00029  * ***** END LICENSE BLOCK ***** */
00030 
00031 #ifdef MOZ_REQUIRE_CURRENT_SDK
00032 #undef WINVER
00033 #define WINVER 0x0500
00034 #undef _WIN32_WINNT
00035 #define _WIN32_WINNT 0x0500
00036 #endif
00037 
00038 /* -------------------------------------------------------------------
00039 To Build This:
00040 
00041   You need to add this to the the makefile.win in mozilla/content/base/src:
00042 
00043        .\$(OBJDIR)\nsFlyOwnPrintDialog.obj       \
00044 
00045 
00046   And this to the makefile.win in mozilla/content/build:
00047 
00048 WIN_LIBS=                                       \
00049         winspool.lib                           \
00050         comctl32.lib                           \
00051         comdlg32.lib
00052 
00053 ---------------------------------------------------------------------- */
00054 
00055 #include "prmem.h"
00056 #include "plstr.h"
00057 #include <windows.h>
00058 #include <TCHAR.H>
00059 
00060 #include <unknwn.h>
00061 #include <commdlg.h>
00062 
00063 #include "nsIWebBrowserPrint.h"
00064 #include "nsString.h"
00065 #include "nsIServiceManager.h"
00066 #include "nsReadableUtils.h"
00067 #include "nsIWidget.h"
00068 #include "nsIPrintSettings.h"
00069 #include "nsIPrintSettingsWin.h"
00070 #include "nsUnitConversion.h"
00071 #include "nsIPrintOptions.h"
00072 #include "nsGfxCIID.h"
00073 #include "nsIPrefService.h"
00074 #include "nsIPrefBranch.h"
00075 
00076 static NS_DEFINE_IID(kPrinterEnumeratorCID, NS_PRINTER_ENUMERATOR_CID);
00077 
00078 #include "nsRect.h"
00079 
00080 #include "nsCRT.h"
00081 #include "prenv.h" /* for PR_GetEnv */
00082 
00083 #include <windows.h>
00084 #include <winspool.h> 
00085 
00086 // For Localization
00087 #include "nsIStringBundle.h"
00088 
00089 // This is for extending the dialog
00090 #include <dlgs.h>
00091 
00092 static NS_DEFINE_CID(kStringBundleServiceCID,  NS_STRINGBUNDLESERVICE_CID);
00093 
00094 // For PrintDlgEx
00095 // needed because there are unicode/ansi versions of this routine
00096 // and we need to make sure we get the correct one.
00097 #ifdef UNICODE
00098 #define GetPrintDlgExQuoted "PrintDlgExW"
00099 #else
00100 #define GetPrintDlgExQuoted "PrintDlgExA"
00101 #endif
00102 
00103 // Default labels for the radio buttons
00104 static const char* kAsLaidOutOnScreenStr = "As &laid out on the screen";
00105 static const char* kTheSelectedFrameStr  = "The selected &frame";
00106 static const char* kEachFrameSeparately  = "&Each frame separately";
00107 
00108 
00109 //-----------------------------------------------
00110 // Global Data
00111 //-----------------------------------------------
00112 // Identifies which new radio btn was cliked on
00113 static UINT gFrameSelectedRadioBtn = 0;
00114 
00115 // Indicates whether the native print dialog was successfully extended
00116 static PRPackedBool gDialogWasExtended     = PR_FALSE;
00117 
00118 #define PRINTDLG_PROPERTIES "chrome://global/locale/printdialog.properties"
00119 
00120 static HWND gParentWnd = NULL;
00121 
00122 //******************************************************
00123 // Define native paper sizes
00124 //******************************************************
00125 typedef struct {
00126   short  mPaperSize; // native enum
00127   double mWidth;
00128   double mHeight;
00129   PRBool mIsInches;
00130 } NativePaperSizes;
00131 
00132 // There are around 40 default print sizes defined by Windows
00133 const NativePaperSizes kPaperSizes[] = {
00134   {DMPAPER_LETTER,    8.5,   11.0,  PR_TRUE},
00135   {DMPAPER_LEGAL,     8.5,   14.0,  PR_TRUE},
00136   {DMPAPER_A4,        210.0, 297.0, PR_FALSE},
00137   {DMPAPER_TABLOID,   11.0,  17.0,  PR_TRUE},
00138   {DMPAPER_LEDGER,    17.0,  11.0,  PR_TRUE},
00139   {DMPAPER_STATEMENT, 5.5,   8.5,   PR_TRUE},
00140   {DMPAPER_EXECUTIVE, 7.25,  10.5,  PR_TRUE},
00141   {DMPAPER_A3,        297.0, 420.0, PR_FALSE},
00142   {DMPAPER_A5,        148.0, 210.0, PR_FALSE},
00143   {DMPAPER_CSHEET,    17.0,  22.0,  PR_TRUE},  
00144   {DMPAPER_DSHEET,    22.0,  34.0,  PR_TRUE},  
00145   {DMPAPER_ESHEET,    34.0,  44.0,  PR_TRUE},  
00146   {DMPAPER_LETTERSMALL, 8.5, 11.0,  PR_TRUE},  
00147   {DMPAPER_A4SMALL,   210.0, 297.0, PR_FALSE}, 
00148   {DMPAPER_B4,        250.0, 354.0, PR_FALSE}, 
00149   {DMPAPER_B5,        182.0, 257.0, PR_FALSE},
00150   {DMPAPER_FOLIO,     8.5,   13.0,  PR_TRUE},
00151   {DMPAPER_QUARTO,    215.0, 275.0, PR_FALSE},
00152   {DMPAPER_10X14,     10.0,  14.0,  PR_TRUE},
00153   {DMPAPER_11X17,     11.0,  17.0,  PR_TRUE},
00154   {DMPAPER_NOTE,      8.5,   11.0,  PR_TRUE},  
00155   {DMPAPER_ENV_9,     3.875, 8.875, PR_TRUE},  
00156   {DMPAPER_ENV_10,    40.125, 9.5,  PR_TRUE},  
00157   {DMPAPER_ENV_11,    4.5,   10.375, PR_TRUE},  
00158   {DMPAPER_ENV_12,    4.75,  11.0,  PR_TRUE},  
00159   {DMPAPER_ENV_14,    5.0,   11.5,  PR_TRUE},  
00160   {DMPAPER_ENV_DL,    110.0, 220.0, PR_FALSE}, 
00161   {DMPAPER_ENV_C5,    162.0, 229.0, PR_FALSE}, 
00162   {DMPAPER_ENV_C3,    324.0, 458.0, PR_FALSE}, 
00163   {DMPAPER_ENV_C4,    229.0, 324.0, PR_FALSE}, 
00164   {DMPAPER_ENV_C6,    114.0, 162.0, PR_FALSE}, 
00165   {DMPAPER_ENV_C65,   114.0, 229.0, PR_FALSE}, 
00166   {DMPAPER_ENV_B4,    250.0, 353.0, PR_FALSE}, 
00167   {DMPAPER_ENV_B5,    176.0, 250.0, PR_FALSE}, 
00168   {DMPAPER_ENV_B6,    176.0, 125.0, PR_FALSE}, 
00169   {DMPAPER_ENV_ITALY, 110.0, 230.0, PR_FALSE}, 
00170   {DMPAPER_ENV_MONARCH,  3.875,  7.5, PR_TRUE},  
00171   {DMPAPER_ENV_PERSONAL, 3.625,  6.5, PR_TRUE},  
00172   {DMPAPER_FANFOLD_US,   14.875, 11.0, PR_TRUE},  
00173   {DMPAPER_FANFOLD_STD_GERMAN, 8.5, 12.0, PR_TRUE},  
00174   {DMPAPER_FANFOLD_LGL_GERMAN, 8.5, 13.0, PR_TRUE},  
00175 };
00176 const PRInt32 kNumPaperSizes = 41;
00177 
00178 //----------------------------------------------------------------------------------
00179 static PRBool 
00180 CheckForExtendedDialog()
00181 {
00182 #ifdef MOZ_REQUIRE_CURRENT_SDK
00183   HMODULE lib = GetModuleHandle("comdlg32.dll");
00184   if ( lib ) {
00185     return GetProcAddress(lib, GetPrintDlgExQuoted);
00186   }
00187 #endif
00188   return PR_FALSE;
00189 }
00190 
00191 //----------------------------------------------------------------------------------
00192 // Map an incoming size to a Windows Native enum in the DevMode
00193 static void 
00194 MapPaperSizeToNativeEnum(LPDEVMODE aDevMode,
00195                          PRInt16   aType, 
00196                          double    aW, 
00197                          double    aH)
00198 {
00199 
00200 #ifdef DEBUG_rods
00201   BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
00202   BOOL doingPaperSize   = aDevMode->dmFields & DM_PAPERSIZE;
00203   BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
00204   BOOL doingPaperWidth  = aDevMode->dmFields & DM_PAPERWIDTH;
00205 #endif
00206 
00207   const double kThreshold = 0.05;
00208   PRBool foundEnum = PR_FALSE;
00209   for (PRInt32 i=0;i<kNumPaperSizes;i++) {
00210     double width  = kPaperSizes[i].mWidth;
00211     double height = kPaperSizes[i].mHeight;
00212     if (aW < width+kThreshold && aW > width-kThreshold && 
00213         aH < height+kThreshold && aH > height-kThreshold) {
00214       aDevMode->dmPaperSize = kPaperSizes[i].mPaperSize;
00215       aDevMode->dmFields &= ~DM_PAPERLENGTH;
00216       aDevMode->dmFields &= ~DM_PAPERWIDTH;
00217       aDevMode->dmFields |= DM_PAPERSIZE;
00218       return;
00219     }
00220   }
00221 
00222   short width  = 0;
00223   short height = 0;
00224   if (aType == nsIPrintSettings::kPaperSizeInches) {
00225     width  = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aW))) / 10);
00226     height = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aH))) / 10);
00227 
00228   } else if (aType == nsIPrintSettings::kPaperSizeMillimeters) {
00229     width  = short(aW / 10.0);
00230     height = short(aH / 10.0);
00231   } else {
00232     return; // don't set anything
00233   }
00234 
00235   // width and height is in 
00236   aDevMode->dmPaperSize   = 0;
00237   aDevMode->dmPaperWidth  = width;
00238   aDevMode->dmPaperLength = height;
00239 
00240   aDevMode->dmFields |= DM_PAPERSIZE;
00241   aDevMode->dmFields |= DM_PAPERLENGTH;
00242   aDevMode->dmFields |= DM_PAPERWIDTH;
00243 }
00244 
00245 //----------------------------------------------------------------------------------
00246 // Setup Paper Size & Orientation options into the DevMode
00247 // 
00248 static void 
00249 SetupDevModeFromSettings(LPDEVMODE aDevMode, nsIPrintSettings* aPrintSettings)
00250 {
00251   // Setup paper size
00252   if (aPrintSettings) {
00253     PRInt16 type;
00254     aPrintSettings->GetPaperSizeType(&type);
00255     if (type == nsIPrintSettings::kPaperSizeNativeData) {
00256       PRInt16 paperEnum;
00257       aPrintSettings->GetPaperData(&paperEnum);
00258       aDevMode->dmPaperSize = paperEnum;
00259       aDevMode->dmFields &= ~DM_PAPERLENGTH;
00260       aDevMode->dmFields &= ~DM_PAPERWIDTH;
00261       aDevMode->dmFields |= DM_PAPERSIZE;
00262     } else {
00263       PRInt16 unit;
00264       double width, height;
00265       aPrintSettings->GetPaperSizeUnit(&unit);
00266       aPrintSettings->GetPaperWidth(&width);
00267       aPrintSettings->GetPaperHeight(&height);
00268       MapPaperSizeToNativeEnum(aDevMode, unit, width, height);
00269     }
00270 
00271     // Setup Orientation
00272     PRInt32 orientation;
00273     aPrintSettings->GetOrientation(&orientation);
00274     aDevMode->dmOrientation = orientation == nsIPrintSettings::kPortraitOrientation?DMORIENT_PORTRAIT:DMORIENT_LANDSCAPE;
00275     aDevMode->dmFields |= DM_ORIENTATION;
00276 
00277     // Setup Number of Copies
00278     PRInt32 copies;
00279     aPrintSettings->GetNumCopies(&copies);
00280     aDevMode->dmCopies = copies;
00281     aDevMode->dmFields |= DM_COPIES;
00282 
00283   }
00284 
00285 }
00286 
00287 //----------------------------------------------------------------------------------
00288 // Helper Function - Free and reallocate the string
00289 static nsresult 
00290 SetPrintSettingsFromDevMode(nsIPrintSettings* aPrintSettings, 
00291                             LPDEVMODE         aDevMode)
00292 {
00293   if (aPrintSettings == nsnull) {
00294     return NS_ERROR_FAILURE;
00295   }
00296 
00297   if (aDevMode->dmFields & DM_ORIENTATION) {
00298     PRInt32 orientation  = aDevMode->dmOrientation == DMORIENT_PORTRAIT?
00299                            nsIPrintSettings::kPortraitOrientation:nsIPrintSettings::kLandscapeOrientation;
00300     aPrintSettings->SetOrientation(orientation);
00301   }
00302 
00303   // Setup Number of Copies
00304   if (aDevMode->dmFields & DM_COPIES) {
00305     aPrintSettings->SetNumCopies(PRInt32(aDevMode->dmCopies));
00306   }
00307 
00308   // Scaling
00309   // Since we do the scaling, grab their value and reset back to 100
00310   if (aDevMode->dmFields & DM_SCALE) {
00311     double origScale = 1.0;
00312     aPrintSettings->GetScaling(&origScale);
00313     double scale = double(aDevMode->dmScale) / 100.0f;
00314     if (origScale == 1.0 || scale != 1.0) {
00315       aPrintSettings->SetScaling(scale);
00316     }
00317     aDevMode->dmScale = 100;
00318     // To turn this on you must change where the mPrt->mShrinkToFit is being set in the DocumentViewer
00319     //aPrintSettings->SetShrinkToFit(PR_FALSE);
00320   }
00321 
00322   if (aDevMode->dmFields & DM_PAPERSIZE) {
00323     aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeNativeData);
00324     aPrintSettings->SetPaperData(aDevMode->dmPaperSize);
00325 
00326   } else if (aDevMode->dmFields & DM_PAPERLENGTH && aDevMode->dmFields & DM_PAPERWIDTH) {
00327     PRBool found = PR_FALSE;
00328     for (PRInt32 i=0;i<kNumPaperSizes;i++) {
00329       if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
00330         aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeDefined);
00331         aPrintSettings->SetPaperWidth(kPaperSizes[i].mWidth);
00332         aPrintSettings->SetPaperHeight(kPaperSizes[i].mHeight);
00333         aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches?nsIPrintSettings::kPaperSizeInches:nsIPrintSettings::kPaperSizeInches);
00334         found = PR_TRUE;
00335         break;
00336       }
00337     }
00338     if (!found) {
00339       return NS_ERROR_FAILURE;
00340     }
00341   } else {
00342     return NS_ERROR_FAILURE;
00343   }
00344   return NS_OK;
00345 }
00346 
00347 //----------------------------------------------------------------------------------
00348 // Return localized bundle for resource strings
00349 static nsresult
00350 GetLocalizedBundle(const char * aPropFileName, nsIStringBundle** aStrBundle)
00351 {
00352   NS_ENSURE_ARG_POINTER(aPropFileName);
00353   NS_ENSURE_ARG_POINTER(aStrBundle);
00354 
00355   nsresult rv;
00356   nsCOMPtr<nsIStringBundle> bundle;
00357   
00358 
00359   // Create bundle
00360   nsCOMPtr<nsIStringBundleService> stringService = 
00361     do_GetService(kStringBundleServiceCID, &rv);
00362   if (NS_SUCCEEDED(rv) && stringService) {
00363     rv = stringService->CreateBundle(aPropFileName, aStrBundle);
00364   }
00365   
00366   return rv;
00367 }
00368 
00369 //--------------------------------------------------------
00370 // Return localized string 
00371 static nsresult
00372 GetLocalizedString(nsIStringBundle* aStrBundle, const char* aKey, nsString& oVal)
00373 {
00374   NS_ENSURE_ARG_POINTER(aStrBundle);
00375   NS_ENSURE_ARG_POINTER(aKey);
00376 
00377   // Determine default label from string bundle
00378   nsXPIDLString valUni;
00379   nsAutoString key; 
00380   key.AssignWithConversion(aKey);
00381   nsresult rv = aStrBundle->GetStringFromName(key.get(), getter_Copies(valUni));
00382   if (NS_SUCCEEDED(rv) && valUni) {
00383     oVal.Assign(valUni);
00384   } else {
00385     oVal.Truncate();
00386   }
00387   return rv;
00388 }
00389 
00390 //--------------------------------------------------------
00391 static char* 
00392 GetACPString(const nsAString& aStr)
00393 {
00394    int acplen = aStr.Length() * 2 + 1;
00395    char * acp = new char[acplen];
00396    if(acp)
00397    {
00398       int outlen = ::WideCharToMultiByte( CP_ACP, 0, 
00399                       PromiseFlatString(aStr).get(), aStr.Length(),
00400                       acp, acplen, NULL, NULL);
00401       if ( outlen > 0)
00402          acp[outlen] = '\0';  // null terminate
00403    }
00404    return acp;
00405 }
00406 
00407 //--------------------------------------------------------
00408 // Set a multi-byte string in the control
00409 static void SetTextOnWnd(HWND aControl, const nsString& aStr)
00410 {
00411   char* pStr = GetACPString(aStr);
00412   if (pStr) {
00413     ::SetWindowText(aControl, pStr);
00414     delete [] pStr;
00415   }
00416 }
00417 
00418 //--------------------------------------------------------
00419 // Will get the control and localized string by "key"
00420 static void SetText(HWND             aParent, 
00421                     UINT             aId, 
00422                     nsIStringBundle* aStrBundle,
00423                     const char*      aKey) 
00424 {
00425   HWND wnd = GetDlgItem (aParent, aId);
00426   if (!wnd) {
00427     return;
00428   }
00429   nsAutoString str;
00430   nsresult rv = GetLocalizedString(aStrBundle, aKey, str);
00431   if (NS_SUCCEEDED(rv)) {
00432     SetTextOnWnd(wnd, str);
00433   }
00434 }
00435 
00436 //--------------------------------------------------------
00437 static void SetRadio(HWND         aParent, 
00438                      UINT         aId, 
00439                      PRBool       aIsSet,
00440                      PRBool       isEnabled = PR_TRUE) 
00441 {
00442   HWND wnd = ::GetDlgItem (aParent, aId);
00443   if (!wnd) {
00444     return;
00445   }
00446   if (!isEnabled) {
00447     ::EnableWindow(wnd, FALSE);
00448     return;
00449   }
00450   ::EnableWindow(wnd, TRUE);
00451   ::SendMessage(wnd, BM_SETCHECK, (WPARAM)aIsSet, (LPARAM)0);
00452 }
00453 
00454 //--------------------------------------------------------
00455 static void SetRadioOfGroup(HWND aDlg, int aRadId)
00456 {
00457   int radioIds[] = {rad4, rad5, rad6};
00458   int numRads = 3;
00459 
00460   for (int i=0;i<numRads;i++) {
00461     HWND radWnd = ::GetDlgItem(aDlg, radioIds[i]);
00462     if (radWnd != NULL) {
00463       ::SendMessage(radWnd, BM_SETCHECK, (WPARAM)(radioIds[i] == aRadId), (LPARAM)0);
00464     }
00465   }
00466 }
00467 
00468 //--------------------------------------------------------
00469 typedef struct {
00470   char * mKeyStr;
00471   long   mKeyId;
00472 } PropKeyInfo;
00473 
00474 // These are the control ids used in the dialog and 
00475 // defined by MS-Windows in commdlg.h
00476 static PropKeyInfo gAllPropKeys[] = {
00477     {"PrintFrames", grp3},
00478     {"Aslaid", rad4},
00479     {"selectedframe", rad5},
00480     {"Eachframe", rad6},
00481     {NULL, NULL}};
00482 
00483 //--------------------------------------------------------
00484 //--------------------------------------------------------
00485 //--------------------------------------------------------
00486 //--------------------------------------------------------
00487 // Get the absolute coords of the child windows relative
00488 // to its parent window
00489 static void GetLocalRect(HWND aWnd, RECT& aRect, HWND aParent)
00490 {
00491   RECT wr;
00492   ::GetWindowRect(aParent, &wr);
00493 
00494   RECT cr;
00495   ::GetClientRect(aParent, &cr);
00496 
00497   ::GetWindowRect(aWnd, &aRect);
00498 
00499   int borderH = (wr.bottom-wr.top+1) - (cr.bottom-cr.top+1);
00500   int borderW = ((wr.right-wr.left+1) - (cr.right-cr.left+1))/2;
00501   aRect.top    -= wr.top+borderH-borderW;
00502   aRect.left   -= wr.left+borderW;
00503   aRect.right  -= wr.left+borderW;
00504   aRect.bottom -= wr.top+borderH-borderW;
00505 }
00506 
00507 //--------------------------------------------------------
00508 // Show or Hide the control
00509 static void Show(HWND aWnd, PRBool bState)
00510 {
00511   if (aWnd) {
00512     ::ShowWindow(aWnd, bState?SW_SHOW:SW_HIDE);
00513   }
00514 }
00515 
00516 //--------------------------------------------------------
00517 // Create a child window "control"
00518 static HWND CreateControl(LPCTSTR          aType,
00519                           DWORD            aStyle,
00520                           HINSTANCE        aHInst, 
00521                           HWND             aHdlg, 
00522                           int              aId, 
00523                           const nsAString& aStr, 
00524                           const nsRect&    aRect)
00525 {
00526   char* pStr = GetACPString(aStr);
00527   if (pStr == NULL) return NULL;
00528 
00529   HWND hWnd = ::CreateWindow (aType, pStr,
00530                               WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | aStyle,
00531                               aRect.x, aRect.y, aRect.width, aRect.height,
00532                               (HWND)aHdlg, (HMENU)aId,
00533                               aHInst, NULL);
00534   delete [] pStr;
00535 
00536   if (hWnd == NULL) return NULL;
00537 
00538   // get the native font for the dialog and 
00539   // set it into the new control
00540   HFONT hFont = (HFONT)::SendMessage(aHdlg, WM_GETFONT, (WPARAM)0, (LPARAM)0);
00541   if (hFont != NULL) {
00542     ::SendMessage(hWnd, WM_SETFONT, (WPARAM) hFont, (LPARAM)0);
00543   }
00544   return hWnd;
00545 }
00546 
00547 //--------------------------------------------------------
00548 // Create a Radio Button
00549 static HWND CreateRadioBtn(HINSTANCE        aHInst, 
00550                            HWND             aHdlg, 
00551                            int              aId, 
00552                            const char*      aStr, 
00553                            const nsRect&    aRect)
00554 {
00555   nsString cStr;
00556   cStr.AssignWithConversion(aStr);
00557   return CreateControl("BUTTON", BS_RADIOBUTTON, aHInst, aHdlg, aId, cStr, aRect);
00558 }
00559 
00560 //--------------------------------------------------------
00561 // Create a Group Box
00562 static HWND CreateGroupBox(HINSTANCE        aHInst, 
00563                            HWND             aHdlg, 
00564                            int              aId, 
00565                            const nsAString& aStr, 
00566                            const nsRect&    aRect)
00567 {
00568   return CreateControl("BUTTON", BS_GROUPBOX, aHInst, aHdlg, aId, aStr, aRect);
00569 }
00570 
00571 //--------------------------------------------------------
00572 // Localizes and initializes the radio buttons and group
00573 static void InitializeExtendedDialog(HWND hdlg, PRInt16 aHowToEnableFrameUI) 
00574 {
00575   // Localize the new controls in the print dialog
00576   nsCOMPtr<nsIStringBundle> strBundle;
00577   if (NS_SUCCEEDED(GetLocalizedBundle(PRINTDLG_PROPERTIES, getter_AddRefs(strBundle)))) {
00578     PRInt32 i = 0;
00579     while (gAllPropKeys[i].mKeyStr != NULL) {
00580       SetText(hdlg, gAllPropKeys[i].mKeyId, strBundle, gAllPropKeys[i].mKeyStr);
00581       i++;
00582     }
00583   }
00584 
00585   // Set up radio buttons
00586   if (aHowToEnableFrameUI == nsIPrintSettings::kFrameEnableAll) {
00587     SetRadio(hdlg, rad4, PR_FALSE);  
00588     SetRadio(hdlg, rad5, PR_TRUE); 
00589     SetRadio(hdlg, rad6, PR_FALSE);
00590     // set default so user doesn't have to actually press on it
00591     gFrameSelectedRadioBtn = rad5;
00592 
00593   } else if (aHowToEnableFrameUI == nsIPrintSettings::kFrameEnableAsIsAndEach) {
00594     SetRadio(hdlg, rad4, PR_FALSE);  
00595     SetRadio(hdlg, rad5, PR_FALSE, PR_FALSE); 
00596     SetRadio(hdlg, rad6, PR_TRUE);
00597     // set default so user doesn't have to actually press on it
00598     gFrameSelectedRadioBtn = rad6;
00599 
00600 
00601   } else {  // nsIPrintSettings::kFrameEnableNone
00602     // we are using this function to disabe the group box
00603     SetRadio(hdlg, grp3, PR_FALSE, PR_FALSE); 
00604     // now disable radiobuttons
00605     SetRadio(hdlg, rad4, PR_FALSE, PR_FALSE); 
00606     SetRadio(hdlg, rad5, PR_FALSE, PR_FALSE); 
00607     SetRadio(hdlg, rad6, PR_FALSE, PR_FALSE); 
00608   }
00609 
00610 }
00611 
00612 
00613 //--------------------------------------------------------
00614 // Special Hook Procedure for handling the print dialog messages
00615 static UINT CALLBACK PrintHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) 
00616 {
00617 
00618   if (uiMsg == WM_COMMAND) {
00619     UINT id = LOWORD(wParam);
00620     if (id == rad4 || id == rad5 || id == rad6) {
00621       gFrameSelectedRadioBtn = id;
00622       SetRadioOfGroup(hdlg, id);
00623     }
00624 
00625   } else if (uiMsg == WM_INITDIALOG) {
00626     PRINTDLG * printDlg = (PRINTDLG *)lParam;
00627     if (printDlg == NULL) return 0L;
00628 
00629     PRInt16 howToEnableFrameUI = (PRInt16)printDlg->lCustData;
00630 
00631     HINSTANCE hInst = (HINSTANCE)::GetWindowLong(hdlg, GWL_HINSTANCE);
00632     if (hInst == NULL) return 0L;
00633 
00634     // Start by getting the local rects of several of the controls
00635     // so we can calculate where the new controls are
00636     HWND wnd = ::GetDlgItem(hdlg, grp1);
00637     if (wnd == NULL) return 0L;
00638     RECT dlgRect;
00639     GetLocalRect(wnd, dlgRect, hdlg);
00640 
00641     wnd = ::GetDlgItem(hdlg, rad1); // this is the top control "All"
00642     if (wnd == NULL) return 0L;
00643     RECT rad1Rect;
00644     GetLocalRect(wnd, rad1Rect, hdlg);
00645 
00646     wnd = ::GetDlgItem(hdlg, rad2); // this is the bottom control "Selection"
00647     if (wnd == NULL) return 0L;
00648     RECT rad2Rect;
00649     GetLocalRect(wnd, rad2Rect, hdlg);
00650 
00651     wnd = ::GetDlgItem(hdlg, rad3); // this is the middle control "Pages"
00652     if (wnd == NULL) return 0L;
00653     RECT rad3Rect;
00654     GetLocalRect(wnd, rad3Rect, hdlg);
00655 
00656     HWND okWnd = ::GetDlgItem(hdlg, IDOK);
00657     if (okWnd == NULL) return 0L;
00658     RECT okRect;
00659     GetLocalRect(okWnd, okRect, hdlg);
00660 
00661     wnd = ::GetDlgItem(hdlg, grp4); // this is the "Print range" groupbox
00662     if (wnd == NULL) return 0L;
00663     RECT prtRect;
00664     GetLocalRect(wnd, prtRect, hdlg);
00665 
00666 
00667     // calculate various different "gaps" for layout purposes
00668 
00669     int rbGap     = rad3Rect.top - rad1Rect.bottom;     // gap between radiobtns
00670     int grpBotGap = dlgRect.bottom - rad2Rect.bottom;   // gap from bottom rb to bottom of grpbox
00671     int grpGap    = dlgRect.top - prtRect.bottom ;      // gap between group boxes
00672     int top       = dlgRect.bottom + grpGap;            
00673     int radHgt    = rad1Rect.bottom - rad1Rect.top + 1; // top of new group box
00674     int y         = top+(rad1Rect.top-dlgRect.top);     // starting pos of first radio
00675     int rbWidth   = dlgRect.right - rad1Rect.left - 5;  // measure from rb left to the edge of the groupbox
00676                                                         // (5 is arbitrary)
00677     nsRect rect;
00678 
00679     // Create and position the radio buttons
00680     //
00681     // If any one control cannot be created then 
00682     // hide the others and bail out
00683     //
00684     rect.SetRect(rad1Rect.left, y, rbWidth,radHgt);
00685     HWND rad4Wnd = CreateRadioBtn(hInst, hdlg, rad4, kAsLaidOutOnScreenStr, rect);
00686     if (rad4Wnd == NULL) return 0L;
00687     y += radHgt + rbGap;
00688 
00689     rect.SetRect(rad1Rect.left, y, rbWidth, radHgt);
00690     HWND rad5Wnd = CreateRadioBtn(hInst, hdlg, rad5, kTheSelectedFrameStr, rect);
00691     if (rad5Wnd == NULL) {
00692       Show(rad4Wnd, FALSE); // hide
00693       return 0L;
00694     }
00695     y += radHgt + rbGap;
00696 
00697     rect.SetRect(rad1Rect.left, y, rbWidth, radHgt);
00698     HWND rad6Wnd = CreateRadioBtn(hInst, hdlg, rad6, kEachFrameSeparately, rect);
00699     if (rad6Wnd == NULL) {
00700       Show(rad4Wnd, FALSE); // hide
00701       Show(rad5Wnd, FALSE); // hide
00702       return 0L;
00703     }
00704     y += radHgt + grpBotGap;
00705 
00706     // Create and position the group box
00707     rect.SetRect (dlgRect.left, top, dlgRect.right-dlgRect.left+1, y-top+1);
00708     HWND grpBoxWnd = CreateGroupBox(hInst, hdlg, grp3, NS_LITERAL_STRING("Print Frame"), rect);
00709     if (grpBoxWnd == NULL) {
00710       Show(rad4Wnd, FALSE); // hide
00711       Show(rad5Wnd, FALSE); // hide
00712       Show(rad6Wnd, FALSE); // hide
00713       return 0L;
00714     }
00715 
00716     // Here we figure out the old height of the dlg
00717     // then figure it's gap from the old grpbx to the bottom
00718     // then size the dlg
00719     RECT pr, cr; 
00720     ::GetWindowRect(hdlg, &pr);
00721     ::GetClientRect(hdlg, &cr);
00722 
00723     int dlgHgt = (cr.bottom - cr.top) + 1;
00724     int bottomGap = dlgHgt - okRect.bottom;
00725     pr.bottom += (dlgRect.bottom-dlgRect.top) + grpGap + 1 - (dlgHgt-dlgRect.bottom) + bottomGap;
00726 
00727     ::SetWindowPos(hdlg, NULL, pr.left, pr.top, pr.right-pr.left+1, pr.bottom-pr.top+1, 
00728                    SWP_NOMOVE|SWP_NOREDRAW|SWP_NOZORDER);
00729 
00730     // figure out the new height of the dialog
00731     ::GetClientRect(hdlg, &cr);
00732     dlgHgt = (cr.bottom - cr.top) + 1;
00733  
00734     // Reposition the OK and Cancel btns
00735     int okHgt = okRect.bottom - okRect.top + 1;
00736     ::SetWindowPos(okWnd, NULL, okRect.left, dlgHgt-bottomGap-okHgt, 0, 0, 
00737                    SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER);
00738 
00739     HWND cancelWnd = ::GetDlgItem(hdlg, IDCANCEL);
00740     if (cancelWnd == NULL) return 0L;
00741 
00742     RECT cancelRect;
00743     GetLocalRect(cancelWnd, cancelRect, hdlg);
00744     int cancelHgt = cancelRect.bottom - cancelRect.top + 1;
00745     ::SetWindowPos(cancelWnd, NULL, cancelRect.left, dlgHgt-bottomGap-cancelHgt, 0, 0, 
00746                    SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER);
00747 
00748     // localize and initialize the groupbox and radiobuttons
00749     InitializeExtendedDialog(hdlg, howToEnableFrameUI);
00750 
00751     // Looks like we were able to extend the dialog
00752     gDialogWasExtended = PR_TRUE;
00753   }
00754   return 0L;
00755 }
00756 
00757 //----------------------------------------------------------------------------------
00758 // Returns a Global Moveable Memory Handle to a DevMode
00759 // from the Printer byt the name of aPrintName
00760 static HGLOBAL CreateGlobalDevModeAndInit(LPTSTR aPrintName, nsIPrintSettings* aPS)
00761 {
00762   HGLOBAL hGlobalDevMode = NULL;
00763 
00764   nsresult rv = NS_ERROR_FAILURE;
00765   HANDLE hPrinter = NULL;
00766   BOOL status = ::OpenPrinter(aPrintName, &hPrinter, NULL);
00767   if (status) {
00768 
00769     LPDEVMODE   pNewDevMode;
00770     DWORD       dwNeeded, dwRet;
00771 
00772     nsString prtName;
00773 #ifdef UNICODE
00774     prtName.AppendWithConversion((PRUnichar *)aPrintName);
00775 #else 
00776     prtName.AssignWithConversion((char*)aPrintName);
00777 #endif
00778 
00779     // Allocate a buffer of the correct size.
00780     dwNeeded = ::DocumentProperties(gParentWnd, hPrinter, aPrintName, NULL, NULL, 0);
00781 
00782     pNewDevMode = (LPDEVMODE)malloc(dwNeeded);
00783     if (!pNewDevMode) return NULL;
00784 
00785     hGlobalDevMode = (HGLOBAL)::GlobalAlloc(GHND, dwNeeded);
00786     if (!hGlobalDevMode) {
00787       free(pNewDevMode);
00788     }
00789 
00790     dwRet = ::DocumentProperties(gParentWnd, hPrinter, aPrintName, pNewDevMode, NULL, DM_OUT_BUFFER);
00791 
00792     if (dwRet != IDOK) {
00793       free(pNewDevMode);
00794       ::GlobalFree(hGlobalDevMode);
00795       ::ClosePrinter(hPrinter);
00796       return NULL;
00797     }
00798 
00799     // Lock memory and copy contents from DEVMODE (current printer)
00800     // to Global Memory DEVMODE
00801     LPDEVMODE devMode = (DEVMODE *)::GlobalLock(hGlobalDevMode);
00802     if (devMode) {
00803       memcpy(devMode, pNewDevMode, dwNeeded);
00804       // Initialize values from the PrintSettings
00805       SetupDevModeFromSettings(devMode, aPS);
00806       ::GlobalUnlock(hGlobalDevMode);
00807     } else {
00808       ::GlobalFree(hGlobalDevMode);
00809       hGlobalDevMode = NULL;
00810     }
00811 
00812     free(pNewDevMode);
00813 
00814     ::ClosePrinter(hPrinter);
00815 
00816   } else {
00817     return NULL;
00818   }
00819 
00820   return hGlobalDevMode;
00821 }
00822 
00823 //------------------------------------------------------------------
00824 // helper
00825 static PRUnichar * GetDefaultPrinterNameFromGlobalPrinters()
00826 {
00827   nsresult rv;
00828   PRUnichar * printerName = nsnull;
00829   nsCOMPtr<nsIPrinterEnumerator> prtEnum = do_GetService(kPrinterEnumeratorCID, &rv);
00830   if (prtEnum) {
00831     prtEnum->GetDefaultPrinterName(&printerName);
00832   }
00833   return printerName;
00834 }
00835 
00836 // Determine whether we have a completely native dialog
00837 // or whether we cshould extend it
00838 static PRBool ShouldExtendPrintDialog()
00839 {
00840   nsresult rv;
00841   nsCOMPtr<nsIPrefService> prefs =
00842     do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
00843   NS_ENSURE_SUCCESS(rv, PR_TRUE);
00844   nsCOMPtr<nsIPrefBranch> prefBranch;
00845   rv = prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
00846   NS_ENSURE_SUCCESS(rv, PR_TRUE);
00847 
00848   PRBool result;
00849   rv = prefBranch->GetBoolPref("print.extend_native_print_dialog", &result);
00850   NS_ENSURE_SUCCESS(rv, PR_TRUE);
00851   return result;
00852 }
00853 
00854 //------------------------------------------------------------------
00855 // Displays the native Print Dialog
00856 static nsresult 
00857 ShowNativePrintDialog(HWND              aHWnd,
00858                       nsIPrintSettings* aPrintSettings)
00859 {
00860   //NS_ENSURE_ARG_POINTER(aHWnd);
00861   NS_ENSURE_ARG_POINTER(aPrintSettings);
00862 
00863   nsresult  rv = NS_ERROR_FAILURE;
00864   gDialogWasExtended  = PR_FALSE;
00865 
00866   HGLOBAL hGlobalDevMode = NULL;
00867   HGLOBAL hDevNames      = NULL;
00868 
00869   // Get the Print Name to be used
00870   PRUnichar * printerName;
00871   aPrintSettings->GetPrinterName(&printerName);
00872 
00873   // If there is no name then use the default printer
00874   if (!printerName || (printerName && !*printerName)) {
00875     printerName = GetDefaultPrinterNameFromGlobalPrinters();
00876   }
00877 
00878   NS_ASSERTION(printerName, "We have to have a printer name");
00879   if (!printerName) return NS_ERROR_FAILURE;
00880 
00881   // Now create a DEVNAMES struct so the the dialog is initialized correctly.
00882   PRUint32 len = nsCRT::strlen(printerName);
00883   hDevNames = (HGLOBAL)::GlobalAlloc(GHND, len+sizeof(DEVNAMES)+1);
00884   DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames);
00885   pDevNames->wDriverOffset = sizeof(DEVNAMES);
00886   pDevNames->wDeviceOffset = sizeof(DEVNAMES);
00887   pDevNames->wOutputOffset = sizeof(DEVNAMES)+len+1;
00888   pDevNames->wDefault      = 0;
00889   char* device = &(((char*)pDevNames)[pDevNames->wDeviceOffset]);
00890   strcpy(device, NS_ConvertUCS2toUTF8(printerName).get());
00891   ::GlobalUnlock(hDevNames);
00892 
00893   // Create a Moveable Memory Object that holds a new DevMode
00894   // from the Printer Name
00895   // The PRINTDLG.hDevMode requires that it be a moveable memory object
00896   // NOTE: We only need to free hGlobalDevMode when the dialog is cancelled
00897   // When the user prints, it comes back in the printdlg struct and 
00898   // is used and cleaned up later
00899 #ifdef UNICODE
00900   hGlobalDevMode = CreateGlobalDevModeAndInit(printerName, aPrintSettings);
00901 #else 
00902   hGlobalDevMode = CreateGlobalDevModeAndInit(NS_CONST_CAST(char*, NS_ConvertUCS2toUTF8(printerName).get()), aPrintSettings);
00903 #endif
00904 
00905   // Prepare to Display the Print Dialog
00906   PRINTDLG  prntdlg;
00907   memset(&prntdlg, 0, sizeof(PRINTDLG));
00908 
00909   prntdlg.lStructSize = sizeof(prntdlg);
00910   prntdlg.hwndOwner   = aHWnd;
00911   prntdlg.hDevMode    = hGlobalDevMode;
00912   prntdlg.hDevNames   = hDevNames;
00913   prntdlg.hDC         = NULL;
00914   prntdlg.Flags       = PD_ALLPAGES | PD_RETURNIC | PD_HIDEPRINTTOFILE | PD_USEDEVMODECOPIESANDCOLLATE;
00915 
00916   // if there is a current selection then enable the "Selection" radio button
00917   PRInt16 howToEnableFrameUI = nsIPrintSettings::kFrameEnableNone;
00918   PRBool isOn;
00919   aPrintSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &isOn);
00920   if (!isOn) {
00921     prntdlg.Flags |= PD_NOSELECTION;
00922   }
00923   aPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI);
00924 
00925   prntdlg.nFromPage           = 0xFFFF;
00926   prntdlg.nToPage             = 0xFFFF;
00927   prntdlg.nMinPage            = 1;
00928   prntdlg.nMaxPage            = 0xFFFF;
00929   prntdlg.nCopies             = 1;
00930   prntdlg.lpfnSetupHook       = NULL;
00931   prntdlg.lpSetupTemplateName = NULL;
00932   prntdlg.hPrintTemplate      = NULL;
00933   prntdlg.hSetupTemplate      = NULL;
00934 
00935   prntdlg.hInstance           = NULL;
00936   prntdlg.lpPrintTemplateName = NULL;
00937 
00938   if (!ShouldExtendPrintDialog()) {
00939     prntdlg.lCustData         = NULL;
00940     prntdlg.lpfnPrintHook     = NULL;
00941   } else {
00942     // Set up print dialog "hook" procedure for extending the dialog
00943     prntdlg.lCustData         = (DWORD)howToEnableFrameUI;
00944     prntdlg.lpfnPrintHook     = (LPPRINTHOOKPROC)PrintHookProc;
00945     prntdlg.Flags            |= PD_ENABLEPRINTHOOK;
00946   }
00947 
00948   BOOL result = ::PrintDlg(&prntdlg);
00949 
00950   if (TRUE == result) {
00951     if (aPrintSettings && prntdlg.hDevMode != NULL) {
00952       // Transfer the settings from the native data to the PrintSettings
00953       LPDEVMODE devMode = (LPDEVMODE)::GlobalLock(prntdlg.hDevMode);
00954       SetPrintSettingsFromDevMode(aPrintSettings, devMode);
00955       ::GlobalUnlock(prntdlg.hDevMode);
00956     }
00957     DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(prntdlg.hDevNames);
00958     if ( NULL != devnames ) {
00959 
00960       char* device = &(((char *)devnames)[devnames->wDeviceOffset]);
00961       char* driver = &(((char *)devnames)[devnames->wDriverOffset]);
00962 
00963       nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
00964       // Setup local Data members
00965       psWin->SetDeviceName(device);
00966       psWin->SetDriverName(driver);
00967 
00968 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
00969       printf("printer: driver %s, device %s  flags: %d\n", driver, device, prntdlg.Flags);
00970 #endif
00971       // fill the print options with the info from the dialog
00972       if (aPrintSettings != nsnull) {
00973         nsString printerName;
00974         printerName.AssignWithConversion(device);
00975 
00976         aPrintSettings->SetPrinterName(printerName.get());
00977 
00978         if (prntdlg.Flags & PD_SELECTION) {
00979           aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSelection);
00980 
00981         } else if (prntdlg.Flags & PD_PAGENUMS) {
00982           aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSpecifiedPageRange);
00983           aPrintSettings->SetStartPageRange(prntdlg.nFromPage);
00984           aPrintSettings->SetEndPageRange(prntdlg.nToPage);
00985 
00986         } else { // (prntdlg.Flags & PD_ALLPAGES)
00987           aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages);
00988         }
00989 
00990         if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) {
00991           // make sure the dialog got extended
00992           if (gDialogWasExtended) {
00993             // check to see about the frame radio buttons
00994             switch (gFrameSelectedRadioBtn) {
00995               case rad4: 
00996                 aPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
00997                 break;
00998               case rad5: 
00999                 aPrintSettings->SetPrintFrameType(nsIPrintSettings::kSelectedFrame);
01000                 break;
01001               case rad6: 
01002                 aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
01003                 break;
01004             } // switch
01005           } else {
01006             // if it didn't get extended then have it default to printing
01007             // each frame separately
01008             aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
01009           }
01010         } else {
01011           aPrintSettings->SetPrintFrameType(nsIPrintSettings::kNoFrames);
01012         }
01013       }
01014       ::GlobalUnlock(prntdlg.hDevNames);
01015 
01016 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
01017     PRBool  printSelection = prntdlg.Flags & PD_SELECTION;
01018     PRBool  printAllPages  = prntdlg.Flags & PD_ALLPAGES;
01019     PRBool  printNumPages  = prntdlg.Flags & PD_PAGENUMS;
01020     PRInt32 fromPageNum    = 0;
01021     PRInt32 toPageNum      = 0;
01022 
01023     if (printNumPages) {
01024       fromPageNum = prntdlg.nFromPage;
01025       toPageNum   = prntdlg.nToPage;
01026     } 
01027     if (printSelection) {
01028       printf("Printing the selection\n");
01029 
01030     } else if (printAllPages) {
01031       printf("Printing all the pages\n");
01032 
01033     } else {
01034       printf("Printing from page no. %d to %d\n", fromPageNum, toPageNum);
01035     }
01036 #endif
01037     
01038       LPDEVMODE devMode = (LPDEVMODE)::GlobalLock(prntdlg.hDevMode);
01039       psWin->SetDevMode(devMode);
01040       SetPrintSettingsFromDevMode(aPrintSettings, devMode);
01041       ::GlobalUnlock(prntdlg.hDevMode);
01042 
01043     }
01044   } else {
01045     aPrintSettings->SetIsCancelled(PR_TRUE);
01046     ::GlobalFree(hGlobalDevMode);
01047     return NS_ERROR_ABORT;
01048   }
01049 
01050   return NS_OK;
01051 }
01052 
01053 
01054 #ifdef MOZ_REQUIRE_CURRENT_SDK
01055 //------------------------------------------------------------------
01056 // Callback for Property Sheet
01057 static BOOL APIENTRY PropSheetCallBack(HWND hdlg, UINT uiMsg, UINT wParam, LONG lParam)
01058 {
01059   if (uiMsg == WM_COMMAND) {
01060     UINT id = LOWORD(wParam);
01061     if (id == rad4 || id == rad5 || id == rad6) {
01062       gFrameSelectedRadioBtn = id;
01063       SetRadioOfGroup(hdlg, id);
01064     }
01065 
01066   } else if (uiMsg == WM_INITDIALOG) {
01067     // Create the groupbox and Radiobuttons on the "Options" Property Sheet
01068 
01069     // We temporarily borrowed the global value for initialization
01070     // now clear it before the dialog appears
01071     PRInt16 howToEnableFrameUI = gFrameSelectedRadioBtn;
01072     gFrameSelectedRadioBtn     = 0;
01073 
01074     HINSTANCE hInst = (HINSTANCE)::GetWindowLong(hdlg, GWL_HINSTANCE);
01075     if (hInst == NULL) return 0L;
01076 
01077     // Get default font for the dialog & then its font metrics
01078     // we need the text height to determine the height of the radio buttons
01079     TEXTMETRIC metrics;
01080     HFONT hFont = (HFONT)::SendMessage(hdlg, WM_GETFONT, (WPARAM)0, (LPARAM)0);
01081     HDC localDC = ::GetDC(hdlg);
01082     ::SelectObject(localDC, (HGDIOBJ)hFont);
01083     ::GetTextMetrics(localDC, &metrics);
01084     ::ReleaseDC(hdlg, localDC);
01085 
01086     // calculate various different "gaps" for layout purposes
01087      RECT dlgr; 
01088     ::GetWindowRect(hdlg, &dlgr);
01089 
01090     int horzGap    = 5;                                 // generic horz gap
01091     int vertGap    = 5;                                 // generic vert gap
01092     int rbGap      = metrics.tmHeight / 2;               // gap between radiobtns
01093     int top        = vertGap*2;                            // start at the top
01094     int radHgt     = metrics.tmHeight;                   // top of new group box
01095     int y          = top;                                // starting pos of first radio
01096     int x          = horzGap*2;
01097     int rbWidth    = dlgr.right - dlgr.left - (5*horzGap);  
01098     int grpWidth   = dlgr.right - dlgr.left - (2*horzGap);  
01099 
01100     nsRect rect;
01101 
01102     // Create and position the radio buttons
01103     //
01104     // If any one control cannot be created then 
01105     // hide the others and bail out
01106     //
01107     x += horzGap*2;
01108     y += vertGap + metrics.tmHeight;
01109     rect.SetRect(x, y, rbWidth,radHgt);
01110     HWND rad4Wnd = CreateRadioBtn(hInst, hdlg, rad4, kAsLaidOutOnScreenStr, rect);
01111     if (rad4Wnd == NULL) return 0L;
01112     y += radHgt + rbGap;
01113 
01114     rect.SetRect(x, y, rbWidth, radHgt);
01115     HWND rad5Wnd = CreateRadioBtn(hInst, hdlg, rad5, kTheSelectedFrameStr, rect);
01116     if (rad5Wnd == NULL) {
01117       Show(rad4Wnd, FALSE); // hide
01118       return 0L;
01119     }
01120     y += radHgt + rbGap;
01121 
01122     rect.SetRect(x, y, rbWidth, radHgt);
01123     HWND rad6Wnd = CreateRadioBtn(hInst, hdlg, rad6, kEachFrameSeparately, rect);
01124     if (rad6Wnd == NULL) {
01125       Show(rad4Wnd, FALSE); // hide
01126       Show(rad5Wnd, FALSE); // hide
01127       return 0L;
01128     }
01129     y += radHgt + (vertGap*2);
01130 
01131     x -= horzGap*2;
01132     // Create and position the group box
01133     rect.SetRect (x, top, grpWidth, y-top+1);
01134     HWND grpBoxWnd = CreateGroupBox(hInst, hdlg, grp3, NS_LITERAL_STRING("Print Frame"), rect);
01135     if (grpBoxWnd == NULL) {
01136       Show(rad4Wnd, FALSE); // hide
01137       Show(rad5Wnd, FALSE); // hide
01138       Show(rad6Wnd, FALSE); // hide
01139       return 0L;
01140     }
01141 
01142     // localize and initialize the groupbox and radiobuttons
01143     InitializeExtendedDialog(hdlg, howToEnableFrameUI);
01144 
01145     // Looks like we were able to extend the dialog
01146     gDialogWasExtended = PR_TRUE;
01147   }
01148   return 0L;
01149 }
01150 
01151 //------------------------------------------------------------------
01152 // Creates the "Options" Property Sheet
01153 static HPROPSHEETPAGE ExtendPrintDialog(HWND aHWnd, char* aTitle)
01154 {
01155   // The resource "OPTPROPSHEET" comes out of the widget/build/widget.rc file
01156   HINSTANCE hInst = (HINSTANCE)::GetWindowLong(aHWnd, GWL_HINSTANCE);
01157   PROPSHEETPAGE psp;
01158   memset(&psp, 0, sizeof(PROPSHEETPAGE));
01159   psp.dwSize      = sizeof(PROPSHEETPAGE);
01160   psp.dwFlags     = PSP_USETITLE | PSP_PREMATURE;
01161   psp.hInstance   = hInst;
01162   psp.pszTemplate = "OPTPROPSHEET";
01163   psp.pfnDlgProc  = PropSheetCallBack;
01164   psp.pszTitle    = aTitle?aTitle:"Options";
01165 
01166   HPROPSHEETPAGE newPropSheet = ::CreatePropertySheetPage(&psp);
01167   return newPropSheet;
01168 
01169 }
01170 
01171 //------------------------------------------------------------------
01172 // Displays the native Print Dialog
01173 static nsresult 
01174 ShowNativePrintDialogEx(HWND              aHWnd,
01175                         nsIPrintSettings* aPrintSettings)
01176 {
01177   NS_ENSURE_ARG_POINTER(aHWnd);
01178   NS_ENSURE_ARG_POINTER(aPrintSettings);
01179 
01180   nsresult  rv = NS_ERROR_FAILURE;
01181   gDialogWasExtended  = PR_FALSE;
01182 
01183   // Create a Moveable Memory Object that holds a new DevMode
01184   // from the Printer Name
01185   // The PRINTDLG.hDevMode requires that it be a moveable memory object
01186   // NOTE: We only need to free hGlobalDevMode when the dialog is cancelled
01187   // When the user prints, it comes back in the printdlg struct and 
01188   // is used and cleaned up later
01189   PRUnichar * printerName;
01190   aPrintSettings->GetPrinterName(&printerName);
01191   HGLOBAL hGlobalDevMode = NULL;
01192   if (printerName) {
01193 #ifdef UNICODE
01194     hGlobalDevMode = CreateGlobalDevModeAndInit(printerName, aPrintSettings);
01195 #else 
01196     hGlobalDevMode = CreateGlobalDevModeAndInit(NS_CONST_CAST(char*, NS_ConvertUCS2toUTF8(printerName).get()), aPrintSettings);
01197 #endif
01198   }
01199 
01200   // Prepare to Display the Print Dialog
01201   PRINTDLGEX  prntdlg;
01202   memset(&prntdlg, 0, sizeof(PRINTDLGEX));
01203 
01204   prntdlg.lStructSize = sizeof(prntdlg);
01205   prntdlg.hwndOwner   = aHWnd;
01206   prntdlg.hDevMode    = hGlobalDevMode;
01207   prntdlg.Flags       = PD_ALLPAGES | PD_RETURNDC | PD_HIDEPRINTTOFILE | PD_USEDEVMODECOPIESANDCOLLATE |
01208                         PD_NOCURRENTPAGE;
01209   prntdlg.nStartPage  = START_PAGE_GENERAL;
01210 
01211   // if there is a current selection then enable the "Selection" radio button
01212   PRInt16 howToEnableFrameUI = nsIPrintSettings::kFrameEnableNone;
01213   if (aPrintSettings != nsnull) {
01214     PRBool isOn;
01215     aPrintSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &isOn);
01216     if (!isOn) {
01217       prntdlg.Flags |= PD_NOSELECTION;
01218     }
01219     aPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI);
01220   }
01221 
01222   // At the moment we can only support one page range
01223   // from all the documentation I can find, it appears that this 
01224   // will get cleanup automatically when the struct goes away
01225   const int kNumPageRanges     = 1;
01226   LPPRINTPAGERANGE pPageRanges = (LPPRINTPAGERANGE) GlobalAlloc(GPTR, kNumPageRanges * sizeof(PRINTPAGERANGE));
01227   if (!pPageRanges)
01228       return E_OUTOFMEMORY;
01229 
01230   prntdlg.nPageRanges    = 0;
01231   prntdlg.nMaxPageRanges = kNumPageRanges;
01232   prntdlg.lpPageRanges   = pPageRanges;
01233   prntdlg.nMinPage       = 1;
01234   prntdlg.nMaxPage       = 0xFFFF;
01235   prntdlg.nCopies        = 1;
01236 
01237   if (ShouldExtendPrintDialog()) {
01238     // lLcalize the Property Sheet (Tab) title
01239     char* pTitle = NULL;
01240     nsString optionsStr;
01241     if (NS_SUCCEEDED(GetLocalizedString(strBundle, "options", optionsStr))) {
01242       pTitle = GetACPString(optionsStr);
01243     }
01244 
01245     // Temporarily borrow this variable for setting up the radiobuttons
01246     // if we don't use this, we will need to define a new global var
01247     gFrameSelectedRadioBtn = howToEnableFrameUI;
01248     HPROPSHEETPAGE psp[1];
01249     psp[0] = ExtendPrintDialog(aHWnd, pTitle);
01250     prntdlg.nPropertyPages      = 1;
01251     prntdlg.lphPropertyPages    = psp;
01252   }
01253 
01254   HRESULT result = ::PrintDlgEx(&prntdlg);
01255 
01256   if (S_OK == result && (prntdlg.dwResultAction == PD_RESULT_PRINT)) {
01257     if (aPrintSettings && prntdlg.hDevMode != NULL) {
01258       LPDEVMODE devMode = (LPDEVMODE)::GlobalLock(prntdlg.hDevMode);
01259       SetPrintSettingsFromDevMode(aPrintSettings, devMode);
01260       ::GlobalUnlock(prntdlg.hDevMode);
01261     }
01262     DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(prntdlg.hDevNames);
01263     if ( NULL != devnames ) {
01264 
01265       char* device = &(((char *)devnames)[devnames->wDeviceOffset]);
01266       char* driver = &(((char *)devnames)[devnames->wDriverOffset]);
01267 
01268       nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
01269       // Setup local Data members
01270       psWin->SetDeviceName(device);
01271       psWin->SetDriverName(driver);
01272 
01273 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
01274       printf("printer: driver %s, device %s  flags: %d\n", driver, device, prntdlg.Flags);
01275 #endif
01276       ::GlobalUnlock(prntdlg.hDevNames);
01277 
01278       // fill the print options with the info from the dialog
01279       if (aPrintSettings != nsnull) {
01280 
01281         if (prntdlg.Flags & PD_SELECTION) {
01282           aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSelection);
01283 
01284         } else if (prntdlg.Flags & PD_PAGENUMS) {
01285           aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSpecifiedPageRange);
01286           aPrintSettings->SetStartPageRange(pPageRanges->nFromPage);
01287           aPrintSettings->SetEndPageRange(pPageRanges->nToPage);
01288 
01289         } else { // (prntdlg.Flags & PD_ALLPAGES)
01290           aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages);
01291         }
01292 
01293         if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) {
01294           // make sure the dialog got extended
01295           if (gDialogWasExtended) {
01296             // check to see about the frame radio buttons
01297             switch (gFrameSelectedRadioBtn) {
01298               case rad4: 
01299                 aPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
01300                 break;
01301               case rad5: 
01302                 aPrintSettings->SetPrintFrameType(nsIPrintSettings::kSelectedFrame);
01303                 break;
01304               case rad6: 
01305                 aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
01306                 break;
01307             } // switch
01308           } else {
01309             // if it didn't get extended then have it default to printing
01310             // each frame separately
01311             aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
01312           }
01313         } else {
01314           aPrintSettings->SetPrintFrameType(nsIPrintSettings::kNoFrames);
01315         }
01316       }
01317 
01318 
01319 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
01320     PRBool  printSelection = prntdlg.Flags & PD_SELECTION;
01321     PRBool  printAllPages  = prntdlg.Flags & PD_ALLPAGES;
01322     PRBool  printNumPages  = prntdlg.Flags & PD_PAGENUMS;
01323     PRInt32 fromPageNum    = 0;
01324     PRInt32 toPageNum      = 0;
01325 
01326     if (printNumPages) {
01327       fromPageNum = pPageRanges->nFromPage;
01328       toPageNum   = pPageRanges->nToPage;
01329     } 
01330     if (printSelection) {
01331       printf("Printing the selection\n");
01332 
01333     } else if (printAllPages) {
01334       printf("Printing all the pages\n");
01335 
01336     } else {
01337       printf("Printing from page no. %d to %d\n", fromPageNum, toPageNum);
01338     }
01339 #endif
01340     
01341     LPDEVMODE devMode = (LPDEVMODE)::GlobalLock(prntdlg.hDevMode);
01342     psWin->SetDevMode(devMode);
01343     SetPrintSettingsFromDevMode(aPrintSettings, devMode);
01344     ::GlobalUnlock(prntdlg.hDevMode);
01345 
01346     }
01347   } else {
01348     if (hGlobalDevMode) ::GlobalFree(hGlobalDevMode);
01349     return NS_ERROR_ABORT;
01350   }
01351 
01352   ::GlobalFree(pPageRanges);
01353 
01354   return NS_OK;
01355 }
01356 #endif // MOZ_REQUIRE_CURRENT_SDK
01357 
01358 //------------------------------------------------------------------
01359 static void 
01360 PrepareForPrintDialog(nsIWebBrowserPrint* aWebBrowserPrint, nsIPrintSettings* aPS)
01361 {
01362   NS_ASSERTION(aWebBrowserPrint, "Can't be null");
01363   NS_ASSERTION(aPS, "Can't be null");
01364 
01365   PRBool isFramesetDocument;
01366   PRBool isFramesetFrameSelected;
01367   PRBool isIFrameSelected;
01368   PRBool isRangeSelection;
01369 
01370   aWebBrowserPrint->GetIsFramesetDocument(&isFramesetDocument);
01371   aWebBrowserPrint->GetIsFramesetFrameSelected(&isFramesetFrameSelected);
01372   aWebBrowserPrint->GetIsIFrameSelected(&isIFrameSelected);
01373   aWebBrowserPrint->GetIsRangeSelection(&isRangeSelection);
01374 
01375   // Setup print options for UI
01376   if (isFramesetDocument) {
01377     if (isFramesetFrameSelected) {
01378       aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll);
01379     } else {
01380       aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach);
01381     }
01382   } else {
01383     aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone);
01384   }
01385 
01386   // Now determine how to set up the Frame print UI
01387   aPS->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, isRangeSelection || isIFrameSelected);
01388 
01389 }
01390 
01391 //----------------------------------------------------------------------------------
01392 //-- Show Print Dialog
01393 //----------------------------------------------------------------------------------
01394 nsresult NativeShowPrintDialog(HWND                aHWnd,
01395                                nsIWebBrowserPrint* aWebBrowserPrint,
01396                                nsIPrintSettings*   aPrintSettings)
01397 {
01398   nsresult rv = NS_ERROR_FAILURE;
01399 
01400   PrepareForPrintDialog(aWebBrowserPrint, aPrintSettings);
01401 
01402 #ifdef MOZ_REQUIRE_CURRENT_SDK
01403   if (CheckForExtendedDialog()) {
01404     rv = ShowNativePrintDialogEx(aHWnd, aPrintSettings);
01405   } else {
01406     rv = ShowNativePrintDialog(aHWnd, aPrintSettings);
01407   }
01408 #else
01409   rv = ShowNativePrintDialog(aHWnd, aPrintSettings);
01410 #endif
01411 
01412   return rv;
01413 }
01414