Get user-defined printer settings presets programmatically

Dear community, how can I get the user-defined printer settings presets programmatically?

PMPrinterCopyPresets() API only gets the pre-defined presets for a given printer, but not the ones added by the user by means of the standard print dialog.

Accepted Reply

Per-printer and common user-defined print presets are saved in plist files located in ~/Library/Preferences/.

For common presets the file is: com.apple.print.custompapers.plist .

For per-printer ones the files are: com.apple.print.custompresets.forprinter.PRINTER_NAME.plist .

To use the preset settings the following steps can be performed:

  • Loade the plist in NSDictionary objects and looked it up.
  • For each preset load the settings of the preset in a NSDictionary accessing thecom.apple.print.preset.settings key.
  • Get the print settings dictionary of your NSPrintInfo using the printSettings selector.
  • Initialize the obtained dictionary with the one read from the plist file by using addEntriesFromDictionary selector. This adds & overwrites entries, but does not clear the receiving dictionary.
  • Optionally update page format, as it is stored in printer settings dictionary keys like com.apple.print.PaperInfo.*** .
  • Use PMPageFormat selector of NSPrintInfo to obtain the above mentioned object that needs to be updated.
  • Set page format values from dictionary and call updateFromPMPageFormat selector from NSPrintInfo.
// Sample code
// ut_print_presets_system.h : PrintPresetsSystem class definition
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

#pragma once

namespace ut
{

class PrintPreset;
class PrintData;

// manages platform-specific print presets stored
class UTILS_API PrintPresetsSystem
{
public:
    static PrintPresetsSystem& instance();

    void load(const wxString& printerName);
    void reload(const wxString& printerName);

    unsigned int size() const; // "None" preset is counted
    unsigned int getIndex(const wxString& name) const;
    wxString getName(unsigned int index) const;
    bool presetToPrintData(const wxString& name, PrintData& printData);

private:
    PrintPresetsSystem();
    PrintPresetsSystem(const PrintPresetsSystem&) = delete;
    PrintPresetsSystem& operator=(const PrintPresetsSystem&) = delete;
    ~PrintPresetsSystem();

    void loadBuiltin(const wxString&);
    void loadCustom(const wxString&, bool);
    void clear();
    void append(PrintPreset*);

private:
    wxString m_printerName;
    std::vector<PrintPreset*> m_printPresets;
};

} // namespace ut


// ut_print_presets_system_mac.mm : PrintPresetsSystem class implementation for mac
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

#include "ut_precompiled.h"
#include "ut_print_presets_system.h"
#include <wx/osx/core/cfstring.h>
#import <Foundation/Foundation.h>

namespace ut
{

#pragma mark - Local defines

static const wxString s_nonePresetName = _("None");

#define kPMPresetFileCommon       @"com.apple.print.custompresets"
#define kPMPresetNamesKey         @"com.apple.print.customPresetNames"
#define kPMPresetSettingsKey      @"com.apple.print.preset.settings"
#define kPMPresetPaperInfoKey     @"com.apple.print.preset.PaperInfo"
#define kPMPresetOrientationKey   @"com.apple.print.preset.Orientation"
#define kPMPresetScalingKey       @"com.apple.print.preset.Scaling"
#define kPMPaperNameKey           @"com.apple.print.PaperInfo.PMPaperName"
#if 0 // so far unused keys
#define kPMCustomPaperKey         @"com.apple.print.PaperInfo.PMCustomPaper"
#define kPMUnadjustedPaperRectKey @"com.apple.print.PaperInfo.PMUnadjustedPaperRect"
#define kPMUnadjustedPageRectKey  @"com.apple.print.PaperInfo.PMUnadjustedPageRect"
#define kPMAdjustedPaperRectKey   @"com.apple.print.PageFormat.PMAdjustedPaperRect"
#define kPMAdjustedPageRectKey    @"com.apple.print.PageFormat.PMAdjustedPageRect"
#endif // 0

#pragma mark - Local helpers

static NSString* getCustomPrintPresetsFolder()
{
    return [@"~/Library/Preferences" stringByExpandingTildeInPath];
}

static bool printSettingsToPrintInfo(NSDictionary* inputDict, WX_NSPrintInfo& printInfo)
{
    // it is ok for a print preset dictionary to have no paper info, for example
    // the "Black and White" preset only contains {ColorModel,Duplex,cupsPrintQuality} keys
    NSDictionary* root = [inputDict objectForKey:kPMPresetPaperInfoKey];
    if (root == nil)
        return true;
    NSDictionary* dict = [root objectForKey:@"paperInfo"];
    if (dict == nil)
        return true;

    // init
    PMPageFormat pageFormat = (PMPageFormat)[printInfo PMPageFormat];
    PMPrintSession printSession = (PMPrintSession)[printInfo PMPrintSession];
    PMPrinter printer;
    OSStatus status = PMSessionGetCurrentPrinter(printSession, &printer);
    NSString* paperName = [dict objectForKey:kPMPaperNameKey];
    if (status != noErr || paperName == nil || [paperName length] == 0)
        return false;

    // re-create print info's page format based on paper name from dictionary
    CFArrayRef paperlist = nullptr;
    if (PMPrinterGetPaperList(printer, &paperlist) == noErr)
    {
        PMPaper matchedPaper = kPMNoData;
        CFIndex papersCount = CFArrayGetCount(paperlist);
        for (CFIndex index = 0; index < papersCount; index++)
        {
            PMPaper paper = (PMPaper)CFArrayGetValueAtIndex(paperlist, index);
            CFStringRef currentPaperName = nullptr;
            if (PMPaperGetID(paper,  &currentPaperName) != noErr)
                continue;
            if ([paperName compare:(NSString*)currentPaperName] == NSOrderedSame)
            {
                matchedPaper = paper;
                break;
            }
        }

        if (matchedPaper != kPMNoData)
        {
            PMPageFormat newPageFormat;
            PMCreatePageFormatWithPMPaper(&newPageFormat, matchedPaper);
            PMCopyPageFormat(newPageFormat, pageFormat);
            PMRelease(newPageFormat);
        }
        else
            return false;
    }

    // update print info's orientation and scale based on values from dictionary
    PMOrientation orientation = [[inputDict objectForKey:kPMPresetOrientationKey] unsignedShortValue];
    if (PMSetOrientation(pageFormat, orientation, kPMUnlocked) != noErr)
        return false;

#if 0 // we don't have GUI for scale expressed in percent or as a factor
    double scale = [[inputDict objectForKey:kPMPresetScalingKey] doubleValue];
    if (PMSetScale(pageFormat, scale) != noErr)
        return false;
#endif // 0

    [printInfo updateFromPMPageFormat];
    return true;
}

#pragma mark - CustomPrintPreset class

class PrintPreset
{
public:
    static PrintPreset* create(NSString* key, NSDictionary* dict);
    ~PrintPreset() { [m_dict release]; }

    wxString getName() const { return m_name; }
    bool toPrintData(PrintData& printData) const;

private:
    PrintPreset(const wxString& name, NSDictionary* dict): m_name(name), m_dict(dict) { [m_dict retain]; }

private:
    wxString m_name;
    NSDictionary* m_dict = nil;
};

PrintPreset* PrintPreset::create(NSString* key, NSDictionary* dict)
{
    if (dict == nil)
        return nullptr;

    wxString wxName = wxCFStringRef::AsString(key);
    return wxName.IsEmpty() ? nullptr : new PrintPreset(wxName, dict);;
}

bool PrintPreset::toPrintData(PrintData& printData) const
{
    MacPrintNativeData* pNativeData = MacPrintNativeData::GetNativeData(printData);
    NSDictionary* printSettingsDict = [m_dict objectForKey:kPMPresetSettingsKey];
    if (pNativeData == nullptr || printSettingsDict == nil)
        return false;

    // adds & overwrites entries, but does not clear the receiving dictionary
    [[pNativeData->m_macPrintInfo printSettings] addEntriesFromDictionary:printSettingsDict];

    // additionally update paper info, as e.g. preset paper format is stored in printer settings
    if (!printSettingsToPrintInfo(printSettingsDict, pNativeData->m_macPrintInfo))
        ut::messageBox(_("Page format defined in print preset cannot be used."));

    if (PMGetPageFormatPaper(pNativeData->m_macPageFormat, &pNativeData->m_macPaper) != noErr)
        return false;
    if (PMSessionValidatePageFormat(pNativeData->m_macPrintSession,
                                    pNativeData->m_macPageFormat, kPMDontWantBoolean) != noErr)
        return false;
    if (PMSessionValidatePrintSettings(pNativeData->m_macPrintSession,
                                       pNativeData->m_macPrintSettings, kPMDontWantBoolean) != noErr)
        return false;

    printData.ConvertFromNative();
    return true;
}

#pragma mark - PrintPresetsSystem class implementation

PrintPresetsSystem::PrintPresetsSystem()
{
}

PrintPresetsSystem::~PrintPresetsSystem()
{
    clear();
}

PrintPresetsSystem& PrintPresetsSystem::instance()
{
    static PrintPresetsSystem s_theInstance;
    return s_theInstance;
}

void PrintPresetsSystem::load(const wxString& printerName)
{
    if (m_printerName == printerName)
        return;
    else
    {
        clear();
        m_printerName = printerName;
    }

    // 1. load builtuin presets, i.e. defined in OS or printer driver
    loadBuiltin(printerName);

    // 2. load custom specific presets, i.e. user-defined presets for the given printer
    loadCustom(printerName, true);

    // 3. load custom common presets, i.e. user-defined presets for all printers
    loadCustom(printerName, false);

}

void PrintPresetsSystem::reload(const wxString& printerName)
{
    clear();
    load(printerName);
}

void PrintPresetsSystem::loadBuiltin(const wxString& printerName)
{
    PMPrinter printer = PMPrinterCreateFromPrinterID(wxCFStringRef(printerName));
    if (printer == nullptr)
        return;

    CFArrayRef presetsList = nullptr;
    OSStatus status = PMPrinterCopyPresets(printer, &presetsList);
    PMRelease(printer);
    if (status != noErr || presetsList == nullptr)
        return;

    CFIndex arrayCount = CFArrayGetCount(presetsList);
    for (CFIndex index = 0; index < arrayCount; index++)
    {
        PMPreset preset = (PMPreset)CFArrayGetValueAtIndex(presetsList, index);
        CFStringRef presetName = nullptr;
        if (PMPresetCopyName(preset, &presetName) == noErr && CFStringGetLength(presetName) > 0)
        {
            NSDictionary* dict = nil;
            if (PMPresetGetAttributes(preset, (CFDictionaryRef*)(&dict)) == noErr)
            {
                PrintPreset* pPreset = PrintPreset::create((NSString*)presetName, dict);
                if (pPreset != nullptr)
                    append(pPreset);
            }
            CFRelease(presetName);
        }
    }
    CFRelease(presetsList);
}

void PrintPresetsSystem::loadCustom(const wxString& printerName, bool perPrinter)
{
    NSMutableString* plistFile = [NSMutableString string];
    [plistFile appendFormat:@"%@/%@", getCustomPrintPresetsFolder(), kPMPresetFileCommon];
    if (perPrinter && !printerName.IsEmpty())
        [plistFile appendFormat:@".forprinter.%@", wxCFStringRef(printerName).AsNSString()];
    [plistFile appendString:@".plist"];

    NSDictionary* rootDict = [[[NSDictionary alloc] initWithContentsOfFile:(NSString*)plistFile] autorelease];
    if (rootDict == nil)
        return;

    NSDictionary* namesDict = [rootDict objectForKey:kPMPresetNamesKey];
    for (NSString* key in namesDict)
    {
        NSDictionary* subDictionary = [rootDict objectForKey:key];

        PrintPreset* pPreset = PrintPreset::create(key, subDictionary);
        if (pPreset != nullptr)
            append(pPreset);
    }
}

void PrintPresetsSystem::clear()
{
    for (size_t index = 0; index < m_printPresets.size(); index++)
        delete m_printPresets[index];
    m_printPresets.clear();
    m_printerName.Clear();
}

void PrintPresetsSystem::append(PrintPreset* pPreset)
{
    m_printPresets.push_back(pPreset);
}

unsigned int PrintPresetsSystem::size() const
{
    return m_printPresets.size() + 1; // "None" preset is counted
}

wxString PrintPresetsSystem::getName(unsigned int index) const
{
    wxASSERT_MSG(index <= size(), _T("Invalid print preset index"));
    return (index == 0) ? s_nonePresetName : m_printPresets[index - 1]->getName();
}

unsigned int PrintPresetsSystem::getIndex(const wxString& name) const
{
    if (name == wxEmptyString || name == s_nonePresetName)
        return 0;

    for (size_t index = 0; index < m_printPresets.size(); index++)
        if (m_printPresets[index]->getName() == name)
            return index + 1;

    wxASSERT_MSG(false, wxString::Format(_T("Print preset not found: %ls"), name.c_str()));
    return 0;
}

bool PrintPresetsSystem::presetToPrintData(const wxString& name, PrintData& printData)
{
    unsigned int index = getIndex(name);
    if (index == 0)
        return false;

    return m_printPresets[index - 1]->toPrintData(printData);
}

} // namespace ut

Replies

Per-printer and common user-defined print presets are saved in plist files located in ~/Library/Preferences/.

For common presets the file is: com.apple.print.custompapers.plist .

For per-printer ones the files are: com.apple.print.custompresets.forprinter.PRINTER_NAME.plist .

To use the preset settings the following steps can be performed:

  • Loade the plist in NSDictionary objects and looked it up.
  • For each preset load the settings of the preset in a NSDictionary accessing thecom.apple.print.preset.settings key.
  • Get the print settings dictionary of your NSPrintInfo using the printSettings selector.
  • Initialize the obtained dictionary with the one read from the plist file by using addEntriesFromDictionary selector. This adds & overwrites entries, but does not clear the receiving dictionary.
  • Optionally update page format, as it is stored in printer settings dictionary keys like com.apple.print.PaperInfo.*** .
  • Use PMPageFormat selector of NSPrintInfo to obtain the above mentioned object that needs to be updated.
  • Set page format values from dictionary and call updateFromPMPageFormat selector from NSPrintInfo.
// Sample code
// ut_print_presets_system.h : PrintPresetsSystem class definition
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

#pragma once

namespace ut
{

class PrintPreset;
class PrintData;

// manages platform-specific print presets stored
class UTILS_API PrintPresetsSystem
{
public:
    static PrintPresetsSystem& instance();

    void load(const wxString& printerName);
    void reload(const wxString& printerName);

    unsigned int size() const; // "None" preset is counted
    unsigned int getIndex(const wxString& name) const;
    wxString getName(unsigned int index) const;
    bool presetToPrintData(const wxString& name, PrintData& printData);

private:
    PrintPresetsSystem();
    PrintPresetsSystem(const PrintPresetsSystem&) = delete;
    PrintPresetsSystem& operator=(const PrintPresetsSystem&) = delete;
    ~PrintPresetsSystem();

    void loadBuiltin(const wxString&);
    void loadCustom(const wxString&, bool);
    void clear();
    void append(PrintPreset*);

private:
    wxString m_printerName;
    std::vector<PrintPreset*> m_printPresets;
};

} // namespace ut


// ut_print_presets_system_mac.mm : PrintPresetsSystem class implementation for mac
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

#include "ut_precompiled.h"
#include "ut_print_presets_system.h"
#include <wx/osx/core/cfstring.h>
#import <Foundation/Foundation.h>

namespace ut
{

#pragma mark - Local defines

static const wxString s_nonePresetName = _("None");

#define kPMPresetFileCommon       @"com.apple.print.custompresets"
#define kPMPresetNamesKey         @"com.apple.print.customPresetNames"
#define kPMPresetSettingsKey      @"com.apple.print.preset.settings"
#define kPMPresetPaperInfoKey     @"com.apple.print.preset.PaperInfo"
#define kPMPresetOrientationKey   @"com.apple.print.preset.Orientation"
#define kPMPresetScalingKey       @"com.apple.print.preset.Scaling"
#define kPMPaperNameKey           @"com.apple.print.PaperInfo.PMPaperName"
#if 0 // so far unused keys
#define kPMCustomPaperKey         @"com.apple.print.PaperInfo.PMCustomPaper"
#define kPMUnadjustedPaperRectKey @"com.apple.print.PaperInfo.PMUnadjustedPaperRect"
#define kPMUnadjustedPageRectKey  @"com.apple.print.PaperInfo.PMUnadjustedPageRect"
#define kPMAdjustedPaperRectKey   @"com.apple.print.PageFormat.PMAdjustedPaperRect"
#define kPMAdjustedPageRectKey    @"com.apple.print.PageFormat.PMAdjustedPageRect"
#endif // 0

#pragma mark - Local helpers

static NSString* getCustomPrintPresetsFolder()
{
    return [@"~/Library/Preferences" stringByExpandingTildeInPath];
}

static bool printSettingsToPrintInfo(NSDictionary* inputDict, WX_NSPrintInfo& printInfo)
{
    // it is ok for a print preset dictionary to have no paper info, for example
    // the "Black and White" preset only contains {ColorModel,Duplex,cupsPrintQuality} keys
    NSDictionary* root = [inputDict objectForKey:kPMPresetPaperInfoKey];
    if (root == nil)
        return true;
    NSDictionary* dict = [root objectForKey:@"paperInfo"];
    if (dict == nil)
        return true;

    // init
    PMPageFormat pageFormat = (PMPageFormat)[printInfo PMPageFormat];
    PMPrintSession printSession = (PMPrintSession)[printInfo PMPrintSession];
    PMPrinter printer;
    OSStatus status = PMSessionGetCurrentPrinter(printSession, &printer);
    NSString* paperName = [dict objectForKey:kPMPaperNameKey];
    if (status != noErr || paperName == nil || [paperName length] == 0)
        return false;

    // re-create print info's page format based on paper name from dictionary
    CFArrayRef paperlist = nullptr;
    if (PMPrinterGetPaperList(printer, &paperlist) == noErr)
    {
        PMPaper matchedPaper = kPMNoData;
        CFIndex papersCount = CFArrayGetCount(paperlist);
        for (CFIndex index = 0; index < papersCount; index++)
        {
            PMPaper paper = (PMPaper)CFArrayGetValueAtIndex(paperlist, index);
            CFStringRef currentPaperName = nullptr;
            if (PMPaperGetID(paper,  &currentPaperName) != noErr)
                continue;
            if ([paperName compare:(NSString*)currentPaperName] == NSOrderedSame)
            {
                matchedPaper = paper;
                break;
            }
        }

        if (matchedPaper != kPMNoData)
        {
            PMPageFormat newPageFormat;
            PMCreatePageFormatWithPMPaper(&newPageFormat, matchedPaper);
            PMCopyPageFormat(newPageFormat, pageFormat);
            PMRelease(newPageFormat);
        }
        else
            return false;
    }

    // update print info's orientation and scale based on values from dictionary
    PMOrientation orientation = [[inputDict objectForKey:kPMPresetOrientationKey] unsignedShortValue];
    if (PMSetOrientation(pageFormat, orientation, kPMUnlocked) != noErr)
        return false;

#if 0 // we don't have GUI for scale expressed in percent or as a factor
    double scale = [[inputDict objectForKey:kPMPresetScalingKey] doubleValue];
    if (PMSetScale(pageFormat, scale) != noErr)
        return false;
#endif // 0

    [printInfo updateFromPMPageFormat];
    return true;
}

#pragma mark - CustomPrintPreset class

class PrintPreset
{
public:
    static PrintPreset* create(NSString* key, NSDictionary* dict);
    ~PrintPreset() { [m_dict release]; }

    wxString getName() const { return m_name; }
    bool toPrintData(PrintData& printData) const;

private:
    PrintPreset(const wxString& name, NSDictionary* dict): m_name(name), m_dict(dict) { [m_dict retain]; }

private:
    wxString m_name;
    NSDictionary* m_dict = nil;
};

PrintPreset* PrintPreset::create(NSString* key, NSDictionary* dict)
{
    if (dict == nil)
        return nullptr;

    wxString wxName = wxCFStringRef::AsString(key);
    return wxName.IsEmpty() ? nullptr : new PrintPreset(wxName, dict);;
}

bool PrintPreset::toPrintData(PrintData& printData) const
{
    MacPrintNativeData* pNativeData = MacPrintNativeData::GetNativeData(printData);
    NSDictionary* printSettingsDict = [m_dict objectForKey:kPMPresetSettingsKey];
    if (pNativeData == nullptr || printSettingsDict == nil)
        return false;

    // adds & overwrites entries, but does not clear the receiving dictionary
    [[pNativeData->m_macPrintInfo printSettings] addEntriesFromDictionary:printSettingsDict];

    // additionally update paper info, as e.g. preset paper format is stored in printer settings
    if (!printSettingsToPrintInfo(printSettingsDict, pNativeData->m_macPrintInfo))
        ut::messageBox(_("Page format defined in print preset cannot be used."));

    if (PMGetPageFormatPaper(pNativeData->m_macPageFormat, &pNativeData->m_macPaper) != noErr)
        return false;
    if (PMSessionValidatePageFormat(pNativeData->m_macPrintSession,
                                    pNativeData->m_macPageFormat, kPMDontWantBoolean) != noErr)
        return false;
    if (PMSessionValidatePrintSettings(pNativeData->m_macPrintSession,
                                       pNativeData->m_macPrintSettings, kPMDontWantBoolean) != noErr)
        return false;

    printData.ConvertFromNative();
    return true;
}

#pragma mark - PrintPresetsSystem class implementation

PrintPresetsSystem::PrintPresetsSystem()
{
}

PrintPresetsSystem::~PrintPresetsSystem()
{
    clear();
}

PrintPresetsSystem& PrintPresetsSystem::instance()
{
    static PrintPresetsSystem s_theInstance;
    return s_theInstance;
}

void PrintPresetsSystem::load(const wxString& printerName)
{
    if (m_printerName == printerName)
        return;
    else
    {
        clear();
        m_printerName = printerName;
    }

    // 1. load builtuin presets, i.e. defined in OS or printer driver
    loadBuiltin(printerName);

    // 2. load custom specific presets, i.e. user-defined presets for the given printer
    loadCustom(printerName, true);

    // 3. load custom common presets, i.e. user-defined presets for all printers
    loadCustom(printerName, false);

}

void PrintPresetsSystem::reload(const wxString& printerName)
{
    clear();
    load(printerName);
}

void PrintPresetsSystem::loadBuiltin(const wxString& printerName)
{
    PMPrinter printer = PMPrinterCreateFromPrinterID(wxCFStringRef(printerName));
    if (printer == nullptr)
        return;

    CFArrayRef presetsList = nullptr;
    OSStatus status = PMPrinterCopyPresets(printer, &presetsList);
    PMRelease(printer);
    if (status != noErr || presetsList == nullptr)
        return;

    CFIndex arrayCount = CFArrayGetCount(presetsList);
    for (CFIndex index = 0; index < arrayCount; index++)
    {
        PMPreset preset = (PMPreset)CFArrayGetValueAtIndex(presetsList, index);
        CFStringRef presetName = nullptr;
        if (PMPresetCopyName(preset, &presetName) == noErr && CFStringGetLength(presetName) > 0)
        {
            NSDictionary* dict = nil;
            if (PMPresetGetAttributes(preset, (CFDictionaryRef*)(&dict)) == noErr)
            {
                PrintPreset* pPreset = PrintPreset::create((NSString*)presetName, dict);
                if (pPreset != nullptr)
                    append(pPreset);
            }
            CFRelease(presetName);
        }
    }
    CFRelease(presetsList);
}

void PrintPresetsSystem::loadCustom(const wxString& printerName, bool perPrinter)
{
    NSMutableString* plistFile = [NSMutableString string];
    [plistFile appendFormat:@"%@/%@", getCustomPrintPresetsFolder(), kPMPresetFileCommon];
    if (perPrinter && !printerName.IsEmpty())
        [plistFile appendFormat:@".forprinter.%@", wxCFStringRef(printerName).AsNSString()];
    [plistFile appendString:@".plist"];

    NSDictionary* rootDict = [[[NSDictionary alloc] initWithContentsOfFile:(NSString*)plistFile] autorelease];
    if (rootDict == nil)
        return;

    NSDictionary* namesDict = [rootDict objectForKey:kPMPresetNamesKey];
    for (NSString* key in namesDict)
    {
        NSDictionary* subDictionary = [rootDict objectForKey:key];

        PrintPreset* pPreset = PrintPreset::create(key, subDictionary);
        if (pPreset != nullptr)
            append(pPreset);
    }
}

void PrintPresetsSystem::clear()
{
    for (size_t index = 0; index < m_printPresets.size(); index++)
        delete m_printPresets[index];
    m_printPresets.clear();
    m_printerName.Clear();
}

void PrintPresetsSystem::append(PrintPreset* pPreset)
{
    m_printPresets.push_back(pPreset);
}

unsigned int PrintPresetsSystem::size() const
{
    return m_printPresets.size() + 1; // "None" preset is counted
}

wxString PrintPresetsSystem::getName(unsigned int index) const
{
    wxASSERT_MSG(index <= size(), _T("Invalid print preset index"));
    return (index == 0) ? s_nonePresetName : m_printPresets[index - 1]->getName();
}

unsigned int PrintPresetsSystem::getIndex(const wxString& name) const
{
    if (name == wxEmptyString || name == s_nonePresetName)
        return 0;

    for (size_t index = 0; index < m_printPresets.size(); index++)
        if (m_printPresets[index]->getName() == name)
            return index + 1;

    wxASSERT_MSG(false, wxString::Format(_T("Print preset not found: %ls"), name.c_str()));
    return 0;
}

bool PrintPresetsSystem::presetToPrintData(const wxString& name, PrintData& printData)
{
    unsigned int index = getIndex(name);
    if (index == 0)
        return false;

    return m_printPresets[index - 1]->toPrintData(printData);
}

} // namespace ut