/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/ArrayUtils.h"

#include "nsPrintDialogX.h"
#include "nsIPrintSettings.h"
#include "nsIPrintSettingsService.h"
#include "nsPrintSettingsX.h"
#include "nsCOMPtr.h"
#include "nsQueryObject.h"
#include "nsServiceManagerUtils.h"
#include "nsIWebProgressListener.h"
#include "nsIStringBundle.h"
#include "nsIWebBrowserPrint.h"
#include "nsCRT.h"

#import <Cocoa/Cocoa.h>
#include "nsObjCExceptions.h"

using namespace mozilla;

NS_IMPL_ISUPPORTS(nsPrintDialogServiceX, nsIPrintDialogService)

nsPrintDialogServiceX::nsPrintDialogServiceX()
{
}

nsPrintDialogServiceX::~nsPrintDialogServiceX()
{
}

NS_IMETHODIMP
nsPrintDialogServiceX::Init()
{
  return NS_OK;
}

NS_IMETHODIMP
nsPrintDialogServiceX::Show(nsPIDOMWindowOuter *aParent, nsIPrintSettings *aSettings,
                            nsIWebBrowserPrint *aWebBrowserPrint)
{
  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;

  NS_PRECONDITION(aSettings, "aSettings must not be null");

  RefPtr<nsPrintSettingsX> settingsX(do_QueryObject(aSettings));
  if (!settingsX)
    return NS_ERROR_FAILURE;

  nsCOMPtr<nsIPrintSettingsService> printSettingsSvc
    = do_GetService("@mozilla.org/gfx/printsettings-service;1");

  // Set the print job title
  char16_t** docTitles;
  uint32_t titleCount;
  nsresult rv = aWebBrowserPrint->EnumerateDocumentNames(&titleCount, &docTitles);
  if (NS_SUCCEEDED(rv) && titleCount > 0) {
    CFStringRef cfTitleString = CFStringCreateWithCharacters(NULL, reinterpret_cast<const UniChar*>(docTitles[0]),
                                                             NS_strlen(docTitles[0]));
    if (cfTitleString) {
      ::PMPrintSettingsSetJobName(settingsX->GetPMPrintSettings(), cfTitleString);
      CFRelease(cfTitleString);
    }
    for (int32_t i = titleCount - 1; i >= 0; i--) {
      free(docTitles[i]);
    }
    free(docTitles);
    docTitles = NULL;
    titleCount = 0;
  }

  // Read default print settings from prefs
  printSettingsSvc->InitPrintSettingsFromPrefs(settingsX, true,
    nsIPrintSettings::kInitSaveNativeData);
  NSPrintInfo* printInfo = settingsX->GetCocoaPrintInfo();

  // Put the print info into the current print operation, since that's where
  // [panel runModal] will look for it. We create the view because otherwise
  // we'll get unrelated warnings printed to the console.
  NSView* tmpView = [[NSView alloc] init];
  NSPrintOperation* printOperation = [NSPrintOperation printOperationWithView:tmpView printInfo:printInfo];
  [NSPrintOperation setCurrentOperation:printOperation];

  NSPrintPanel* panel = [NSPrintPanel printPanel];
  [panel setOptions:NSPrintPanelShowsCopies
    | NSPrintPanelShowsPageRange
    | NSPrintPanelShowsPaperSize
    | NSPrintPanelShowsOrientation
    | NSPrintPanelShowsScaling ];
  PrintPanelAccessoryController* viewController =
    [[PrintPanelAccessoryController alloc] initWithSettings:aSettings];
  [panel addAccessoryController:viewController];
  [viewController release];

  // Show the dialog.
  nsCocoaUtils::PrepareForNativeAppModalDialog();
  int button = [panel runModal];
  nsCocoaUtils::CleanUpAfterNativeAppModalDialog();

  NSPrintInfo* copy = [[[NSPrintOperation currentOperation] printInfo] copy];
  if (!copy) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  [NSPrintOperation setCurrentOperation:nil];
  [tmpView release];

  if (button != NSFileHandlingPanelOKButton)
    return NS_ERROR_ABORT;

  settingsX->SetCocoaPrintInfo(copy);
  settingsX->InitUnwriteableMargin();

  // Save settings unless saving is pref'd off
  if (Preferences::GetBool("print.save_print_settings", false)) {
    printSettingsSvc->SavePrintSettingsToPrefs(settingsX, true,
      nsIPrintSettings::kInitSaveNativeData);
  }

  // Get coordinate space resolution for converting paper size units to inches
  NSWindow *win = [[NSApplication sharedApplication] mainWindow];
  if (win) {
    NSDictionary *devDesc = [win deviceDescription];
    if (devDesc) {
      NSSize res = [[devDesc objectForKey: NSDeviceResolution] sizeValue];
      float scale = [win backingScaleFactor];
      if (scale > 0) {
        settingsX->SetInchesScale(res.width / scale, res.height / scale);
      }
    }
  }

  // Export settings.
  [viewController exportSettings];

  // If "ignore scaling" is checked, overwrite scaling factor with 1.
  bool isShrinkToFitChecked;
  settingsX->GetShrinkToFit(&isShrinkToFitChecked);
  if (isShrinkToFitChecked) {
    NSMutableDictionary* dict = [copy dictionary];
    if (dict) {
      [dict setObject: [NSNumber numberWithFloat: 1]
               forKey: NSPrintScalingFactor];
    }
    // Set the scaling factor to 100% in the NSPrintInfo
    // object so that it will not affect the paper size
    // retrieved from the PMPageFormat routines.
    [copy setScalingFactor:1.0];
  } else {
    aSettings->SetScaling([copy scalingFactor]);
  }

  // Set the adjusted paper size now that we've updated
  // the scaling factor.
  settingsX->InitAdjustedPaperSize();

  [copy release];

  int16_t pageRange;
  aSettings->GetPrintRange(&pageRange);
  if (pageRange != nsIPrintSettings::kRangeSelection) {
    PMPrintSettings nativePrintSettings = settingsX->GetPMPrintSettings();
    UInt32 firstPage, lastPage;
    OSStatus status = ::PMGetFirstPage(nativePrintSettings, &firstPage);
    if (status == noErr) {
      status = ::PMGetLastPage(nativePrintSettings, &lastPage);
      if (status == noErr && lastPage != UINT32_MAX) {
        aSettings->SetPrintRange(nsIPrintSettings::kRangeSpecifiedPageRange);
        aSettings->SetStartPageRange(firstPage);
        aSettings->SetEndPageRange(lastPage);
      }
    }
  }

  return NS_OK;

  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}

NS_IMETHODIMP
nsPrintDialogServiceX::ShowPageSetup(nsPIDOMWindowOuter *aParent,
                                     nsIPrintSettings *aNSSettings)
{
  NS_PRECONDITION(aParent, "aParent must not be null");
  NS_PRECONDITION(aNSSettings, "aSettings must not be null");
  NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);

  RefPtr<nsPrintSettingsX> settingsX(do_QueryObject(aNSSettings));
  if (!settingsX)
    return NS_ERROR_FAILURE;

  NSPrintInfo* printInfo = settingsX->GetCocoaPrintInfo();
  NSPageLayout *pageLayout = [NSPageLayout pageLayout];
  nsCocoaUtils::PrepareForNativeAppModalDialog();
  int button = [pageLayout runModalWithPrintInfo:printInfo];
  nsCocoaUtils::CleanUpAfterNativeAppModalDialog();

  return button == NSFileHandlingPanelOKButton ? NS_OK : NS_ERROR_ABORT;
}

// Accessory view

@interface PrintPanelAccessoryView (Private)

- (NSString*)localizedString:(const char*)aKey;

- (int16_t)chosenFrameSetting;

- (const char*)headerFooterStringForList:(NSPopUpButton*)aList;

- (void)exportHeaderFooterSettings;

- (void)initBundle;

- (NSTextField*)label:(const char*)aLabel
            withFrame:(NSRect)aRect
            alignment:(NSTextAlignment)aAlignment;

- (void)addLabel:(const char*)aLabel
       withFrame:(NSRect)aRect
       alignment:(NSTextAlignment)aAlignment;

- (void)addLabel:(const char*)aLabel withFrame:(NSRect)aRect;

- (void)addCenteredLabel:(const char*)aLabel withFrame:(NSRect)aRect;

- (NSButton*)checkboxWithLabel:(const char*)aLabel andFrame:(NSRect)aRect;

- (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
                                   selectedItem:(const char16_t*)aCurrentString;

- (void)addOptionsSection;

- (void)addAppearanceSection;

- (void)addFramesSection;

- (void)addHeaderFooterSection;

- (NSString*)summaryValueForCheckbox:(NSButton*)aCheckbox;

- (NSString*)framesSummaryValue;

- (NSString*)headerSummaryValue;

- (NSString*)footerSummaryValue;

@end

static const char sHeaderFooterTags[][4] =  {"", "&T", "&U", "&D", "&P", "&PT"};

@implementation PrintPanelAccessoryView

// Public methods

- (id)initWithSettings:(nsIPrintSettings*)aSettings
{
  [super initWithFrame:NSMakeRect(0, 0, 540, 270)];

  mSettings = aSettings;
  [self initBundle];
  [self addOptionsSection];
  [self addAppearanceSection];
  [self addFramesSection];
  [self addHeaderFooterSection];

  return self;
}

- (void)exportSettings
{
  mSettings->SetPrintRange([mPrintSelectionOnlyCheckbox state] == NSOnState ?
                             (int16_t)nsIPrintSettings::kRangeSelection :
                             (int16_t)nsIPrintSettings::kRangeAllPages);
  mSettings->SetShrinkToFit([mShrinkToFitCheckbox state] == NSOnState);
  mSettings->SetPrintBGColors([mPrintBGColorsCheckbox state] == NSOnState);
  mSettings->SetPrintBGImages([mPrintBGImagesCheckbox state] == NSOnState);
  mSettings->SetPrintFrameType([self chosenFrameSetting]);

  [self exportHeaderFooterSettings];
}

- (void)dealloc
{
  NS_IF_RELEASE(mPrintBundle);
  [super dealloc];
}

// Localization

- (void)initBundle
{
  nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
  bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", &mPrintBundle);
}

- (NSString*)localizedString:(const char*)aKey
{
  if (!mPrintBundle)
    return @"";

  nsXPIDLString intlString;
  mPrintBundle->GetStringFromName(NS_ConvertUTF8toUTF16(aKey).get(), getter_Copies(intlString));
  NSMutableString* s = [NSMutableString stringWithUTF8String:NS_ConvertUTF16toUTF8(intlString).get()];

  // Remove all underscores (they're used in the GTK dialog for accesskeys).
  [s replaceOccurrencesOfString:@"_" withString:@"" options:0 range:NSMakeRange(0, [s length])];
  return s;
}

// Widget helpers

- (NSTextField*)label:(const char*)aLabel
            withFrame:(NSRect)aRect
            alignment:(NSTextAlignment)aAlignment
{
  NSTextField* label = [[[NSTextField alloc] initWithFrame:aRect] autorelease];
  [label setStringValue:[self localizedString:aLabel]];
  [label setEditable:NO];
  [label setSelectable:NO];
  [label setBezeled:NO];
  [label setBordered:NO];
  [label setDrawsBackground:NO];
  [label setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
  [label setAlignment:aAlignment];
  return label;
}

- (void)addLabel:(const char*)aLabel
       withFrame:(NSRect)aRect
       alignment:(NSTextAlignment)aAlignment
{
  NSTextField* label = [self label:aLabel withFrame:aRect alignment:aAlignment];
  [self addSubview:label];
}

- (void)addLabel:(const char*)aLabel withFrame:(NSRect)aRect
{
  [self addLabel:aLabel withFrame:aRect alignment:NSRightTextAlignment];
}

- (void)addCenteredLabel:(const char*)aLabel withFrame:(NSRect)aRect
{
  [self addLabel:aLabel withFrame:aRect alignment:NSCenterTextAlignment];
}

- (NSButton*)checkboxWithLabel:(const char*)aLabel andFrame:(NSRect)aRect
{
  aRect.origin.y += 4.0f;
  NSButton* checkbox = [[[NSButton alloc] initWithFrame:aRect] autorelease];
  [checkbox setButtonType:NSSwitchButton];
  [checkbox setTitle:[self localizedString:aLabel]];
  [checkbox setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
  [checkbox sizeToFit];
  return checkbox;
}

- (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
                                   selectedItem:(const char16_t*)aCurrentString
{
  NSPopUpButton* list = [[[NSPopUpButton alloc] initWithFrame:aRect pullsDown:NO] autorelease];
  [list setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
  [[list cell] setControlSize:NSSmallControlSize];
  NSArray* items =
    [NSArray arrayWithObjects:[self localizedString:"headerFooterBlank"],
                              [self localizedString:"headerFooterTitle"],
                              [self localizedString:"headerFooterURL"],
                              [self localizedString:"headerFooterDate"],
                              [self localizedString:"headerFooterPage"],
                              [self localizedString:"headerFooterPageTotal"],
                              nil];
  [list addItemsWithTitles:items];

  NS_ConvertUTF16toUTF8 currentStringUTF8(aCurrentString);
  for (unsigned int i = 0; i < ArrayLength(sHeaderFooterTags); i++) {
    if (!strcmp(currentStringUTF8.get(), sHeaderFooterTags[i])) {
      [list selectItemAtIndex:i];
      break;
    }
  }

  return list;
}

// Build sections

- (void)addOptionsSection
{
  // Title
  [self addLabel:"optionsTitleMac" withFrame:NSMakeRect(0, 240, 151, 22)];

  // "Print Selection Only"
  mPrintSelectionOnlyCheckbox = [self checkboxWithLabel:"selectionOnly"
                                               andFrame:NSMakeRect(156, 240, 0, 0)];

  bool canPrintSelection;
  mSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB,
                             &canPrintSelection);
  [mPrintSelectionOnlyCheckbox setEnabled:canPrintSelection];

  int16_t printRange;
  mSettings->GetPrintRange(&printRange);
  if (printRange == nsIPrintSettings::kRangeSelection) {
    [mPrintSelectionOnlyCheckbox setState:NSOnState];
  }

  [self addSubview:mPrintSelectionOnlyCheckbox];

  // "Shrink To Fit"
  mShrinkToFitCheckbox = [self checkboxWithLabel:"shrinkToFit"
                                        andFrame:NSMakeRect(156, 218, 0, 0)];

  bool shrinkToFit;
  mSettings->GetShrinkToFit(&shrinkToFit);
  [mShrinkToFitCheckbox setState:(shrinkToFit ? NSOnState : NSOffState)];

  [self addSubview:mShrinkToFitCheckbox];
}

- (void)addAppearanceSection
{
  // Title
  [self addLabel:"appearanceTitleMac" withFrame:NSMakeRect(0, 188, 151, 22)];

  // "Print Background Colors"
  mPrintBGColorsCheckbox = [self checkboxWithLabel:"printBGColors"
                                          andFrame:NSMakeRect(156, 188, 0, 0)];

  bool geckoBool;
  mSettings->GetPrintBGColors(&geckoBool);
  [mPrintBGColorsCheckbox setState:(geckoBool ? NSOnState : NSOffState)];

  [self addSubview:mPrintBGColorsCheckbox];

  // "Print Background Images"
  mPrintBGImagesCheckbox = [self checkboxWithLabel:"printBGImages"
                                          andFrame:NSMakeRect(156, 166, 0, 0)];

  mSettings->GetPrintBGImages(&geckoBool);
  [mPrintBGImagesCheckbox setState:(geckoBool ? NSOnState : NSOffState)];

  [self addSubview:mPrintBGImagesCheckbox];
}

- (void)addFramesSection
{
  // Title
  [self addLabel:"framesTitleMac" withFrame:NSMakeRect(0, 124, 151, 22)];

  // Radio matrix
  NSButtonCell *radio = [[NSButtonCell alloc] init];
  [radio setButtonType:NSRadioButton];
  [radio setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
  NSMatrix *matrix = [[NSMatrix alloc] initWithFrame:NSMakeRect(156, 81, 400, 66)
                                                mode:NSRadioModeMatrix
                                           prototype:(NSCell*)radio
                                        numberOfRows:3
                                     numberOfColumns:1];
  [radio release];
  [matrix setCellSize:NSMakeSize(400, 21)];
  [self addSubview:matrix];
  [matrix release];
  NSArray *cellArray = [matrix cells];
  mAsLaidOutRadio = [cellArray objectAtIndex:0];
  mSelectedFrameRadio = [cellArray objectAtIndex:1];
  mSeparateFramesRadio = [cellArray objectAtIndex:2];
  [mAsLaidOutRadio setTitle:[self localizedString:"asLaidOut"]];
  [mSelectedFrameRadio setTitle:[self localizedString:"selectedFrame"]];
  [mSeparateFramesRadio setTitle:[self localizedString:"separateFrames"]];

  // Radio enabled state
  int16_t frameUIFlag;
  mSettings->GetHowToEnableFrameUI(&frameUIFlag);
  if (frameUIFlag == nsIPrintSettings::kFrameEnableNone) {
    [mAsLaidOutRadio setEnabled:NO];
    [mSelectedFrameRadio setEnabled:NO];
    [mSeparateFramesRadio setEnabled:NO];
  } else if (frameUIFlag == nsIPrintSettings::kFrameEnableAsIsAndEach) {
    [mSelectedFrameRadio setEnabled:NO];
  }

  // Radio values
  int16_t printFrameType;
  mSettings->GetPrintFrameType(&printFrameType);
  switch (printFrameType) {
    case nsIPrintSettings::kFramesAsIs:
      [mAsLaidOutRadio setState:NSOnState];
      break;
    case nsIPrintSettings::kSelectedFrame:
      [mSelectedFrameRadio setState:NSOnState];
      break;
    case nsIPrintSettings::kEachFrameSep:
      [mSeparateFramesRadio setState:NSOnState];
      break;
  }
}

- (void)addHeaderFooterSection
{
  // Labels
  [self addLabel:"pageHeadersTitleMac" withFrame:NSMakeRect(0, 44, 151, 22)];
  [self addLabel:"pageFootersTitleMac" withFrame:NSMakeRect(0, 0, 151, 22)];
  [self addCenteredLabel:"left" withFrame:NSMakeRect(156, 22, 100, 22)];
  [self addCenteredLabel:"center" withFrame:NSMakeRect(256, 22, 100, 22)];
  [self addCenteredLabel:"right" withFrame:NSMakeRect(356, 22, 100, 22)];

  // Lists
  nsXPIDLString sel;

  mSettings->GetHeaderStrLeft(getter_Copies(sel));
  mHeaderLeftList = [self headerFooterItemListWithFrame:NSMakeRect(156, 44, 100, 22)
                                           selectedItem:sel];
  [self addSubview:mHeaderLeftList];

  mSettings->GetHeaderStrCenter(getter_Copies(sel));
  mHeaderCenterList = [self headerFooterItemListWithFrame:NSMakeRect(256, 44, 100, 22)
                                             selectedItem:sel];
  [self addSubview:mHeaderCenterList];

  mSettings->GetHeaderStrRight(getter_Copies(sel));
  mHeaderRightList = [self headerFooterItemListWithFrame:NSMakeRect(356, 44, 100, 22)
                                            selectedItem:sel];
  [self addSubview:mHeaderRightList];

  mSettings->GetFooterStrLeft(getter_Copies(sel));
  mFooterLeftList = [self headerFooterItemListWithFrame:NSMakeRect(156, 0, 100, 22)
                                           selectedItem:sel];
  [self addSubview:mFooterLeftList];

  mSettings->GetFooterStrCenter(getter_Copies(sel));
  mFooterCenterList = [self headerFooterItemListWithFrame:NSMakeRect(256, 0, 100, 22)
                                             selectedItem:sel];
  [self addSubview:mFooterCenterList];

  mSettings->GetFooterStrRight(getter_Copies(sel));
  mFooterRightList = [self headerFooterItemListWithFrame:NSMakeRect(356, 0, 100, 22)
                                            selectedItem:sel];
  [self addSubview:mFooterRightList];
}

// Export settings

- (int16_t)chosenFrameSetting
{
  if ([mAsLaidOutRadio state] == NSOnState)
    return nsIPrintSettings::kFramesAsIs;
  if ([mSelectedFrameRadio state] == NSOnState)
    return nsIPrintSettings::kSelectedFrame;
  if ([mSeparateFramesRadio state] == NSOnState)
    return nsIPrintSettings::kEachFrameSep;
  return nsIPrintSettings::kNoFrames;
}

- (const char*)headerFooterStringForList:(NSPopUpButton*)aList
{
  NSInteger index = [aList indexOfSelectedItem];
  NS_ASSERTION(index < NSInteger(ArrayLength(sHeaderFooterTags)), "Index of dropdown is higher than expected!");
  return sHeaderFooterTags[index];
}

- (void)exportHeaderFooterSettings
{
  const char* headerFooterStr;
  headerFooterStr = [self headerFooterStringForList:mHeaderLeftList];
  mSettings->SetHeaderStrLeft(NS_ConvertUTF8toUTF16(headerFooterStr).get());

  headerFooterStr = [self headerFooterStringForList:mHeaderCenterList];
  mSettings->SetHeaderStrCenter(NS_ConvertUTF8toUTF16(headerFooterStr).get());

  headerFooterStr = [self headerFooterStringForList:mHeaderRightList];
  mSettings->SetHeaderStrRight(NS_ConvertUTF8toUTF16(headerFooterStr).get());

  headerFooterStr = [self headerFooterStringForList:mFooterLeftList];
  mSettings->SetFooterStrLeft(NS_ConvertUTF8toUTF16(headerFooterStr).get());

  headerFooterStr = [self headerFooterStringForList:mFooterCenterList];
  mSettings->SetFooterStrCenter(NS_ConvertUTF8toUTF16(headerFooterStr).get());

  headerFooterStr = [self headerFooterStringForList:mFooterRightList];
  mSettings->SetFooterStrRight(NS_ConvertUTF8toUTF16(headerFooterStr).get());
}

// Summary

- (NSString*)summaryValueForCheckbox:(NSButton*)aCheckbox
{
  if (![aCheckbox isEnabled])
    return [self localizedString:"summaryNAValue"];

  return [aCheckbox state] == NSOnState ?
    [self localizedString:"summaryOnValue"] :
    [self localizedString:"summaryOffValue"];
}

- (NSString*)framesSummaryValue
{
  switch([self chosenFrameSetting]) {
    case nsIPrintSettings::kFramesAsIs:
      return [self localizedString:"asLaidOut"];
    case nsIPrintSettings::kSelectedFrame:
      return [self localizedString:"selectedFrame"];
    case nsIPrintSettings::kEachFrameSep:
      return [self localizedString:"separateFrames"];
  }
  return [self localizedString:"summaryNAValue"];
}

- (NSString*)headerSummaryValue
{
  return [[mHeaderLeftList titleOfSelectedItem] stringByAppendingString:
    [@", " stringByAppendingString:
      [[mHeaderCenterList titleOfSelectedItem] stringByAppendingString:
        [@", " stringByAppendingString:
          [mHeaderRightList titleOfSelectedItem]]]]];
}

- (NSString*)footerSummaryValue
{
  return [[mFooterLeftList titleOfSelectedItem] stringByAppendingString:
    [@", " stringByAppendingString:
      [[mFooterCenterList titleOfSelectedItem] stringByAppendingString:
        [@", " stringByAppendingString:
          [mFooterRightList titleOfSelectedItem]]]]];
}

- (NSArray*)localizedSummaryItems
{
  return [NSArray arrayWithObjects:
    [NSDictionary dictionaryWithObjectsAndKeys:
      [self localizedString:"summaryFramesTitle"], NSPrintPanelAccessorySummaryItemNameKey,
      [self framesSummaryValue], NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
    [NSDictionary dictionaryWithObjectsAndKeys:
      [self localizedString:"summarySelectionOnlyTitle"], NSPrintPanelAccessorySummaryItemNameKey,
      [self summaryValueForCheckbox:mPrintSelectionOnlyCheckbox], NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
    [NSDictionary dictionaryWithObjectsAndKeys:
      [self localizedString:"summaryShrinkToFitTitle"], NSPrintPanelAccessorySummaryItemNameKey,
      [self summaryValueForCheckbox:mShrinkToFitCheckbox], NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
    [NSDictionary dictionaryWithObjectsAndKeys:
      [self localizedString:"summaryPrintBGColorsTitle"], NSPrintPanelAccessorySummaryItemNameKey,
      [self summaryValueForCheckbox:mPrintBGColorsCheckbox], NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
    [NSDictionary dictionaryWithObjectsAndKeys:
      [self localizedString:"summaryPrintBGImagesTitle"], NSPrintPanelAccessorySummaryItemNameKey,
      [self summaryValueForCheckbox:mPrintBGImagesCheckbox], NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
    [NSDictionary dictionaryWithObjectsAndKeys:
      [self localizedString:"summaryHeaderTitle"], NSPrintPanelAccessorySummaryItemNameKey,
      [self headerSummaryValue], NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
    [NSDictionary dictionaryWithObjectsAndKeys:
      [self localizedString:"summaryFooterTitle"], NSPrintPanelAccessorySummaryItemNameKey,
      [self footerSummaryValue], NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
    nil];
}

@end

// Accessory controller

@implementation PrintPanelAccessoryController

- (id)initWithSettings:(nsIPrintSettings*)aSettings
{
  [super initWithNibName:nil bundle:nil];

  NSView* accView = [[PrintPanelAccessoryView alloc] initWithSettings:aSettings];
  [self setView:accView];
  [accView release];
  return self;
}

- (void)exportSettings
{
  return [(PrintPanelAccessoryView*)[self view] exportSettings];
}

- (NSArray *)localizedSummaryItems
{
  return [(PrintPanelAccessoryView*)[self view] localizedSummaryItems];
}

@end