XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefaultSet) const
{
    ScopedPointer <KeyPressMappingSet> defaultSet;

    if (saveDifferencesFromDefaultSet)
    {
        defaultSet = new KeyPressMappingSet (commandManager);
        defaultSet->resetToDefaultMappings();
    }

    XmlElement* const doc = new XmlElement (T("KEYMAPPINGS"));

    doc->setAttribute (T("basedOnDefaults"), saveDifferencesFromDefaultSet);

    int i;
    for (i = 0; i < mappings.size(); ++i)
    {
        const CommandMapping* const cm = mappings.getUnchecked(i);

        for (int j = 0; j < cm->keypresses.size(); ++j)
        {
            if (defaultSet == 0
                 || ! defaultSet->containsMapping (cm->commandID, cm->keypresses.getReference (j)))
            {
                XmlElement* const map = new XmlElement (T("MAPPING"));

                map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID));
                map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID));
                map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription());

                doc->addChildElement (map);
            }
        }
    }

    if (defaultSet != 0)
    {
        for (i = 0; i < defaultSet->mappings.size(); ++i)
        {
            const CommandMapping* const cm = defaultSet->mappings.getUnchecked(i);

            for (int j = 0; j < cm->keypresses.size(); ++j)
            {
                if (! containsMapping (cm->commandID, cm->keypresses.getReference (j)))
                {
                    XmlElement* const map = new XmlElement (T("UNMAPPING"));

                    map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID));
                    map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID));
                    map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription());

                    doc->addChildElement (map);
                }
            }
        }
    }

    return doc;
}
XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefaultSet) const
{
    std::unique_ptr<KeyPressMappingSet> defaultSet;

    if (saveDifferencesFromDefaultSet)
    {
        defaultSet.reset (new KeyPressMappingSet (commandManager));
        defaultSet->resetToDefaultMappings();
    }

    XmlElement* const doc = new XmlElement ("KEYMAPPINGS");

    doc->setAttribute ("basedOnDefaults", saveDifferencesFromDefaultSet);

    for (int i = 0; i < mappings.size(); ++i)
    {
        const CommandMapping& cm = *mappings.getUnchecked(i);

        for (int j = 0; j < cm.keypresses.size(); ++j)
        {
            if (defaultSet == nullptr
                 || ! defaultSet->containsMapping (cm.commandID, cm.keypresses.getReference (j)))
            {
                XmlElement* const map = doc->createNewChildElement ("MAPPING");

                map->setAttribute ("commandId", String::toHexString ((int) cm.commandID));
                map->setAttribute ("description", commandManager.getDescriptionOfCommand (cm.commandID));
                map->setAttribute ("key", cm.keypresses.getReference (j).getTextDescription());
            }
        }
    }

    if (defaultSet != nullptr)
    {
        for (int i = 0; i < defaultSet->mappings.size(); ++i)
        {
            const CommandMapping& cm = *defaultSet->mappings.getUnchecked(i);

            for (int j = 0; j < cm.keypresses.size(); ++j)
            {
                if (! containsMapping (cm.commandID, cm.keypresses.getReference (j)))
                {
                    XmlElement* const map = doc->createNewChildElement ("UNMAPPING");

                    map->setAttribute ("commandId", String::toHexString ((int) cm.commandID));
                    map->setAttribute ("description", commandManager.getDescriptionOfCommand (cm.commandID));
                    map->setAttribute ("key", cm.keypresses.getReference (j).getTextDescription());
                }
            }
        }
    }

    return doc;
}
//==============================================================================
bool KeyPressMappingSet::restoreFromXml (const XmlElement& xmlVersion)
{
    if (xmlVersion.hasTagName ("KEYMAPPINGS"))
    {
        if (xmlVersion.getBoolAttribute ("basedOnDefaults", true))
        {
            // if the XML was created as a set of differences from the default mappings,
            // (i.e. by calling createXml (true)), then we need to first restore the defaults.
            resetToDefaultMappings();
        }
        else
        {
            // if the XML was created calling createXml (false), then we need to clear all
            // the keys and treat the xml as describing the entire set of mappings.
            clearAllKeyPresses();
        }

        forEachXmlChildElement (xmlVersion, map)
        {
            const CommandID commandId = map->getStringAttribute ("commandId").getHexValue32();

            if (commandId != 0)
            {
                const KeyPress key (KeyPress::createFromDescription (map->getStringAttribute ("key")));

                if (map->hasTagName ("MAPPING"))
                {
                    addKeyPress (commandId, key);
                }
                else if (map->hasTagName ("UNMAPPING"))
                {
                    if (containsMapping (commandId, key))
                        removeKeyPress (key);
                }
            }
        }

        return true;
    }

    return false;
}