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