root/src/apps/debugger/user_interface/gui/value/value_handlers/IntegerValueHandler.cpp
/*
 * Copyright 2015-2016, Rene Gollent, rene@gollent.com.
 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */


#include "IntegerValueHandler.h"

#include <new>

#include <AutoDeleter.h>

#include "IntegerValue.h"
#include "Setting.h"
#include "Settings.h"
#include "SettingsDescription.h"
#include "SettingsMenu.h"
#include "TableCellFormattedValueRenderer.h"
#include "TableCellIntegerEditor.h"


static const char* const kFormatSettingID = "format";


// #pragma mark - FormatOption


class IntegerValueHandler::FormatOption : public SettingsOption {
public:
        FormatOption(const char* id, const char* name, integer_format format)
                :
                fID(id),
                fName(name),
                fFormat(format)
        {
        }

        virtual const char* ID() const
        {
                return fID;
        }

        virtual const char* Name() const
        {
                return fName;
        }

        integer_format Format() const
        {
                return fFormat;
        }

private:
        const char*             fID;
        const char*             fName;
        integer_format  fFormat;
};


// #pragma mark - IntegerFormatterConfig


class IntegerValueHandler::IntegerFormatterConfig
        : public IntegerValueFormatter::Config {
public:
        IntegerFormatterConfig()
                :
                fSettings(NULL),
                fFormatSetting(NULL)
        {
        }

        ~IntegerFormatterConfig()
        {
                if (fSettings != NULL)
                        fSettings->ReleaseReference();
        }

        status_t Init(SettingsDescription* settingsDescription)
        {
                fSettings = new(std::nothrow) Settings(settingsDescription);
                if (fSettings == NULL)
                        return B_NO_MEMORY;

                status_t error = fSettings->Init();
                if (error != B_OK)
                        return error;

                fFormatSetting = dynamic_cast<OptionsSetting*>(
                        settingsDescription->SettingByID(kFormatSettingID));
                if (fFormatSetting == NULL)
                        return B_BAD_VALUE;

                return B_OK;
        }

        virtual Settings* GetSettings() const
        {
                return fSettings;
        }

        virtual integer_format IntegerFormat() const
        {
                FormatOption* option = dynamic_cast<FormatOption*>(
                        fSettings->OptionValue(fFormatSetting));
                return option != NULL ? option->Format() : INTEGER_FORMAT_DEFAULT;
        }

private:
        Settings*               fSettings;
        OptionsSetting* fFormatSetting;
};


// #pragma mark - IntegerValueHandler


IntegerValueHandler::IntegerValueHandler()
{
}


IntegerValueHandler::~IntegerValueHandler()
{
}


status_t
IntegerValueHandler::Init()
{
        return B_OK;
}


float
IntegerValueHandler::SupportsValue(Value* value)
{
        return dynamic_cast<IntegerValue*>(value) != NULL ? 0.5f : 0;
}


status_t
IntegerValueHandler::GetValueFormatter(Value* _value,
        ValueFormatter*& _formatter)
{
        IntegerValue* value = dynamic_cast<IntegerValue*>(_value);
        if (value == NULL)
                return B_BAD_VALUE;

        IntegerValueFormatter::Config* config = NULL;
        status_t error = CreateIntegerFormatterConfig(value, config);
        if (error != B_OK)
                return error;

        BReference<IntegerValueFormatter::Config> configReference(config, true);
        ValueFormatter* formatter = new(std::nothrow) IntegerValueFormatter(config);
        if (formatter == NULL)
                return B_NO_MEMORY;

        _formatter = formatter;
        return B_OK;
}


status_t
IntegerValueHandler::GetTableCellValueRenderer(Value* _value,
        TableCellValueRenderer*& _renderer)
{
        IntegerValue* value = dynamic_cast<IntegerValue*>(_value);
        if (value == NULL)
                return B_BAD_VALUE;

        IntegerValueFormatter::Config* config = NULL;
        status_t error = CreateIntegerFormatterConfig(value, config);
        if (error != B_OK)
                return error;
        BReference<IntegerValueFormatter::Config> configReference(config, true);

        // create the renderer
        return CreateTableCellValueRenderer(value, config, _renderer);
}


status_t
IntegerValueHandler::GetTableCellValueEditor(Value* _value,
        Settings* settings, TableCellValueEditor*& _editor)
{
        IntegerValue* value = dynamic_cast<IntegerValue*>(_value);
        if (value == NULL)
                return B_BAD_VALUE;

        IntegerValueFormatter::Config* config = NULL;
        status_t error = CreateIntegerFormatterConfig(value, config);
        if (error != B_OK)
                return error;
        BReference<IntegerValueFormatter::Config> configReference(config, true);

        ValueFormatter* formatter;
        error = CreateValueFormatter(config, formatter);
        if (error != B_OK)
                return error;
        BReference<ValueFormatter> formatterReference(formatter, true);

        TableCellIntegerEditor* editor = new(std::nothrow) TableCellIntegerEditor(
                value, formatter);
        if (editor == NULL)
                return B_NO_MEMORY;

        BReference<TableCellIntegerEditor> editorReference(editor, true);
        error = editor->Init();
        if (error != B_OK)
                return error;

        editorReference.Detach();
        _editor = editor;
        return B_OK;
}


status_t
IntegerValueHandler::CreateTableCellValueSettingsMenu(Value* value,
        Settings* settings, SettingsMenu*& _menu)
{
        // get the format option
        OptionsSetting* formatSetting = dynamic_cast<OptionsSetting*>(
                settings->Description()->SettingByID(kFormatSettingID));
        if (formatSetting == NULL)
                return B_BAD_VALUE;

        // create the settings menu
        SettingsMenuImpl* menu = new(std::nothrow) SettingsMenuImpl(settings);
        if (menu == NULL)
                return B_NO_MEMORY;
        ObjectDeleter<SettingsMenu> menuDeleter(menu);

        // add the format option menu item
        if (!menu->AddOptionsItem(formatSetting))
                return B_NO_MEMORY;

        _menu = menuDeleter.Detach();
        return B_OK;
}


integer_format
IntegerValueHandler::DefaultIntegerFormat(IntegerValue* value)
{
        return value->IsSigned() ? INTEGER_FORMAT_SIGNED : INTEGER_FORMAT_UNSIGNED;
}


status_t
IntegerValueHandler::AddIntegerFormatSettingOptions(IntegerValue* value,
        OptionsSettingImpl* setting)
{
        status_t error = AddIntegerFormatOption(setting, "signed", "Signed",
                INTEGER_FORMAT_SIGNED);
        if (error != B_OK)
                return error;

        error = AddIntegerFormatOption(setting, "unsigned", "Unsigned",
                INTEGER_FORMAT_UNSIGNED);
        if (error != B_OK)
                return error;

        error = AddIntegerFormatOption(setting, "hex", "Hexadecimal",
                INTEGER_FORMAT_HEX_DEFAULT);
        if (error != B_OK)
                return error;

        return B_OK;
}


status_t
IntegerValueHandler::CreateValueFormatter(
        IntegerValueFormatter::Config* config,
        ValueFormatter*& _formatter)
{
        ValueFormatter* formatter = new(std::nothrow) IntegerValueFormatter(
                config);
        if (formatter == NULL)
                return B_NO_MEMORY;

        _formatter = formatter;
        return B_OK;
}


status_t
IntegerValueHandler::CreateTableCellValueRenderer(IntegerValue* value,
        IntegerValueFormatter::Config* config,
        TableCellValueRenderer*& _renderer)
{
        ValueFormatter* formatter;
        status_t error = CreateValueFormatter(config, formatter);
        if (error != B_OK)
                return error;
        BReference<ValueFormatter> formatterReference(formatter, true);

        TableCellValueRenderer* renderer
                = new(std::nothrow) TableCellFormattedValueRenderer(formatter);
        if (renderer == NULL)
                return B_NO_MEMORY;

        _renderer = renderer;
        return B_OK;
}


status_t
IntegerValueHandler::CreateIntegerFormatterConfig(IntegerValue* value,
        IntegerValueFormatter::Config*& _config)
{
        // create a settings description
        SettingsDescription* settingsDescription
                = _CreateTableCellSettingsDescription(value);
        if (settingsDescription == NULL)
                return B_NO_MEMORY;
        BReference<SettingsDescription> settingsDescriptionReference(
                settingsDescription, true);

        // create config
        IntegerFormatterConfig* config = new(std::nothrow) IntegerFormatterConfig;
        if (config == NULL)
                return B_NO_MEMORY;
        BReference<IntegerFormatterConfig> configReference(config, true);

        status_t error = config->Init(settingsDescription);
        if (error != B_OK)
                return error;

        _config = config;
        configReference.Detach();

        return B_OK;
}


status_t
IntegerValueHandler::AddIntegerFormatOption(OptionsSettingImpl* setting,
        const char* id, const char* name, integer_format format)
{
        FormatOption* option = new(std::nothrow) FormatOption(id, name, format);
        BReference<FormatOption> optionReference(option, true);
        if (option == NULL || !setting->AddOption(option))
                return B_NO_MEMORY;

        return B_OK;
}


SettingsDescription*
IntegerValueHandler::_CreateTableCellSettingsDescription(
        IntegerValue* value)
{
        // create description object
        SettingsDescription* description = new(std::nothrow) SettingsDescription;
        if (description == NULL)
                return NULL;
        BReference<SettingsDescription> descriptionReference(description, true);

        // integer format setting
        OptionsSettingImpl* setting = new(std::nothrow) OptionsSettingImpl(
                kFormatSettingID, "Format");
        if (setting == NULL)
                return NULL;
        BReference<OptionsSettingImpl> settingReference(setting, true);

        // add options
        if (AddIntegerFormatSettingOptions(value, setting) != B_OK)
                return NULL;

        // set default
        integer_format defaultFormat = DefaultIntegerFormat(value);
        SettingsOption* defaultOption = setting->OptionAt(0);
        for (int32 i = 0;
                FormatOption* option
                        = dynamic_cast<FormatOption*>(setting->OptionAt(i));
                i++) {
                if (option->Format() == defaultFormat) {
                        defaultOption = option;
                        break;
                }
        }

        setting->SetDefaultOption(defaultOption);

        // add setting
        if (!description->AddSetting(setting))
                return NULL;

        return descriptionReference.Detach();
}