<commit_before>/*
 * Copyright 2015 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "parser.h"

#include <ThreadWeaver/ThreadWeaver>
#include <KFormat>
#include <KLocalizedString>

#include <QTextStream>
#include <QDebug>

#include "../accumulatedtracedata.h"
#include "flamegraph.h"

#include <vector>

using namespace std;

namespace {

// TODO: use QString directly
struct StringCache
{
    StringCache()
    {
        m_ipAddresses.reserve(16384);
    }

    QString func(const InstructionPointer& ip) const
    {
        if (ip.functionIndex) {
            // TODO: support removal of template arguments
            return stringify(ip.functionIndex);
        } else {
            auto& ipAddr = m_ipAddresses[ip.instructionPointer];
            if (ipAddr.isEmpty()) {
                ipAddr = QLatin1String("0x") + QString::number(ip.instructionPointer, 16);
            }
            return ipAddr;
        }
    }

    QString file(const InstructionPointer& ip) const
    {
        if (ip.fileIndex) {
            return stringify(ip.fileIndex);
        } else {
            return {};
        }
    }

    QString module(const InstructionPointer& ip) const
    {
        return stringify(ip.moduleIndex);
    }

    QString stringify(const StringIndex index) const
    {
        if (!index || index.index > m_strings.size()) {
            return {};
        } else {
            return m_strings.at(index.index - 1);
        }
    }

    LocationData location(const InstructionPointer& ip) const
    {
        return {func(ip), file(ip), module(ip), ip.line};
    }

    void update(const vector<string>& strings)
    {
        transform(strings.begin() + m_strings.size(), strings.end(),
                  back_inserter(m_strings), [] (const string& str) { return QString::fromStdString(str); });
    }

    vector<QString> m_strings;
    mutable QHash<uint64_t, QString> m_ipAddresses;
};

struct ChartMergeData
{
    QString function;
    quint64 consumed;
    quint64 allocations;
    quint64 allocated;
    bool operator<(const QString& rhs) const
    {
        return function < rhs;
    }
};

struct ParserData final : public AccumulatedTraceData
{
    ParserData()
    {
        // start off with null data at the origin
        consumedChartData.data.rows.push_back({});
        allocatedChartData.data.rows.push_back({});
        allocationsChartData.data.rows.push_back({});
        // index 0 indicates the total row
        consumedChartData.labelIds.insert(i18n("total"), 0);
        allocatedChartData.labelIds.insert(i18n("total"), 0);
        allocationsChartData.labelIds.insert(i18n("total"), 0);
    }

    void handleTimeStamp(uint64_t /*oldStamp*/, uint64_t newStamp)
    {
        stringCache.update(strings);
        maxConsumedSinceLastTimeStamp = max(maxConsumedSinceLastTimeStamp, leaked);

        // merge data for top 10 functions in this timestamp
        vector<ChartMergeData> mergedData;
        for (const auto& allocation : allocations) {
            const auto function = stringCache.func(findIp(findTrace(allocation.traceIndex).ipIndex));
            auto it = lower_bound(mergedData.begin(), mergedData.end(), function);
            if (it != mergedData.end() && it->function == function) {
                it->allocated += allocation.allocated;
                it->allocations += allocation.allocations;
                it->consumed += allocation.leaked;
            } else {
                it = mergedData.insert(it, {function, allocation.leaked, allocation.allocations, allocation.allocated});
            }
        }

        auto addChartData = [&] (quint64 ChartMergeData::* member, ChartDataWithLabels* data, quint64 totalCost) {
            ChartRows row;
            row.timeStamp = newStamp;
            row.cost.insert(0, totalCost);
            sort(mergedData.begin(), mergedData.end(), [=] (const ChartMergeData& left, const ChartMergeData& right) {
                return left.*member > right.*member;
            });
            for (size_t i = 0; i < min(size_t(10), mergedData.size()); ++i) {
                const auto& alloc = mergedData[i];
                if (!(alloc.*member)) {
                    break;
                }
                auto& id = data->labelIds[alloc.function];
                if (!id) {
                    id = data->labelIds.size() - 1;
                }
                row.cost.insert(id, alloc.*member);
            }
            data->data.rows.append(row);

            if (newStamp == totalTime) {
                // finalize and convert labels
                data->data.labels.reserve(data->labelIds.size());
                for (auto it = data->labelIds.constBegin(); it != data->labelIds.constEnd(); ++it) {
                    data->data.labels.insert(it.value(), it.key());
                }
            }
        };
        addChartData(&ChartMergeData::consumed, &consumedChartData, maxConsumedSinceLastTimeStamp);
        addChartData(&ChartMergeData::allocated, &allocatedChartData, totalAllocated);
        addChartData(&ChartMergeData::allocations, &allocationsChartData, totalAllocations);
        maxConsumedSinceLastTimeStamp = 0;
    }

    void handleAllocation()
    {
        maxConsumedSinceLastTimeStamp = max(maxConsumedSinceLastTimeStamp, leaked);
    }

    void handleDebuggee(const char* command)
    {
        debuggee = command;
    }

    string debuggee;

    struct ChartDataWithLabels
    {
        ChartData data;
        QHash<QString, int> labelIds;
    };
    ChartDataWithLabels consumedChartData;
    ChartDataWithLabels allocationsChartData;
    ChartDataWithLabels allocatedChartData;
    uint64_t maxConsumedSinceLastTimeStamp = 0;

    StringCache stringCache;
};

QString generateSummary(const ParserData& data)
{
    QString ret;
    KFormat format;
    QTextStream stream(&ret);
    const double totalTimeS = 0.001 * data.totalTime;
    stream << "<qt>"
           << i18n("debuggee: %1", QString::fromStdString(data.debuggee)) << "
"
           // xgettext:no-c-format
           << i18n("total runtime: %1s", totalTimeS) << "
"
           << i18n("bytes allocated in total (ignoring deallocations): %1 (%2/s)",
                   format.formatByteSize(data.totalAllocated, 2), format.formatByteSize(data.totalAllocated / totalTimeS)) << "
"
           << i18n("calls to allocation functions: %1 (%2/s)",
                   data.totalAllocations, quint64(data.totalAllocations / totalTimeS)) << "
"
           << i18n("peak heap memory consumption: %1", format.formatByteSize(data.peak)) << "
"
           << i18n("total memory leaked: %1", format.formatByteSize(data.leaked)) << "
";
    stream << "</qt>";
    return ret;
}

void setParents(QVector<RowData>& children, const RowData* parent)
{
    for (auto& row: children) {
        row.parent = parent;
        setParents(row.children, &row);
    }
}

QVector<RowData> mergeAllocations(const ParserData& data)
{
    QVector<RowData> topRows;
    // merge allocations, leave parent pointers invalid (their location may change)
    for (const auto& allocation : data.allocations) {
        auto traceIndex = allocation.traceIndex;
        auto rows = &topRows;
        while (traceIndex) {
            const auto& trace = data.findTrace(traceIndex);
            const auto& ip = data.findIp(trace.ipIndex);
            // TODO: only store the IpIndex and use that
            auto location = data.stringCache.location(ip);
            auto it = lower_bound(rows->begin(), rows->end(), location);
            if (it != rows->end() && it->location == location) {
                it->allocated += allocation.allocated;
                it->allocations += allocation.allocations;
                it->leaked += allocation.leaked;
                it->peak += allocation.peak;
            } else {
                it = rows->insert(it, {allocation.allocations, allocation.peak, allocation.leaked, allocation.allocated,
                                        location, nullptr, {}});
            }
            if (data.isStopIndex(ip.functionIndex)) {
                break;
            }
            traceIndex = trace.parentIndex;
            rows = &it->children;
        }
    }
    // now set the parents, the data is constant from here on
    setParents(topRows, nullptr);
    return topRows;
}

RowData* findByLocation(const RowData& row, QVector<RowData>* data)
{
    for (int i = 0; i < data->size(); ++i) {
        if (data->at(i).location == row.location) {
            return data->data() + i;
        }
    }
    return nullptr;
}

void buildTopDown(const QVector<RowData>& bottomUpData, QVector<RowData>* topDownData)
{
    foreach (const auto& row, bottomUpData) {
        if (row.children.isEmpty()) {
            // leaf node found, bubble up the parent chain to build a top-down tree
            auto node = &row;
            auto stack = topDownData;
            while (node) {
                auto data = findByLocation(*node, stack);
                if (!data) {
                    // create an empty top-down item for this bottom-up node
                    *stack << RowData{0, 0, 0, 0, node->location, nullptr, {}};
                    data = &stack->back();
                }
                // always use the leaf node's cost and propagate that one up the chain
                // otherwise we'd count the cost of some nodes multiple times
                data->allocations += row.allocations;
                data->peak += row.peak;
                data->leaked += row.leaked;
                data->allocated += row.allocated;
                stack = &data->children;
                node = node->parent;
            }
        } else {
            // recurse to find a leaf
            buildTopDown(row.children, topDownData);
        }
    }
}

QVector<RowData> toTopDownData(const QVector<RowData>& bottomUpData)
{
    QVector<RowData> topRows;
    buildTopDown(bottomUpData, &topRows);
    // now set the parents, the data is constant from here on
    setParents(topRows, nullptr);
    return topRows;
}

}

Parser::Parser(QObject* parent)
    : QObject(parent)
{}

Parser::~Parser() = default;

void Parser::parse(const QString& path)
{
    using namespace ThreadWeaver;
    stream() << make_job([=]() {
        ParserData data;
        data.read(path.toStdString());
        emit summaryAvailable(generateSummary(data));
        const auto mergedAllocations = mergeAllocations(data);
        emit bottomUpDataAvailable(mergedAllocations);
        emit consumedChartDataAvailable(data.consumedChartData.data);
        emit allocationsChartDataAvailable(data.allocationsChartData.data);
        emit allocatedChartDataAvailable(data.allocatedChartData.data);
        const auto topDownData = toTopDownData(mergedAllocations);
        emit topDownDataAvailable(topDownData);
        emit flameGraphDataAvailable(FlameGraph::parseData(topDownData));
        emit finished();
    });
}
<commit_msg>Make sure the ChartMergeData is nothrow-move-assignable.<commit_after>/*
 * Copyright 2015 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "parser.h"

#include <ThreadWeaver/ThreadWeaver>
#include <KFormat>
#include <KLocalizedString>

#include <QTextStream>
#include <QDebug>

#include "../accumulatedtracedata.h"
#include "flamegraph.h"

#include <vector>

using namespace std;

namespace {

// TODO: use QString directly
struct StringCache
{
    StringCache()
    {
        m_ipAddresses.reserve(16384);
    }

    QString func(const InstructionPointer& ip) const
    {
        if (ip.functionIndex) {
            // TODO: support removal of template arguments
            return stringify(ip.functionIndex);
        } else {
            auto& ipAddr = m_ipAddresses[ip.instructionPointer];
            if (ipAddr.isEmpty()) {
                ipAddr = QLatin1String("0x") + QString::number(ip.instructionPointer, 16);
            }
            return ipAddr;
        }
    }

    QString file(const InstructionPointer& ip) const
    {
        if (ip.fileIndex) {
            return stringify(ip.fileIndex);
        } else {
            return {};
        }
    }

    QString module(const InstructionPointer& ip) const
    {
        return stringify(ip.moduleIndex);
    }

    QString stringify(const StringIndex index) const
    {
        if (!index || index.index > m_strings.size()) {
            return {};
        } else {
            return m_strings.at(index.index - 1);
        }
    }

    LocationData location(const InstructionPointer& ip) const
    {
        return {func(ip), file(ip), module(ip), ip.line};
    }

    void update(const vector<string>& strings)
    {
        transform(strings.begin() + m_strings.size(), strings.end(),
                  back_inserter(m_strings), [] (const string& str) { return QString::fromStdString(str); });
    }

    vector<QString> m_strings;
    mutable QHash<uint64_t, QString> m_ipAddresses;
};

struct ChartMergeData
{
    QString function;
    quint64 consumed;
    quint64 allocations;
    quint64 allocated;
    bool operator<(const QString& rhs) const
    {
        return function < rhs;
    }
};
static_assert(std::is_nothrow_move_assignable<ChartMergeData>::value, "ChartMergeData must be nothrow move assignable for performance reasons");

struct ParserData final : public AccumulatedTraceData
{
    ParserData()
    {
        // start off with null data at the origin
        consumedChartData.data.rows.push_back({});
        allocatedChartData.data.rows.push_back({});
        allocationsChartData.data.rows.push_back({});
        // index 0 indicates the total row
        consumedChartData.labelIds.insert(i18n("total"), 0);
        allocatedChartData.labelIds.insert(i18n("total"), 0);
        allocationsChartData.labelIds.insert(i18n("total"), 0);
    }

    void handleTimeStamp(uint64_t /*oldStamp*/, uint64_t newStamp)
    {
        stringCache.update(strings);
        maxConsumedSinceLastTimeStamp = max(maxConsumedSinceLastTimeStamp, leaked);

        // merge data for top 10 functions in this timestamp
        vector<ChartMergeData> mergedData;
        for (const auto& allocation : allocations) {
            const auto function = stringCache.func(findIp(findTrace(allocation.traceIndex).ipIndex));
            auto it = lower_bound(mergedData.begin(), mergedData.end(), function);
            if (it != mergedData.end() && it->function == function) {
                it->allocated += allocation.allocated;
                it->allocations += allocation.allocations;
                it->consumed += allocation.leaked;
            } else {
                it = mergedData.insert(it, {function, allocation.leaked, allocation.allocations, allocation.allocated});
            }
        }

        auto addChartData = [&] (quint64 ChartMergeData::* member, ChartDataWithLabels* data, quint64 totalCost) {
            ChartRows row;
            row.timeStamp = newStamp;
            row.cost.insert(0, totalCost);
            sort(mergedData.begin(), mergedData.end(), [=] (const ChartMergeData& left, const ChartMergeData& right) {
                return left.*member > right.*member;
            });
            for (size_t i = 0; i < min(size_t(10), mergedData.size()); ++i) {
                const auto& alloc = mergedData[i];
                if (!(alloc.*member)) {
                    break;
                }
                auto& id = data->labelIds[alloc.function];
                if (!id) {
                    id = data->labelIds.size() - 1;
                }
                row.cost.insert(id, alloc.*member);
            }
            data->data.rows.append(row);

            if (newStamp == totalTime) {
                // finalize and convert labels
                data->data.labels.reserve(data->labelIds.size());
                for (auto it = data->labelIds.constBegin(); it != data->labelIds.constEnd(); ++it) {
                    data->data.labels.insert(it.value(), it.key());
                }
            }
        };
        addChartData(&ChartMergeData::consumed, &consumedChartData, maxConsumedSinceLastTimeStamp);
        addChartData(&ChartMergeData::allocated, &allocatedChartData, totalAllocated);
        addChartData(&ChartMergeData::allocations, &allocationsChartData, totalAllocations);
        maxConsumedSinceLastTimeStamp = 0;
    }

    void handleAllocation()
    {
        maxConsumedSinceLastTimeStamp = max(maxConsumedSinceLastTimeStamp, leaked);
    }

    void handleDebuggee(const char* command)
    {
        debuggee = command;
    }

    string debuggee;

    struct ChartDataWithLabels
    {
        ChartData data;
        QHash<QString, int> labelIds;
    };
    ChartDataWithLabels consumedChartData;
    ChartDataWithLabels allocationsChartData;
    ChartDataWithLabels allocatedChartData;
    uint64_t maxConsumedSinceLastTimeStamp = 0;

    StringCache stringCache;
};

QString generateSummary(const ParserData& data)
{
    QString ret;
    KFormat format;
    QTextStream stream(&ret);
    const double totalTimeS = 0.001 * data.totalTime;
    stream << "<qt>"
           << i18n("debuggee: %1", QString::fromStdString(data.debuggee)) << "
"
           // xgettext:no-c-format
           << i18n("total runtime: %1s", totalTimeS) << "
"
           << i18n("bytes allocated in total (ignoring deallocations): %1 (%2/s)",
                   format.formatByteSize(data.totalAllocated, 2), format.formatByteSize(data.totalAllocated / totalTimeS)) << "
"
           << i18n("calls to allocation functions: %1 (%2/s)",
                   data.totalAllocations, quint64(data.totalAllocations / totalTimeS)) << "
"
           << i18n("peak heap memory consumption: %1", format.formatByteSize(data.peak)) << "
"
           << i18n("total memory leaked: %1", format.formatByteSize(data.leaked)) << "
";
    stream << "</qt>";
    return ret;
}

void setParents(QVector<RowData>& children, const RowData* parent)
{
    for (auto& row: children) {
        row.parent = parent;
        setParents(row.children, &row);
    }
}

QVector<RowData> mergeAllocations(const ParserData& data)
{
    QVector<RowData> topRows;
    // merge allocations, leave parent pointers invalid (their location may change)
    for (const auto& allocation : data.allocations) {
        auto traceIndex = allocation.traceIndex;
        auto rows = &topRows;
        while (traceIndex) {
            const auto& trace = data.findTrace(traceIndex);
            const auto& ip = data.findIp(trace.ipIndex);
            // TODO: only store the IpIndex and use that
            auto location = data.stringCache.location(ip);
            auto it = lower_bound(rows->begin(), rows->end(), location);
            if (it != rows->end() && it->location == location) {
                it->allocated += allocation.allocated;
                it->allocations += allocation.allocations;
                it->leaked += allocation.leaked;
                it->peak += allocation.peak;
            } else {
                it = rows->insert(it, {allocation.allocations, allocation.peak, allocation.leaked, allocation.allocated,
                                        location, nullptr, {}});
            }
            if (data.isStopIndex(ip.functionIndex)) {
                break;
            }
            traceIndex = trace.parentIndex;
            rows = &it->children;
        }
    }
    // now set the parents, the data is constant from here on
    setParents(topRows, nullptr);
    return topRows;
}

RowData* findByLocation(const RowData& row, QVector<RowData>* data)
{
    for (int i = 0; i < data->size(); ++i) {
        if (data->at(i).location == row.location) {
            return data->data() + i;
        }
    }
    return nullptr;
}

void buildTopDown(const QVector<RowData>& bottomUpData, QVector<RowData>* topDownData)
{
    foreach (const auto& row, bottomUpData) {
        if (row.children.isEmpty()) {
            // leaf node found, bubble up the parent chain to build a top-down tree
            auto node = &row;
            auto stack = topDownData;
            while (node) {
                auto data = findByLocation(*node, stack);
                if (!data) {
                    // create an empty top-down item for this bottom-up node
                    *stack << RowData{0, 0, 0, 0, node->location, nullptr, {}};
                    data = &stack->back();
                }
                // always use the leaf node's cost and propagate that one up the chain
                // otherwise we'd count the cost of some nodes multiple times
                data->allocations += row.allocations;
                data->peak += row.peak;
                data->leaked += row.leaked;
                data->allocated += row.allocated;
                stack = &data->children;
                node = node->parent;
            }
        } else {
            // recurse to find a leaf
            buildTopDown(row.children, topDownData);
        }
    }
}

QVector<RowData> toTopDownData(const QVector<RowData>& bottomUpData)
{
    QVector<RowData> topRows;
    buildTopDown(bottomUpData, &topRows);
    // now set the parents, the data is constant from here on
    setParents(topRows, nullptr);
    return topRows;
}

}

Parser::Parser(QObject* parent)
    : QObject(parent)
{}

Parser::~Parser() = default;

void Parser::parse(const QString& path)
{
    using namespace ThreadWeaver;
    stream() << make_job([=]() {
        ParserData data;
        data.read(path.toStdString());
        emit summaryAvailable(generateSummary(data));
        const auto mergedAllocations = mergeAllocations(data);
        emit bottomUpDataAvailable(mergedAllocations);
        emit consumedChartDataAvailable(data.consumedChartData.data);
        emit allocationsChartDataAvailable(data.allocationsChartData.data);
        emit allocatedChartDataAvailable(data.allocatedChartData.data);
        const auto topDownData = toTopDownData(mergedAllocations);
        emit topDownDataAvailable(topDownData);
        emit flameGraphDataAvailable(FlameGraph::parseData(topDownData));
        emit finished();
    });
}
<|endoftext|>


<commit_before>class JointUtils
{
public:
  JointUtils (){

    // Atlas:
    // Note: ordering here MUST match that in AtlasControlTypes.h ***********************
    atlas_joint_names = {"back_bkz", "back_bky", "back_bkx",
        "neck_ay", "l_leg_hpz", "l_leg_hpx", "l_leg_hpy",
        "l_leg_kny", "l_leg_aky", "l_leg_akx", "r_leg_hpz",
        "r_leg_hpx", "r_leg_hpy", "r_leg_kny", "r_leg_aky",
        "r_leg_akx", "l_arm_usy", "l_arm_shx", "l_arm_ely",
        "l_arm_elx", "l_arm_uwy", "l_arm_mwx", "r_arm_usy",
        "r_arm_shx", "r_arm_ely", "r_arm_elx", "r_arm_uwy", "r_arm_mwx"};

    head_joint_names = {"hokuyo_joint","pre_spindle_cal_x_joint", "pre_spindle_cal_y_joint",
        "pre_spindle_cal_z_joint", "pre_spindle_cal_roll_joint", "pre_spindle_cal_pitch_joint",
        "pre_spindle_cal_yaw_joint", "post_spindle_cal_x_joint", "post_spindle_cal_y_joint",
        "post_spindle_cal_z_joint", "post_spindle_cal_roll_joint", "post_spindle_cal_pitch_joint", "post_spindle_cal_yaw_joint" };
    simple_head_joint_names =  {"hokuyo_joint"}; // used in simulation

    sandia_l_joint_names = {"left_f0_j0","left_f0_j1","left_f0_j2",   "left_f1_j0","left_f1_j1","left_f1_j2",
      "left_f2_j0","left_f2_j1","left_f2_j2",   "left_f3_j0","left_f3_j1","left_f3_j2" };
    sandia_r_joint_names = {"right_f0_j0","right_f0_j1","right_f0_j2",  "right_f1_j0","right_f1_j1","right_f1_j2",
      "right_f2_j0","right_f2_j1","right_f2_j2",  "right_f3_j0","right_f3_j1","right_f3_j2" };

    /// iRobot:
    irobot_l_joint_names = {"left_finger[0]/joint_base_rotation", "left_finger[0]/joint_base",
        "left_finger[0]/joint_flex", "left_finger[1]/joint_base_rotation",
        "left_finger[1]/joint_base", "left_finger[1]/joint_flex",
        "left_finger[2]/joint_base", "left_finger[2]/joint_flex" };
    irobot_r_joint_names = {"right_finger[0]/joint_base_rotation", "right_finger[0]/joint_base",
        "right_finger[0]/joint_flex", "right_finger[1]/joint_base_rotation",
        "right_finger[1]/joint_base", "right_finger[1]/joint_flex",
        "right_finger[2]/joint_base", "right_finger[2]/joint_flex" };

    /// Robotiq:
    robotiq_l_joint_names = { "left_finger_1_joint_1", "left_finger_1_joint_2", "left_finger_1_joint_3",
        "left_finger_2_joint_1", "left_finger_2_joint_2", "left_finger_2_joint_3",
        "left_finger_middle_joint_1", "left_finger_middle_joint_2", "left_finger_middle_joint_3",
        "left_palm_finger_1_joint", "left_palm_finger_2_joint"};
    robotiq_r_joint_names = { "right_finger_1_joint_1", "right_finger_1_joint_2", "right_finger_1_joint_3",
        "right_finger_2_joint_1", "right_finger_2_joint_2", "right_finger_2_joint_3",
        "right_finger_middle_joint_1", "right_finger_middle_joint_2", "right_finger_middle_joint_3",
        "right_palm_finger_1_joint", "right_palm_finger_2_joint"};

  };
  ~JointUtils() {}

  std::vector<std::string> atlas_joint_names, head_joint_names, simple_head_joint_names;
  std::vector<std::string> irobot_l_joint_names, irobot_r_joint_names;
  std::vector<std::string> sandia_l_joint_names, sandia_r_joint_names;
  std::vector<std::string> robotiq_l_joint_names, robotiq_r_joint_names;

private:
};

<commit_msg>git-svn-id: https://svn.csail.mit.edu/drc/trunk@7981 c7283977-0100-402a-a91a-fa70b306dbfe<commit_after>class JointUtils
{
public:
  JointUtils (){

    // Atlas:
    // Note: ordering here MUST match that in AtlasControlTypes.h ***********************
    atlas_joint_names = {"back_bkz", "back_bky", "back_bkx",
        "neck_ay", "l_leg_hpz", "l_leg_hpx", "l_leg_hpy",
        "l_leg_kny", "l_leg_aky", "l_leg_akx", "r_leg_hpz",
        "r_leg_hpx", "r_leg_hpy", "r_leg_kny", "r_leg_aky",
        "r_leg_akx", "l_arm_usy", "l_arm_shx", "l_arm_ely",
        "l_arm_elx", "l_arm_uwy", "l_arm_mwx", "r_arm_usy",
        "r_arm_shx", "r_arm_ely", "r_arm_elx", "r_arm_uwy", "r_arm_mwx"};

    head_joint_names = {"hokuyo_joint","pre_spindle_cal_x_joint", "pre_spindle_cal_y_joint",
        "pre_spindle_cal_z_joint", "pre_spindle_cal_roll_joint", "pre_spindle_cal_pitch_joint",
        "pre_spindle_cal_yaw_joint", "post_spindle_cal_x_joint", "post_spindle_cal_y_joint",
        "post_spindle_cal_z_joint", "post_spindle_cal_roll_joint", "post_spindle_cal_pitch_joint", "post_spindle_cal_yaw_joint" };
    simple_head_joint_names =  {"hokuyo_joint"}; // used in simulation

    sandia_l_joint_names = {"left_f0_j0","left_f0_j1","left_f0_j2",   "left_f1_j0","left_f1_j1","left_f1_j2",
      "left_f2_j0","left_f2_j1","left_f2_j2",   "left_f3_j0","left_f3_j1","left_f3_j2" };
    sandia_r_joint_names = {"right_f0_j0","right_f0_j1","right_f0_j2",  "right_f1_j0","right_f1_j1","right_f1_j2",
      "right_f2_j0","right_f2_j1","right_f2_j2",  "right_f3_j0","right_f3_j1","right_f3_j2" };

    /// iRobot:
    irobot_l_joint_names = {"left_finger[0]/joint_base_rotation", "left_finger[0]/joint_base",
        "left_finger[0]/joint_flex", "left_finger[1]/joint_base_rotation",
        "left_finger[1]/joint_base", "left_finger[1]/joint_flex",
        "left_finger[2]/joint_base", "left_finger[2]/joint_flex" };
    irobot_r_joint_names = {"right_finger[0]/joint_base_rotation", "right_finger[0]/joint_base",
        "right_finger[0]/joint_flex", "right_finger[1]/joint_base_rotation",
        "right_finger[1]/joint_base", "right_finger[1]/joint_flex",
        "right_finger[2]/joint_base", "right_finger[2]/joint_flex" };

    /// Robotiq:
    robotiq_l_joint_names = { "left_finger_1_joint_1", "left_finger_1_joint_2", "left_finger_1_joint_3",
        "left_finger_2_joint_1", "left_finger_2_joint_2", "left_finger_2_joint_3",
        "left_finger_middle_joint_1", "left_finger_middle_joint_2", "left_finger_middle_joint_3",
        "left_palm_finger_1_joint", "left_palm_finger_2_joint"};
    robotiq_r_joint_names = { "right_finger_1_joint_1", "right_finger_1_joint_2", "right_finger_1_joint_3",
        "right_finger_2_joint_1", "right_finger_2_joint_2", "right_finger_2_joint_3",
        "right_finger_middle_joint_1", "right_finger_middle_joint_2", "right_finger_middle_joint_3",
        "right_palm_finger_1_joint", "right_palm_finger_2_joint"};

    all_joint_names.append(atlas_joint_names);
    all_joint_names.append(head_joint_names);
    // all_joint_names.append(simple_head_joint_names); // skipped as its in the above
    all_joint_names.append(sandia_l_joint_names);
    all_joint_names.append(sandia_r_joint_names);

    all_joint_names.append(irobot_l_joint_names);
    all_joint_names.append(irobot_r_joint_names);

    all_joint_names.append(robotiq_l_joint_names);
    all_joint_names.append(robotiq_r_joint_names);
  };
  ~JointUtils() {}

  std::vector<std::string> atlas_joint_names, head_joint_names, simple_head_joint_names;
  std::vector<std::string> irobot_l_joint_names, irobot_r_joint_names;
  std::vector<std::string> sandia_l_joint_names, sandia_r_joint_names;
  std::vector<std::string> robotiq_l_joint_names, robotiq_r_joint_names;

  std::vector<std::string> all_joint_names;
private:
};

<|endoftext|>


<commit_before>// Copyright (C) 2010-2014 Joshua Boyce.
// See the file COPYING for copying permission.

#include "tone_mapping.hpp"

#include <iostream>

#include <hadesmem/error.hpp>
#include <hadesmem/find_pattern.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/read.hpp>
#include <hadesmem/write.hpp>

void SetToneMappingType(hadesmem::Process const& process, std::uint32_t type)
{
  std::cout << "\nPreparing to set tone mapping type.\n";

  // eso.live.1.1.2.995904 (dumped with module base of 0x00960000)
  // .text:00C74BCB                 mov     eax, ds:dword_18BC774
  // .text:00C74BD0                 cmp     eax, ebx
  // .text:00C74BD2                 jz      short loc_C74BE0
  // .text:00C74BD4                 push    eax
  auto tone_mapping_type_ref =
    static_cast<std::uint8_t*>(hadesmem::Find(process,
                                              L"",
                                              L"A1 ?? ?? ?? ?? 3B C3 74 0C 50",
                                              hadesmem::PatternFlags::kNone,
                                              0));
  auto tone_mapping_type_ref_offset = 0x01;
  if (!tone_mapping_type_ref)
  {
    // In 1.2.0 the code changed due to a new flag being added which toggles
    // tone mapping on or off, controlled by a new setting (aptly named
    // "TONE_MAPPING"). I couldn't see anywhere where the actual tone mapping
    // type was being set though so it seems a bit pointless, but maybe I've
    // simply overlooked it or they plan on adding that in the future... Either
    // way, I didn't look very hard and this new pattern works so I'll continue
    // doing it this way until the functionality is properly exposed in the UI.
    // eso.rc.1.2.0.999025 (dumped with module base of 0x00A90000)
    // .text:00E8A424                 jz      short loc_E8A443
    // .text:00E8A426                 lea     ecx, [ebp+var_C8]
    // .text:00E8A42C                 call    sub_1338A70
    // .text:00E8A431                 mov     ecx, ds:dword_1C0F7A8
    tone_mapping_type_ref = static_cast<std::uint8_t*>(
      hadesmem::Find(process,
                     L"",
                     L"74 1D 8D 8D ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 0D",
                     hadesmem::PatternFlags::kThrowOnUnmatch,
                     0));
    tone_mapping_type_ref_offset = 0x0F;
  }
  std::cout << "Got tone mapping type ref. ["
            << static_cast<void*>(tone_mapping_type_ref) << "].\n";

  auto const tone_mapping_type_ptr = hadesmem::Read<std::uint8_t*>(
    process, tone_mapping_type_ref + tone_mapping_type_ref_offset);
  std::cout << "Got tone mapping type ptr. ["
            << static_cast<void*>(tone_mapping_type_ptr) << "].\n";

  auto const old_type =
    hadesmem::Read<std::uint32_t>(process, tone_mapping_type_ptr);
  std::cout << "Old tone mapping type is " << old_type << ".\n";
  hadesmem::Write(process, tone_mapping_type_ptr, type);
  std::cout << "New tone mapping type is " << type << ".\n";
}
<commit_msg>* Clarify a comment.<commit_after>// Copyright (C) 2010-2014 Joshua Boyce.
// See the file COPYING for copying permission.

#include "tone_mapping.hpp"

#include <iostream>

#include <hadesmem/error.hpp>
#include <hadesmem/find_pattern.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/read.hpp>
#include <hadesmem/write.hpp>

void SetToneMappingType(hadesmem::Process const& process, std::uint32_t type)
{
  std::cout << "\nPreparing to set tone mapping type.\n";

  // eso.live.1.1.2.995904 (dumped with module base of 0x00960000)
  // .text:00C74BCB                 mov     eax, ds:dword_18BC774
  // .text:00C74BD0                 cmp     eax, ebx
  // .text:00C74BD2                 jz      short loc_C74BE0
  // .text:00C74BD4                 push    eax
  auto tone_mapping_type_ref =
    static_cast<std::uint8_t*>(hadesmem::Find(process,
                                              L"",
                                              L"A1 ?? ?? ?? ?? 3B C3 74 0C 50",
                                              hadesmem::PatternFlags::kNone,
                                              0));
  auto tone_mapping_type_ref_offset = 0x01;
  if (!tone_mapping_type_ref)
  {
    // In 1.2.0 the code changed due to a new flag being added which toggles
    // tone mapping on or off, controlled by a new setting (aptly named
    // "TONE_MAPPING"). I couldn't see anywhere where the actual tone mapping
    // type was being set though so it seems a bit pointless, but maybe I've
    // simply overlooked it or they plan on adding that in the future... Either
    // way, I didn't look very hard and this new pattern works so I'll continue
    // doing it this way until the functionality is properly exposed.
    // eso.rc.1.2.0.999025 (dumped with module base of 0x00A90000)
    // .text:00E8A424                 jz      short loc_E8A443
    // .text:00E8A426                 lea     ecx, [ebp+var_C8]
    // .text:00E8A42C                 call    sub_1338A70
    // .text:00E8A431                 mov     ecx, ds:dword_1C0F7A8
    tone_mapping_type_ref = static_cast<std::uint8_t*>(
      hadesmem::Find(process,
                     L"",
                     L"74 1D 8D 8D ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 0D",
                     hadesmem::PatternFlags::kThrowOnUnmatch,
                     0));
    tone_mapping_type_ref_offset = 0x0F;
  }
  std::cout << "Got tone mapping type ref. ["
            << static_cast<void*>(tone_mapping_type_ref) << "].\n";

  auto const tone_mapping_type_ptr = hadesmem::Read<std::uint8_t*>(
    process, tone_mapping_type_ref + tone_mapping_type_ref_offset);
  std::cout << "Got tone mapping type ptr. ["
            << static_cast<void*>(tone_mapping_type_ptr) << "].\n";

  auto const old_type =
    hadesmem::Read<std::uint32_t>(process, tone_mapping_type_ptr);
  std::cout << "Old tone mapping type is " << old_type << ".\n";
  hadesmem::Write(process, tone_mapping_type_ptr, type);
  std::cout << "New tone mapping type is " << type << ".\n";
}
<|endoftext|>


<commit_before> /*
    kopetechatwindowstylemanager.cpp - Manager all chat window styles

    Copyright (c) 2005      by Michaël Larouche     <larouche@kde.org>

    Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "kopetechatwindowstylemanager.h"

// Qt includes
#include <QStack>
#include <QFileInfo>

// KDE includes
#include <kstandarddirs.h>
#include <kdirlister.h>
#include <kdebug.h>
#include <kurl.h>
#include <kglobal.h>
#include <karchive.h>
#include <kzip.h>
#include <ktar.h>
#include <kmimetype.h>
#include <kio/netaccess.h>
#include <ksharedconfig.h>

#include "kopetechatwindowstyle.h"

class ChatWindowStyleManager::Private
{
public:
	Private()
	 : styleDirLister(0)
	{}

	~Private()
	{
		if(styleDirLister)
		{
			styleDirLister->deleteLater();
		}

		qDeleteAll(stylePool);
	}

	KDirLister *styleDirLister;
	QStringList availableStyles;

	// key = style name, value = ChatWindowStyle instance
	QHash<QString, ChatWindowStyle*> stylePool;

	QStack<KUrl> styleDirs;
};

ChatWindowStyleManager *ChatWindowStyleManager::self()
{
	static ChatWindowStyleManager s;
	return &s;
}

ChatWindowStyleManager::ChatWindowStyleManager(QObject *parent)
	: QObject(parent), d(new Private())
{
	kDebug(14000) ;
	loadStyles();
}

ChatWindowStyleManager::~ChatWindowStyleManager()
{
	kDebug(14000) ;
	delete d;
}

void ChatWindowStyleManager::loadStyles()
{
        QStringList chatStyles = KGlobal::dirs()->findDirs( "appdata", QLatin1String( "styles" ) );
	foreach(const QString &styleDir, chatStyles)
	{
		kDebug(14000) << styleDir;
		d->styleDirs.push( KUrl(styleDir) );
	}

	d->styleDirLister = new KDirLister(this);
	d->styleDirLister->setDirOnlyMode(true);

	connect(d->styleDirLister, SIGNAL(newItems(const KFileItemList &)), this, SLOT(slotNewStyles(const KFileItemList &)));
	connect(d->styleDirLister, SIGNAL(completed()), this, SLOT(slotDirectoryFinished()));

	if( !d->styleDirs.isEmpty() )
		d->styleDirLister->openUrl(d->styleDirs.pop(), true);
}

QStringList ChatWindowStyleManager::getAvailableStyles() const
{
	return d->availableStyles;
}

int ChatWindowStyleManager::installStyle(const QString &styleBundlePath)
{
	QString localStyleDir;
	QStringList chatStyles = KGlobal::dirs()->findDirs( "appdata", QLatin1String( "styles" ) );
	// findDirs returns preferred paths first, let's check if one of them is writable
	foreach(const QString& styleDir, chatStyles)
	{
		if(QFileInfo(styleDir).isWritable())
		{
			localStyleDir = styleDir;
			break;
		}
	}
	if( localStyleDir.isEmpty() ) // none of dirs is writable
	{
		return StyleNoDirectoryValid;
	}

	KArchiveEntry *currentEntry = 0L;
	KArchiveDirectory* currentDir = 0L;
	KArchive *archive = 0L;

	// Find mimetype for current bundle. ZIP and KTar need separate constructor
	QString currentBundleMimeType = KMimeType::findByPath(styleBundlePath, 0, false)->name();
	if(currentBundleMimeType == "application/zip")
	{
		archive = new KZip(styleBundlePath);
	}
	else if( currentBundleMimeType == "application/x-compressed-tar" || currentBundleMimeType == "application/x-bzip-compressed-tar" || currentBundleMimeType == "application/x-gzip" || currentBundleMimeType == "application/x-bzip" )
	{
		archive = new KTar(styleBundlePath);
	}
	else
	{
		return StyleCannotOpen;
	}

	if ( !archive->open(QIODevice::ReadOnly) )
	{
		delete archive;

		return StyleCannotOpen;
	}

	const KArchiveDirectory* rootDir = archive->directory();

	// Ok where we go to check if the archive is valid.
	// Each time we found a correspondance to a theme bundle, we add a point to validResult.
	// A valid style bundle must have:
	// -a Contents, Contents/Resources, Co/Res/Incoming, Co/Res/Outgoing dirs
	// main.css, Footer.html, Header.html, Status.html files in Contents/Ressources.
	// So for a style bundle to be valid, it must have a result greather than 8, because we test for 8 required entry.
	int validResult = 0;
	QStringList entries = rootDir->entries();
	// Will be reused later.
	QStringList::Iterator entriesIt, entriesItEnd = entries.end();
	for(entriesIt = entries.begin(); entriesIt != entries.end(); ++entriesIt)
	{
		currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*entriesIt));
// 		kDebug() << "Current entry name: " << currentEntry->name();
		if (currentEntry->isDirectory())
		{
			currentDir = dynamic_cast<KArchiveDirectory*>( currentEntry );
			if (currentDir)
			{
				if( currentDir->entry(QString::fromUtf8("Contents")) )
				{
// 					kDebug() << "Contents found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources")) )
				{
// 					kDebug() << "Contents/Resources found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Incoming")) )
				{
// 					kDebug() << "Contents/Resources/Incoming found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Outgoing")) )
				{
// 					kDebug() << "Contents/Resources/Outgoing found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/main.css")) )
				{
// 					kDebug() << "Contents/Resources/main.css found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Footer.html")) )
				{
// 					kDebug() << "Contents/Resources/Footer.html found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Status.html")) )
				{
// 					kDebug() << "Contents/Resources/Status.html found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Header.html")) )
				{
// 					kDebug() << "Contents/Resources/Header.html found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Incoming/Content.html")) )
				{
// 					kDebug() << "Contents/Resources/Incoming/Content.html found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Outgoing/Content.html")) )
				{
// 					kDebug() << "Contents/Resources/Outgoing/Content.html found";
					validResult += 1;
				}
			}
		}
	}
// 	kDebug() << "Valid result: " << QString::number(validResult);
	// The archive is a valid style bundle.
	if(validResult >= 8)
	{
		bool installOk = false;
		for(entriesIt = entries.begin(); entriesIt != entries.end(); ++entriesIt)
		{
			currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*entriesIt));
			if(currentEntry && currentEntry->isDirectory())
			{
				// Ignore this MacOS X "garbage" directory in zip.
				if(currentEntry->name() == QString::fromUtf8("__MACOSX"))
				{
					continue;
				}
				else
				{
					currentDir = dynamic_cast<KArchiveDirectory*>(currentEntry);
					if(currentDir)
					{
						currentDir->copyTo(localStyleDir + currentDir->name());
						installOk = true;
					}
				}
			}
		}

		archive->close();
		delete archive;

		if(installOk)
			return StyleInstallOk;
		else
			return StyleUnknow;
	}
	else
	{
		archive->close();
		delete archive;

		return StyleNotValid;
	}

	if(archive)
	{
		archive->close();
		delete archive;
	}

	return StyleUnknow;
}

bool ChatWindowStyleManager::removeStyle(const QString &styleName)
{
	kDebug(14000) << styleName;
	// Find for the current style in avaiableStyles map.
	int foundStyleIdx = d->availableStyles.indexOf(styleName);

	if(foundStyleIdx != -1)
	{
		d->availableStyles.removeAt(foundStyleIdx);

		// Remove and delete style from pool if needed.
		if( d->stylePool.contains(styleName) )
		{
			ChatWindowStyle *deletedStyle = d->stylePool[styleName];
			d->stylePool.remove(styleName);
			delete deletedStyle;
		}

		QStringList styleDirs = KGlobal::dirs()->findDirs("appdata", QString("styles/%1").arg(styleName));
		if(styleDirs.isEmpty())
		{
			kDebug(14000) << "Failed to find style" << styleName;
			return false;
		}

		// attempt to delete all dirs with this style
		int numDeleted = 0;
		foreach( const QString& stylePath, styleDirs )
		{
			KUrl urlStyle(stylePath);
			// Do the actual deletion of the directory style.
			if(KIO::NetAccess::del( urlStyle, 0 ))
				numDeleted++;
		}
		return numDeleted == styleDirs.count();
	}
	else
	{
		return false;
	}
}

ChatWindowStyle *ChatWindowStyleManager::getStyleFromPool(const QString &styleName)
{
	if( d->stylePool.contains(styleName) )
	{
		kDebug(14000) << styleName << " was on the pool";

		// NOTE: This is a hidden config switch for style developers
		// Check in the config if the cache is disabled.
		// if the cache is disabled, reload the style every time it's getted.
		KConfigGroup config(KGlobal::config(), "KopeteStyleDebug");
		bool disableCache = config.readEntry("disableStyleCache", false);
		if(disableCache)
		{
			d->stylePool[styleName]->reload();
		}

		return d->stylePool[styleName];
	}
	else
	{
		// Build a chat window style and list its variants, then add it to the pool.
		ChatWindowStyle *style = new ChatWindowStyle(styleName, ChatWindowStyle::StyleBuildNormal);
		d->stylePool.insert(styleName, style);

		kDebug(14000) << styleName << " is just created";

		return style;
	}

	return 0;
}

void ChatWindowStyleManager::slotNewStyles(const KFileItemList &dirList)
{
	foreach(KFileItem item, dirList)
	{
		// Ignore data dir(from deprecated XSLT themes)
		if( !item.url().fileName().contains(QString::fromUtf8("data")) )
		{
			kDebug(14000) << "Listing: " << item.url().fileName();
			// If the style path is already in the pool, that's mean the style was updated on disk
			// Reload the style
			QString styleName = item.url().fileName();
			if( d->stylePool.contains(styleName) )
			{
				kDebug(14000) << "Updating style: " << styleName;

				d->stylePool[styleName]->reload();

				// Add to avaialble if required.
				if( d->availableStyles.indexOf(styleName) == -1 )
					d->availableStyles.append(styleName);
			}
			else
			{
				// TODO: Use name from Info.plist
				d->availableStyles.append(styleName);
			}
		}
	}
}

void ChatWindowStyleManager::slotDirectoryFinished()
{
	// Start another scanning if the directories stack is not empty
	if( !d->styleDirs.isEmpty() )
	{
		kDebug(14000) << "Starting another directory.";
		d->styleDirLister->openUrl(d->styleDirs.pop(), true);
	}
	else
	{
		emit loadStylesFinished();
	}
}

#include "kopetechatwindowstylemanager.moc"
<commit_msg>KDirLister openUrl parameters are now flags<commit_after> /*
    kopetechatwindowstylemanager.cpp - Manager all chat window styles

    Copyright (c) 2005      by Michaël Larouche     <larouche@kde.org>

    Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "kopetechatwindowstylemanager.h"

// Qt includes
#include <QStack>
#include <QFileInfo>

// KDE includes
#include <kstandarddirs.h>
#include <kdirlister.h>
#include <kdebug.h>
#include <kurl.h>
#include <kglobal.h>
#include <karchive.h>
#include <kzip.h>
#include <ktar.h>
#include <kmimetype.h>
#include <kio/netaccess.h>
#include <ksharedconfig.h>

#include "kopetechatwindowstyle.h"

class ChatWindowStyleManager::Private
{
public:
	Private()
	 : styleDirLister(0)
	{}

	~Private()
	{
		if(styleDirLister)
		{
			styleDirLister->deleteLater();
		}

		qDeleteAll(stylePool);
	}

	KDirLister *styleDirLister;
	QStringList availableStyles;

	// key = style name, value = ChatWindowStyle instance
	QHash<QString, ChatWindowStyle*> stylePool;

	QStack<KUrl> styleDirs;
};

ChatWindowStyleManager *ChatWindowStyleManager::self()
{
	static ChatWindowStyleManager s;
	return &s;
}

ChatWindowStyleManager::ChatWindowStyleManager(QObject *parent)
	: QObject(parent), d(new Private())
{
	kDebug(14000) ;
	loadStyles();
}

ChatWindowStyleManager::~ChatWindowStyleManager()
{
	kDebug(14000) ;
	delete d;
}

void ChatWindowStyleManager::loadStyles()
{
        QStringList chatStyles = KGlobal::dirs()->findDirs( "appdata", QLatin1String( "styles" ) );
	foreach(const QString &styleDir, chatStyles)
	{
		kDebug(14000) << styleDir;
		d->styleDirs.push( KUrl(styleDir) );
	}

	d->styleDirLister = new KDirLister(this);
	d->styleDirLister->setDirOnlyMode(true);

	connect(d->styleDirLister, SIGNAL(newItems(const KFileItemList &)), this, SLOT(slotNewStyles(const KFileItemList &)));
	connect(d->styleDirLister, SIGNAL(completed()), this, SLOT(slotDirectoryFinished()));

	if( !d->styleDirs.isEmpty() )
		d->styleDirLister->openUrl(d->styleDirs.pop(), KDirLister::Keep);
}

QStringList ChatWindowStyleManager::getAvailableStyles() const
{
	return d->availableStyles;
}

int ChatWindowStyleManager::installStyle(const QString &styleBundlePath)
{
	QString localStyleDir;
	QStringList chatStyles = KGlobal::dirs()->findDirs( "appdata", QLatin1String( "styles" ) );
	// findDirs returns preferred paths first, let's check if one of them is writable
	foreach(const QString& styleDir, chatStyles)
	{
		if(QFileInfo(styleDir).isWritable())
		{
			localStyleDir = styleDir;
			break;
		}
	}
	if( localStyleDir.isEmpty() ) // none of dirs is writable
	{
		return StyleNoDirectoryValid;
	}

	KArchiveEntry *currentEntry = 0L;
	KArchiveDirectory* currentDir = 0L;
	KArchive *archive = 0L;

	// Find mimetype for current bundle. ZIP and KTar need separate constructor
	QString currentBundleMimeType = KMimeType::findByPath(styleBundlePath, 0, false)->name();
	if(currentBundleMimeType == "application/zip")
	{
		archive = new KZip(styleBundlePath);
	}
	else if( currentBundleMimeType == "application/x-compressed-tar" || currentBundleMimeType == "application/x-bzip-compressed-tar" || currentBundleMimeType == "application/x-gzip" || currentBundleMimeType == "application/x-bzip" )
	{
		archive = new KTar(styleBundlePath);
	}
	else
	{
		return StyleCannotOpen;
	}

	if ( !archive->open(QIODevice::ReadOnly) )
	{
		delete archive;

		return StyleCannotOpen;
	}

	const KArchiveDirectory* rootDir = archive->directory();

	// Ok where we go to check if the archive is valid.
	// Each time we found a correspondance to a theme bundle, we add a point to validResult.
	// A valid style bundle must have:
	// -a Contents, Contents/Resources, Co/Res/Incoming, Co/Res/Outgoing dirs
	// main.css, Footer.html, Header.html, Status.html files in Contents/Ressources.
	// So for a style bundle to be valid, it must have a result greather than 8, because we test for 8 required entry.
	int validResult = 0;
	QStringList entries = rootDir->entries();
	// Will be reused later.
	QStringList::Iterator entriesIt, entriesItEnd = entries.end();
	for(entriesIt = entries.begin(); entriesIt != entries.end(); ++entriesIt)
	{
		currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*entriesIt));
// 		kDebug() << "Current entry name: " << currentEntry->name();
		if (currentEntry->isDirectory())
		{
			currentDir = dynamic_cast<KArchiveDirectory*>( currentEntry );
			if (currentDir)
			{
				if( currentDir->entry(QString::fromUtf8("Contents")) )
				{
// 					kDebug() << "Contents found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources")) )
				{
// 					kDebug() << "Contents/Resources found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Incoming")) )
				{
// 					kDebug() << "Contents/Resources/Incoming found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Outgoing")) )
				{
// 					kDebug() << "Contents/Resources/Outgoing found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/main.css")) )
				{
// 					kDebug() << "Contents/Resources/main.css found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Footer.html")) )
				{
// 					kDebug() << "Contents/Resources/Footer.html found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Status.html")) )
				{
// 					kDebug() << "Contents/Resources/Status.html found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Header.html")) )
				{
// 					kDebug() << "Contents/Resources/Header.html found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Incoming/Content.html")) )
				{
// 					kDebug() << "Contents/Resources/Incoming/Content.html found";
					validResult += 1;
				}
				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Outgoing/Content.html")) )
				{
// 					kDebug() << "Contents/Resources/Outgoing/Content.html found";
					validResult += 1;
				}
			}
		}
	}
// 	kDebug() << "Valid result: " << QString::number(validResult);
	// The archive is a valid style bundle.
	if(validResult >= 8)
	{
		bool installOk = false;
		for(entriesIt = entries.begin(); entriesIt != entries.end(); ++entriesIt)
		{
			currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*entriesIt));
			if(currentEntry && currentEntry->isDirectory())
			{
				// Ignore this MacOS X "garbage" directory in zip.
				if(currentEntry->name() == QString::fromUtf8("__MACOSX"))
				{
					continue;
				}
				else
				{
					currentDir = dynamic_cast<KArchiveDirectory*>(currentEntry);
					if(currentDir)
					{
						currentDir->copyTo(localStyleDir + currentDir->name());
						installOk = true;
					}
				}
			}
		}

		archive->close();
		delete archive;

		if(installOk)
			return StyleInstallOk;
		else
			return StyleUnknow;
	}
	else
	{
		archive->close();
		delete archive;

		return StyleNotValid;
	}

	if(archive)
	{
		archive->close();
		delete archive;
	}

	return StyleUnknow;
}

bool ChatWindowStyleManager::removeStyle(const QString &styleName)
{
	kDebug(14000) << styleName;
	// Find for the current style in avaiableStyles map.
	int foundStyleIdx = d->availableStyles.indexOf(styleName);

	if(foundStyleIdx != -1)
	{
		d->availableStyles.removeAt(foundStyleIdx);

		// Remove and delete style from pool if needed.
		if( d->stylePool.contains(styleName) )
		{
			ChatWindowStyle *deletedStyle = d->stylePool[styleName];
			d->stylePool.remove(styleName);
			delete deletedStyle;
		}

		QStringList styleDirs = KGlobal::dirs()->findDirs("appdata", QString("styles/%1").arg(styleName));
		if(styleDirs.isEmpty())
		{
			kDebug(14000) << "Failed to find style" << styleName;
			return false;
		}

		// attempt to delete all dirs with this style
		int numDeleted = 0;
		foreach( const QString& stylePath, styleDirs )
		{
			KUrl urlStyle(stylePath);
			// Do the actual deletion of the directory style.
			if(KIO::NetAccess::del( urlStyle, 0 ))
				numDeleted++;
		}
		return numDeleted == styleDirs.count();
	}
	else
	{
		return false;
	}
}

ChatWindowStyle *ChatWindowStyleManager::getStyleFromPool(const QString &styleName)
{
	if( d->stylePool.contains(styleName) )
	{
		kDebug(14000) << styleName << " was on the pool";

		// NOTE: This is a hidden config switch for style developers
		// Check in the config if the cache is disabled.
		// if the cache is disabled, reload the style every time it's getted.
		KConfigGroup config(KGlobal::config(), "KopeteStyleDebug");
		bool disableCache = config.readEntry("disableStyleCache", false);
		if(disableCache)
		{
			d->stylePool[styleName]->reload();
		}

		return d->stylePool[styleName];
	}
	else
	{
		// Build a chat window style and list its variants, then add it to the pool.
		ChatWindowStyle *style = new ChatWindowStyle(styleName, ChatWindowStyle::StyleBuildNormal);
		d->stylePool.insert(styleName, style);

		kDebug(14000) << styleName << " is just created";

		return style;
	}

	return 0;
}

void ChatWindowStyleManager::slotNewStyles(const KFileItemList &dirList)
{
	foreach(KFileItem item, dirList)
	{
		// Ignore data dir(from deprecated XSLT themes)
		if( !item.url().fileName().contains(QString::fromUtf8("data")) )
		{
			kDebug(14000) << "Listing: " << item.url().fileName();
			// If the style path is already in the pool, that's mean the style was updated on disk
			// Reload the style
			QString styleName = item.url().fileName();
			if( d->stylePool.contains(styleName) )
			{
				kDebug(14000) << "Updating style: " << styleName;

				d->stylePool[styleName]->reload();

				// Add to avaialble if required.
				if( d->availableStyles.indexOf(styleName) == -1 )
					d->availableStyles.append(styleName);
			}
			else
			{
				// TODO: Use name from Info.plist
				d->availableStyles.append(styleName);
			}
		}
	}
}

void ChatWindowStyleManager::slotDirectoryFinished()
{
	// Start another scanning if the directories stack is not empty
	if( !d->styleDirs.isEmpty() )
	{
		kDebug(14000) << "Starting another directory.";
		d->styleDirLister->openUrl(d->styleDirs.pop(), KDirLister::Keep);
	}
	else
	{
		emit loadStylesFinished();
	}
}

#include "kopetechatwindowstylemanager.moc"
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: langbox.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: tl $ $Date: 2001-03-22 09:30:28 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

// include ---------------------------------------------------------------

#ifndef _COM_SUN_STAR_LINGUISTIC2_XLINGUSERVICEMANAGER_HDL_
#include <com/sun/star/linguistic2/XLinguServiceManager.hdl>
#endif
#ifndef _LINGUISTIC_MISC_HXX_
#include <linguistic/misc.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include<rtl/ustring.hxx>
#endif

#ifndef _SHL_HXX
#include <tools/shl.hxx>
#endif
#ifndef _ISOLANG_HXX
#include <tools/isolang.hxx>
#endif
#pragma hdrstop

#ifndef _SVX_SCRIPTTYPEITEM_HXX
#include <scripttypeitem.hxx>
#endif
#ifndef _UNO_LINGU_HXX
#include <unolingu.hxx>
#endif
#ifndef _SVX_LANGTAB_HXX
#include <langtab.hxx>
#endif
#include "langbox.hxx"
#include "langtab.hxx"
#include "dialmgr.hxx"
#include "dialogs.hrc"
#include "unolingu.hxx"

using namespace ::rtl;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::linguistic2;
using namespace ::com::sun::star::uno;

#define A2OU(x)     OUString::createFromAscii( x )

//========================================================================
//  list of languages for forbidden chars
//========================================================================

static const LanguageType aForbiddenCharLang[] =
{
    LANGUAGE_CHINESE_TRADITIONAL,
    LANGUAGE_CHINESE_SIMPLIFIED,
    LANGUAGE_JAPANESE,
    LANGUAGE_KOREAN
};

static const int nForbiddenCharLang = sizeof( aForbiddenCharLang ) / sizeof( aForbiddenCharLang[0] );

static BOOL lcl_HasLanguage( const LanguageType *pLang, int nCount, LanguageType nLang )
{
    int i = -1;
    if (pLang && nCount > 0)
    {
        for (i = 0;  i < nCount; ++i )
        {
            if (pLang[i] == nLang)
                break;
        }
    }
    return i >= 0  &&  i < nCount;
}

//========================================================================
//  misc local helper functions
//========================================================================

static Sequence< INT16 > lcl_LocaleSeqToLangSeq( Sequence< Locale > &rSeq )
{
    const Locale *pLocale = rSeq.getConstArray();
    INT32 nCount = rSeq.getLength();

    Sequence< INT16 >   aLangs( nCount );
    INT16 *pLang = aLangs.getArray();
    for (INT32 i = 0;  i < nCount;  ++i)
    {
        pLang[i] = SvxLocaleToLanguage( pLocale[i] );

    }

    return aLangs;
}

static BOOL lcl_SeqHasLang( const Sequence< INT16 > & rLangSeq, INT16 nLang )
{
    INT32 i = -1;
    INT32 nLen = rLangSeq.getLength();
    if (nLen)
    {
        const INT16 *pLang = rLangSeq.getConstArray();
        for (i = 0;  i < nLen;  ++i)
        {
            if (nLang == pLang[i])
                break;
        }
    }
    return i >= 0  &&  i < nLen;
}

//========================================================================
//  class SvxLanguageBox
//========================================================================

USHORT TypeToPos_Impl( LanguageType eType, const ListBox& rLb )
{
    USHORT  nPos   = LISTBOX_ENTRY_NOTFOUND;
    USHORT  nCount = rLb.GetEntryCount();

    for ( USHORT i=0; nPos == LISTBOX_ENTRY_NOTFOUND && i<nCount; i++ )
        if ( eType == LanguageType((ULONG)rLb.GetEntryData(i)) )
            nPos = i;

    return nPos;
}

//-----------------------------------------------------------------------
/*!!! (pb) obsolete
SvxLanguageBox::SvxLanguageBox( Window* pParent, WinBits nWinStyle ) :

    ListBox( pParent, nWinStyle )

{
    m_pLangTable = new SvxLanguageTable;
    aNotCheckedImage = Image( SVX_RES( RID_SVXIMG_NOTCHECKED ) );
    aCheckedImage = Image( SVX_RES( RID_SVXIMG_CHECKED ) );
}
*/
//------------------------------------------------------------------------

SvxLanguageBox::SvxLanguageBox( Window* pParent, const ResId& rResId, BOOL bCheck ) :

    ListBox( pParent, rResId ),

    m_bWithCheckmark( bCheck )
{
    m_pLangTable = new SvxLanguageTable;
    m_aNotCheckedImage = Image( SVX_RES( RID_SVXIMG_NOTCHECKED ) );
    m_aCheckedImage = Image( SVX_RES( RID_SVXIMG_CHECKED ) );
    m_aAllString            = String( SVX_RESSTR( RID_SVXSTR_LANGUAGE_ALL ) );
    m_nLangList             = LANG_LIST_EMPTY;
    m_bHasLangNone          = FALSE;
    m_bLangNoneIsLangAll    = FALSE;

    // display entries sorted
    SetStyle( GetStyle() | WB_SORT );

    if ( m_bWithCheckmark )
    {
        SvxLanguageTable aLangTable;
        const USHORT nCount = aLangTable.GetEntryCount();
        for ( USHORT i = 0; i < nCount; i++ )
        {
            LanguageType nLangType = aLangTable.GetTypeAtIndex( i );

            BOOL bInsert = TRUE;
            if ((LANGUAGE_DONTKNOW == nLangType)  ||
                (LANGUAGE_SYSTEM   == nLangType)  ||
                (LANGUAGE_USER1 <= nLangType  &&  nLangType <= LANGUAGE_USER9))
            {
                bInsert = FALSE;
            }

            if ( bInsert )
                InsertLanguage( nLangType );
        }
        m_nLangList = LANG_LIST_ALL;
    }
}

//------------------------------------------------------------------------

SvxLanguageBox::SvxLanguageBox( Window* pParent, const ResId& rResId ) :
    ListBox( pParent, rResId )
{
    m_pLangTable        = new SvxLanguageTable;
    m_aNotCheckedImage  = Image( SVX_RES( RID_SVXIMG_NOTCHECKED ) );
    m_aCheckedImage     = Image( SVX_RES( RID_SVXIMG_CHECKED ) );
    m_bWithCheckmark    = FALSE;
    m_aAllString            = String( SVX_RESSTR( RID_SVXSTR_LANGUAGE_ALL ) );
    m_nLangList             = LANG_LIST_EMPTY;
    m_bHasLangNone          = FALSE;
    m_bLangNoneIsLangAll    = FALSE;

    // display entries sorted
    SetStyle( GetStyle() | WB_SORT );
}

//------------------------------------------------------------------------

SvxLanguageBox::~SvxLanguageBox()
{
    delete m_pLangTable;
}

//------------------------------------------------------------------------

void SvxLanguageBox::SetLanguageList( INT16 nLangList,
        BOOL bHasLangNone, BOOL bLangNoneIsLangAll, BOOL bCheckSpellAvail )
{
    Clear();

    m_nLangList             = nLangList;
    m_bHasLangNone          = bHasLangNone;
    m_bLangNoneIsLangAll    = bLangNoneIsLangAll;
    m_bWithCheckmark        = bCheckSpellAvail;

    if ( LANG_LIST_EMPTY != nLangList )
    {
        Sequence< INT16 > aSpellAvailLang;
        Sequence< INT16 > aHyphAvailLang;
        Sequence< INT16 > aThesAvailLang;
        if (LinguMgr::GetLngSvcMgr().is())
        {
            Sequence< Locale > aTmp;

            if (LANG_LIST_SPELL_AVAIL & nLangList)
            {
                aTmp = LinguMgr::GetLngSvcMgr()
                            ->getAvailableLocales( A2OU( SN_SPELLCHECKER ) );
                aSpellAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
            }
            if (LANG_LIST_HYPH_AVAIL  & nLangList)
            {
                aTmp = LinguMgr::GetLngSvcMgr()
                            ->getAvailableLocales( A2OU( SN_HYPHENATOR ) );
                aHyphAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
            }
            if (LANG_LIST_THES_AVAIL  & nLangList)
            {
                aTmp = LinguMgr::GetLngSvcMgr()
                            ->getAvailableLocales( A2OU( SN_THESAURUS ) );
                aThesAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
            }
        }

        SvxLanguageTable aLangTable;
        const USHORT nCount = aLangTable.GetEntryCount();
        for ( USHORT i = 0; i < nCount; i++ )
        {
            LanguageType nLangType = aLangTable.GetTypeAtIndex( i );
            BOOL bInsert = FALSE;
            if ( nLangType != LANGUAGE_DONTKNOW &&
                 nLangType != LANGUAGE_SYSTEM   &&
                 nLangType != LANGUAGE_NONE     &&
                !(LANGUAGE_USER1 <= nLangType  &&  nLangType <= LANGUAGE_USER9) )
            {
                if (!bInsert && (nLangList & LANG_LIST_ALL))
                    bInsert |= TRUE;
                if (!bInsert && (nLangList & LANG_LIST_WESTERN))
                    bInsert |= SCRIPTTYPE_LATIN == GetScriptTypeOfLanguage( nLangType );
                if (!bInsert && (nLangList & LANG_LIST_CTL))
                    bInsert |= SCRIPTTYPE_COMPLEX == GetScriptTypeOfLanguage( nLangType );
                if (!bInsert && (nLangList & LANG_LIST_CJK))
                    bInsert |= SCRIPTTYPE_ASIAN == GetScriptTypeOfLanguage( nLangType );
                if (!bInsert && (nLangList & LANG_LIST_FBD_CHARS))
                    bInsert |= lcl_HasLanguage( aForbiddenCharLang,
                                        nForbiddenCharLang, nLangType );
                if (!bInsert && (nLangList & LANG_LIST_SPELL_AVAIL))
                    bInsert |= lcl_SeqHasLang( aSpellAvailLang, nLangType );
                if (!bInsert && (nLangList & LANG_LIST_HYPH_AVAIL))
                    bInsert |= lcl_SeqHasLang( aHyphAvailLang, nLangType );
                if (!bInsert && (nLangList & LANG_LIST_THES_AVAIL))
                    bInsert |= lcl_SeqHasLang( aThesAvailLang, nLangType );
            }

            if (bInsert)
                InsertLanguage( nLangType );
        }

        if (bHasLangNone)
            InsertLanguage( LANGUAGE_NONE );
    }
}

//------------------------------------------------------------------------

USHORT SvxLanguageBox::InsertLanguage( const LanguageType nLangType, USHORT nPos )
{
    String aStrEntry = m_pLangTable->GetString( nLangType );
    if (LANGUAGE_NONE == nLangType && m_bHasLangNone && m_bLangNoneIsLangAll)
        aStrEntry = m_aAllString;

    USHORT nAt = 0;
    if ( m_bWithCheckmark )
    {
        const USHORT nLanguageCount = SvxGetSelectableLanguages().getLength();
        const Language* pLangList = SvxGetSelectableLanguages().getConstArray();
        sal_Bool bFound = sal_False;
        for ( USHORT i = 0; i < nLanguageCount; ++i )
        {
            if ( nLangType == pLangList[i] )
            {
                bFound = sal_True;
                break;
            }
        }

        if ( !bFound )
            nAt = InsertEntry( aStrEntry, m_aNotCheckedImage, nPos );
        else
            nAt = InsertEntry( aStrEntry, m_aCheckedImage, nPos );
    }
    else
        nAt = InsertEntry( aStrEntry, nPos );

    SetEntryData( nAt, (void*)(ULONG)nLangType );
    return nPos;
}

//------------------------------------------------------------------------

void SvxLanguageBox::RemoveLanguage( const LanguageType eLangType )
{
    USHORT nAt = TypeToPos_Impl( eLangType, *this );

    if ( nAt != LISTBOX_ENTRY_NOTFOUND )
        RemoveEntry( nAt );
}

//------------------------------------------------------------------------

LanguageType SvxLanguageBox::GetSelectLanguage() const
{
    LanguageType eType  = LanguageType(LANGUAGE_DONTKNOW);
    USHORT       nPos   = GetSelectEntryPos();

    if ( nPos != LISTBOX_ENTRY_NOTFOUND )
        return LanguageType( (ULONG)GetEntryData(nPos) );
    else
        return LanguageType( LANGUAGE_DONTKNOW );
}

//------------------------------------------------------------------------

void SvxLanguageBox::SelectLanguage( const LanguageType eLangType, BOOL bSelect )
{
    USHORT nAt = TypeToPos_Impl( eLangType, *this );

    if ( nAt != LISTBOX_ENTRY_NOTFOUND )
        SelectEntryPos( nAt, bSelect );
}

//------------------------------------------------------------------------

BOOL SvxLanguageBox::IsLanguageSelected( const LanguageType eLangType ) const
{
    USHORT nAt = TypeToPos_Impl( eLangType, *this );

    if ( nAt != LISTBOX_ENTRY_NOTFOUND )
        return IsEntryPosSelected( nAt );
    else
        return FALSE;
}

<commit_msg>new XAvailableLocales interface used now to check for available Locales<commit_after>/*************************************************************************
 *
 *  $RCSfile: langbox.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: tl $ $Date: 2001-03-28 11:45:54 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

// include ---------------------------------------------------------------

#ifndef _COM_SUN_STAR_LINGUISTIC2_XLINGUSERVICEMANAGER_HDL_
#include <com/sun/star/linguistic2/XLinguServiceManager.hdl>
#endif
#ifndef _COM_SUN_STAR_LINGUISTIC2_XAVAILABLELOCALES_HPP_
#include <com/sun/star/linguistic2/XAvailableLocales.hpp>
#endif
#ifndef _LINGUISTIC_MISC_HXX_
#include <linguistic/misc.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include<rtl/ustring.hxx>
#endif

#ifndef _SHL_HXX
#include <tools/shl.hxx>
#endif
#ifndef _ISOLANG_HXX
#include <tools/isolang.hxx>
#endif
#pragma hdrstop

#ifndef _SVX_SCRIPTTYPEITEM_HXX
#include <scripttypeitem.hxx>
#endif
#ifndef _UNO_LINGU_HXX
#include <unolingu.hxx>
#endif
#ifndef _SVX_LANGTAB_HXX
#include <langtab.hxx>
#endif
#include "langbox.hxx"
#include "langtab.hxx"
#include "dialmgr.hxx"
#include "dialogs.hrc"
#include "unolingu.hxx"

using namespace ::rtl;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::linguistic2;
using namespace ::com::sun::star::uno;

#define A2OU(x)     OUString::createFromAscii( x )

//========================================================================
//  list of languages for forbidden chars
//========================================================================

static const LanguageType aForbiddenCharLang[] =
{
    LANGUAGE_CHINESE_TRADITIONAL,
    LANGUAGE_CHINESE_SIMPLIFIED,
    LANGUAGE_JAPANESE,
    LANGUAGE_KOREAN
};

static const int nForbiddenCharLang = sizeof( aForbiddenCharLang ) / sizeof( aForbiddenCharLang[0] );

static BOOL lcl_HasLanguage( const LanguageType *pLang, int nCount, LanguageType nLang )
{
    int i = -1;
    if (pLang && nCount > 0)
    {
        for (i = 0;  i < nCount; ++i )
        {
            if (pLang[i] == nLang)
                break;
        }
    }
    return i >= 0  &&  i < nCount;
}

//========================================================================
//  misc local helper functions
//========================================================================

static Sequence< INT16 > lcl_LocaleSeqToLangSeq( Sequence< Locale > &rSeq )
{
    const Locale *pLocale = rSeq.getConstArray();
    INT32 nCount = rSeq.getLength();

    Sequence< INT16 >   aLangs( nCount );
    INT16 *pLang = aLangs.getArray();
    for (INT32 i = 0;  i < nCount;  ++i)
    {
        pLang[i] = SvxLocaleToLanguage( pLocale[i] );

    }

    return aLangs;
}

static BOOL lcl_SeqHasLang( const Sequence< INT16 > & rLangSeq, INT16 nLang )
{
    INT32 i = -1;
    INT32 nLen = rLangSeq.getLength();
    if (nLen)
    {
        const INT16 *pLang = rLangSeq.getConstArray();
        for (i = 0;  i < nLen;  ++i)
        {
            if (nLang == pLang[i])
                break;
        }
    }
    return i >= 0  &&  i < nLen;
}

//========================================================================
//  class SvxLanguageBox
//========================================================================

USHORT TypeToPos_Impl( LanguageType eType, const ListBox& rLb )
{
    USHORT  nPos   = LISTBOX_ENTRY_NOTFOUND;
    USHORT  nCount = rLb.GetEntryCount();

    for ( USHORT i=0; nPos == LISTBOX_ENTRY_NOTFOUND && i<nCount; i++ )
        if ( eType == LanguageType((ULONG)rLb.GetEntryData(i)) )
            nPos = i;

    return nPos;
}

//-----------------------------------------------------------------------
/*!!! (pb) obsolete
SvxLanguageBox::SvxLanguageBox( Window* pParent, WinBits nWinStyle ) :

    ListBox( pParent, nWinStyle )

{
    m_pLangTable = new SvxLanguageTable;
    aNotCheckedImage = Image( SVX_RES( RID_SVXIMG_NOTCHECKED ) );
    aCheckedImage = Image( SVX_RES( RID_SVXIMG_CHECKED ) );
}
*/
//------------------------------------------------------------------------

SvxLanguageBox::SvxLanguageBox( Window* pParent, const ResId& rResId, BOOL bCheck ) :

    ListBox( pParent, rResId ),

    m_bWithCheckmark( bCheck )
{
    m_pLangTable = new SvxLanguageTable;
    m_aNotCheckedImage = Image( SVX_RES( RID_SVXIMG_NOTCHECKED ) );
    m_aCheckedImage = Image( SVX_RES( RID_SVXIMG_CHECKED ) );
    m_aAllString            = String( SVX_RESSTR( RID_SVXSTR_LANGUAGE_ALL ) );
    m_nLangList             = LANG_LIST_EMPTY;
    m_bHasLangNone          = FALSE;
    m_bLangNoneIsLangAll    = FALSE;

    // display entries sorted
    SetStyle( GetStyle() | WB_SORT );

    if ( m_bWithCheckmark )
    {
        SvxLanguageTable aLangTable;
        const USHORT nCount = aLangTable.GetEntryCount();
        for ( USHORT i = 0; i < nCount; i++ )
        {
            LanguageType nLangType = aLangTable.GetTypeAtIndex( i );

            BOOL bInsert = TRUE;
            if ((LANGUAGE_DONTKNOW == nLangType)  ||
                (LANGUAGE_SYSTEM   == nLangType)  ||
                (LANGUAGE_USER1 <= nLangType  &&  nLangType <= LANGUAGE_USER9))
            {
                bInsert = FALSE;
            }

            if ( bInsert )
                InsertLanguage( nLangType );
        }
        m_nLangList = LANG_LIST_ALL;
    }
}

//------------------------------------------------------------------------

SvxLanguageBox::SvxLanguageBox( Window* pParent, const ResId& rResId ) :
    ListBox( pParent, rResId )
{
    m_pLangTable        = new SvxLanguageTable;
    m_aNotCheckedImage  = Image( SVX_RES( RID_SVXIMG_NOTCHECKED ) );
    m_aCheckedImage     = Image( SVX_RES( RID_SVXIMG_CHECKED ) );
    m_bWithCheckmark    = FALSE;
    m_aAllString            = String( SVX_RESSTR( RID_SVXSTR_LANGUAGE_ALL ) );
    m_nLangList             = LANG_LIST_EMPTY;
    m_bHasLangNone          = FALSE;
    m_bLangNoneIsLangAll    = FALSE;

    // display entries sorted
    SetStyle( GetStyle() | WB_SORT );
}

//------------------------------------------------------------------------

SvxLanguageBox::~SvxLanguageBox()
{
    delete m_pLangTable;
}

//------------------------------------------------------------------------

void SvxLanguageBox::SetLanguageList( INT16 nLangList,
        BOOL bHasLangNone, BOOL bLangNoneIsLangAll, BOOL bCheckSpellAvail )
{
    Clear();

    m_nLangList             = nLangList;
    m_bHasLangNone          = bHasLangNone;
    m_bLangNoneIsLangAll    = bLangNoneIsLangAll;
    m_bWithCheckmark        = bCheckSpellAvail;

    if ( LANG_LIST_EMPTY != nLangList )
    {
        Sequence< INT16 > aSpellAvailLang;
        Sequence< INT16 > aHyphAvailLang;
        Sequence< INT16 > aThesAvailLang;
        Reference< XAvailableLocales > xAvail( LinguMgr::GetLngSvcMgr(), UNO_QUERY );
        if (xAvail.is())
        {
            Sequence< Locale > aTmp;

            if (LANG_LIST_SPELL_AVAIL & nLangList)
            {
                aTmp = xAvail->getAvailableLocales( A2OU( SN_SPELLCHECKER ) );
                aSpellAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
            }
            if (LANG_LIST_HYPH_AVAIL  & nLangList)
            {
                aTmp = xAvail->getAvailableLocales( A2OU( SN_HYPHENATOR ) );
                aHyphAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
            }
            if (LANG_LIST_THES_AVAIL  & nLangList)
            {
                aTmp = xAvail->getAvailableLocales( A2OU( SN_THESAURUS ) );
                aThesAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
            }
        }

        SvxLanguageTable aLangTable;
        const USHORT nCount = aLangTable.GetEntryCount();
        for ( USHORT i = 0; i < nCount; i++ )
        {
            LanguageType nLangType = aLangTable.GetTypeAtIndex( i );
            BOOL bInsert = FALSE;
            if ( nLangType != LANGUAGE_DONTKNOW &&
                 nLangType != LANGUAGE_SYSTEM   &&
                 nLangType != LANGUAGE_NONE     &&
                !(LANGUAGE_USER1 <= nLangType  &&  nLangType <= LANGUAGE_USER9) )
            {
                if (!bInsert && (nLangList & LANG_LIST_ALL))
                    bInsert |= TRUE;
                if (!bInsert && (nLangList & LANG_LIST_WESTERN))
                    bInsert |= SCRIPTTYPE_LATIN == GetScriptTypeOfLanguage( nLangType );
                if (!bInsert && (nLangList & LANG_LIST_CTL))
                    bInsert |= SCRIPTTYPE_COMPLEX == GetScriptTypeOfLanguage( nLangType );
                if (!bInsert && (nLangList & LANG_LIST_CJK))
                    bInsert |= SCRIPTTYPE_ASIAN == GetScriptTypeOfLanguage( nLangType );
                if (!bInsert && (nLangList & LANG_LIST_FBD_CHARS))
                    bInsert |= lcl_HasLanguage( aForbiddenCharLang,
                                        nForbiddenCharLang, nLangType );
                if (!bInsert && (nLangList & LANG_LIST_SPELL_AVAIL))
                    bInsert |= lcl_SeqHasLang( aSpellAvailLang, nLangType );
                if (!bInsert && (nLangList & LANG_LIST_HYPH_AVAIL))
                    bInsert |= lcl_SeqHasLang( aHyphAvailLang, nLangType );
                if (!bInsert && (nLangList & LANG_LIST_THES_AVAIL))
                    bInsert |= lcl_SeqHasLang( aThesAvailLang, nLangType );
            }

            if (bInsert)
                InsertLanguage( nLangType );
        }

        if (bHasLangNone)
            InsertLanguage( LANGUAGE_NONE );
    }
}

//------------------------------------------------------------------------

USHORT SvxLanguageBox::InsertLanguage( const LanguageType nLangType, USHORT nPos )
{
    String aStrEntry = m_pLangTable->GetString( nLangType );
    if (LANGUAGE_NONE == nLangType && m_bHasLangNone && m_bLangNoneIsLangAll)
        aStrEntry = m_aAllString;

    USHORT nAt = 0;
    if ( m_bWithCheckmark )
    {
        const USHORT nLanguageCount = SvxGetSelectableLanguages().getLength();
        const Language* pLangList = SvxGetSelectableLanguages().getConstArray();
        sal_Bool bFound = sal_False;
        for ( USHORT i = 0; i < nLanguageCount; ++i )
        {
            if ( nLangType == pLangList[i] )
            {
                bFound = sal_True;
                break;
            }
        }

        if ( !bFound )
            nAt = InsertEntry( aStrEntry, m_aNotCheckedImage, nPos );
        else
            nAt = InsertEntry( aStrEntry, m_aCheckedImage, nPos );
    }
    else
        nAt = InsertEntry( aStrEntry, nPos );

    SetEntryData( nAt, (void*)(ULONG)nLangType );
    return nPos;
}

//------------------------------------------------------------------------

void SvxLanguageBox::RemoveLanguage( const LanguageType eLangType )
{
    USHORT nAt = TypeToPos_Impl( eLangType, *this );

    if ( nAt != LISTBOX_ENTRY_NOTFOUND )
        RemoveEntry( nAt );
}

//------------------------------------------------------------------------

LanguageType SvxLanguageBox::GetSelectLanguage() const
{
    LanguageType eType  = LanguageType(LANGUAGE_DONTKNOW);
    USHORT       nPos   = GetSelectEntryPos();

    if ( nPos != LISTBOX_ENTRY_NOTFOUND )
        return LanguageType( (ULONG)GetEntryData(nPos) );
    else
        return LanguageType( LANGUAGE_DONTKNOW );
}

//------------------------------------------------------------------------

void SvxLanguageBox::SelectLanguage( const LanguageType eLangType, BOOL bSelect )
{
    USHORT nAt = TypeToPos_Impl( eLangType, *this );

    if ( nAt != LISTBOX_ENTRY_NOTFOUND )
        SelectEntryPos( nAt, bSelect );
}

//------------------------------------------------------------------------

BOOL SvxLanguageBox::IsLanguageSelected( const LanguageType eLangType ) const
{
    USHORT nAt = TypeToPos_Impl( eLangType, *this );

    if ( nAt != LISTBOX_ENTRY_NOTFOUND )
        return IsEntryPosSelected( nAt );
    else
        return FALSE;
}

<|endoftext|>