<commit_before>//
// Urho3D Engine
// Copyright (c) 2008-2012 Lasse rni
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "Precompiled.h"
#include "AreaAllocator.h"
#include "Context.h"
#include "Deserializer.h"
#include "Font.h"
#include "Graphics.h"
#include "Log.h"
#include "Profiler.h"
#include "Texture2D.h"

#include "ft2build.h"
#include FT_FREETYPE_H

#include "DebugNew.h"

/// FreeType library subsystem.
class FreeTypeLibrary : public Object
{
    OBJECT(FreeTypeLibrary);

public:
    /// Construct.
    FreeTypeLibrary(Context* context) :
        Object(context)
    {
        FT_Error error = FT_Init_FreeType(&mLibrary);
        if (error)
            LOGERROR("Could not initialize FreeType library");
    }

    /// Destruct.
    virtual ~FreeTypeLibrary()
    {
        FT_Done_FreeType(mLibrary);
    }

    FT_Library getLibrary() const { return mLibrary; }

private:
    /// FreeType library.
    FT_Library mLibrary;
};

FontFace::FontFace() :
    hasKerning_(false)
{
}

FontFace::~FontFace()
{
}

const FontGlyph& FontFace::GetGlyph(unsigned c) const
{
    Map<unsigned, unsigned>::ConstIterator i = glyphMapping_.Find(c);
    if (i != glyphMapping_.End())
        return glyphs_[i->second_];
    else
        return glyphs_[0];
}

short FontFace::GetKerning(unsigned c, unsigned d) const
{
    if (!hasKerning_)
        return 0;

    if (c == '\n' || d == '\n')
        return 0;

    unsigned leftIndex = 0;
    unsigned rightIndex = 0;
    Map<unsigned, unsigned>::ConstIterator leftIt = glyphMapping_.Find(c);
    Map<unsigned, unsigned>::ConstIterator rightIt = glyphMapping_.Find(c);
    if (leftIt != glyphMapping_.End())
        leftIndex = leftIt->second_;
    if (rightIt != glyphMapping_.End())
        rightIndex = rightIt->second_;

    Map<unsigned, unsigned>::ConstIterator kerningIt = glyphs_[leftIndex].kerning_.Find(rightIndex);
    if (kerningIt != glyphs_[leftIndex].kerning_.End())
        return kerningIt->second_;
    else
        return 0;
}

OBJECTTYPESTATIC(FreeTypeLibrary);
OBJECTTYPESTATIC(Font);

Font::Font(Context* context) :
    Resource(context),
    fontDataSize_(0)
{
    // Create & initialize FreeType library if it does not exist yet
    if (!GetSubsystem<FreeTypeLibrary>())
        context_->RegisterSubsystem(new FreeTypeLibrary(context_));
}

Font::~Font()
{
}

void Font::RegisterObject(Context* context)
{
    context->RegisterFactory<Font>();
}

bool Font::Load(Deserializer& source)
{
    PROFILE(LoadFont);

    faces_.Clear();

    fontDataSize_ = source.GetSize();
    if (fontDataSize_)
    {
        fontData_ = new unsigned char[fontDataSize_];
        if (source.Read(&fontData_[0], fontDataSize_) != fontDataSize_)
            return false;
    }
    else
    {
        fontData_.Reset();
        return false;
    }

    SetMemoryUse(fontDataSize_);
    return true;
}

const FontFace* Font::GetFace(int pointSize)
{
    Map<int, SharedPtr<FontFace> >::ConstIterator i = faces_.Find(pointSize);
    if (i != faces_.End())
        return i->second_;

    PROFILE(GetFontFace);

    FT_Face face;
    FT_Error error;
    FT_Library library = GetSubsystem<FreeTypeLibrary>()->getLibrary();

    if (pointSize <= 0)
    {
        LOGERROR("Zero or negative point size");
        return 0;
    }

    if (!fontDataSize_)
    {
        LOGERROR("Font not loaded");
        return 0;
    }

    error = FT_New_Memory_Face(library, &fontData_[0], fontDataSize_, 0, &face);
    if (error)
    {
        LOGERROR("Could not create font face");
        return 0;
    }
    error = FT_Set_Char_Size(face, 0, pointSize * 64, FONT_DPI, FONT_DPI);
    if (error)
    {
        FT_Done_Face(face);
        LOGERROR("Could not set font point size " + String(pointSize));
        return 0;
    }

    SharedPtr<FontFace> newFace(new FontFace());

    FT_GlyphSlot slot = face->glyph;
    unsigned numGlyphs = 0;

    // Build glyph mapping
    /// \todo Find out the Unicode range more intelligently, and support all characters
    for (unsigned i = 0; i < 65536; ++i)
    {
        unsigned index = FT_Get_Char_Index(face, i);
        numGlyphs = Max((int)index + 1, (int)numGlyphs);
        if (index)
            newFace->glyphMapping_[i] = index; // Glyph 0 is default, build a "sparse" map
    }

    // Load each of the glyphs to see the sizes & store other information
    int maxOffsetY = 0;
    int maxHeight = 0;

    for (unsigned i = 0; i < numGlyphs; ++i)
    {
        FontGlyph newGlyph;

        error = FT_Load_Glyph(face, i, FT_LOAD_DEFAULT);
        if (!error)
        {
            // Note: position within texture will be filled later
            newGlyph.width_ = (short)((slot->metrics.width) >> 6);
            newGlyph.height_ = (short)((slot->metrics.height) >> 6);
            newGlyph.offsetX_ = (short)((slot->metrics.horiBearingX) >> 6);
            newGlyph.offsetY_ = (short)((face->size->metrics.ascender - slot->metrics.horiBearingY) >> 6);
            newGlyph.advanceX_ = (short)((slot->metrics.horiAdvance) >> 6);

            maxOffsetY = Max(maxOffsetY, newGlyph.offsetY_);
            maxHeight = Max(maxHeight, newGlyph.height_);
        }
        else
        {
            newGlyph.width_ = 0;
            newGlyph.height_ = 0;
            newGlyph.offsetX_ = 0;
            newGlyph.offsetY_ = 0;
            newGlyph.advanceX_ = 0;
        }

        newFace->glyphs_.Push(newGlyph);
    }

    // Store kerning if face has kerning information
    if (FT_HAS_KERNING(face))
    {
        newFace->hasKerning_ = true;
        unsigned numGlyphs = newFace->glyphs_.Size();

        for (unsigned i = 0; i < numGlyphs; ++i)
        {
            for (unsigned j = 0; j < numGlyphs; ++j)
            {
                FT_Vector vector;
                FT_Get_Kerning(face, i, j, FT_KERNING_DEFAULT, &vector);
                newFace->glyphs_[i].kerning_[j] = (short)(vector.x >> 6);
            }
        }
    }

    // Store point size and the height of a row. Use the height of the tallest font if taller than the specified row height
    newFace->pointSize_ = pointSize;
    newFace->rowHeight_ = Max((face->size->metrics.height + 63) >> 6, maxHeight);

    // Now try to pack into the smallest possible texture
    int texWidth = FONT_TEXTURE_MIN_SIZE;
    int texHeight = FONT_TEXTURE_MIN_SIZE;
    bool doubleHorizontal = true;

    for (;;)
    {
        bool success = true;

        // Check first for theoretical possible fit. If it fails, there is no need to try to fit
        int totalArea = 0;
        for (unsigned i = 0; i < newFace->glyphs_.Size(); ++i)
            totalArea += (newFace->glyphs_[i].width_ + 1) * (newFace->glyphs_[i].height_ + 1);

        if (totalArea > texWidth * texHeight)
            success = false;
        else
        {
            AreaAllocator allocator(texWidth, texHeight);
            for (unsigned i = 0; i < newFace->glyphs_.Size(); ++i)
            {
                if (newFace->glyphs_[i].width_ && newFace->glyphs_[i].height_)
                {
                    int x, y;
                    // Reserve an empty border between glyphs for filtering
                    if (!allocator.Allocate(newFace->glyphs_[i].width_ + 1, newFace->glyphs_[i].height_ + 1, x, y))
                    {
                        success = false;
                        break;
                    }
                    else
                    {
                        newFace->glyphs_[i].x_ = x;
                        newFace->glyphs_[i].y_ = y;
                    }
                }
                else
                {
                    newFace->glyphs_[i].x_ = 0;
                    newFace->glyphs_[i].y_ = 0;
                }
            }
        }

        if (!success)
        {
            // Alternate between doubling the horizontal and the vertical dimension
            if (doubleHorizontal)
                texWidth <<= 1;
            else
                texHeight <<= 1;

            if (texWidth > FONT_TEXTURE_MAX_SIZE || texHeight > FONT_TEXTURE_MAX_SIZE)
            {
                FT_Done_Face(face);
                LOGERROR("Font face could not be fit into the largest possible texture");
                return 0;
            }
            doubleHorizontal = !doubleHorizontal;
        }
        else
            break;
    }

    // Create the image for rendering the fonts
    SharedPtr<Image> image(new Image(context_));
    image->SetSize(texWidth, texHeight, 1);

    // First clear the whole image
    unsigned char* imageData = image->GetData();
    for (int y = 0; y < texHeight; ++y)
    {
        unsigned char* dest = imageData + texWidth * y;
        memset(dest, 0, texWidth);
    }

    // Render glyphs into texture, and find out a scaling value in case font uses less than full opacity (thin outlines)
    unsigned char avgMaxOpacity = 255;
    unsigned sumMaxOpacity = 0;
    unsigned samples = 0;
    for (unsigned i = 0; i < newFace->glyphs_.Size(); ++i)
    {
        if (!newFace->glyphs_[i].width_ || !newFace->glyphs_[i].height_)
            continue;

        FT_Load_Glyph(face, i, FT_LOAD_DEFAULT);
        FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);

        unsigned char glyphOpacity = 0;
        for (int y = 0; y < newFace->glyphs_[i].height_; ++y)
        {
            unsigned char* src = slot->bitmap.buffer + slot->bitmap.pitch * y;
            unsigned char* dest = imageData + texWidth * (y + newFace->glyphs_[i].y_) + newFace->glyphs_[i].x_;

            for (int x = 0; x < newFace->glyphs_[i].width_; ++x)
            {
                dest[x] = src[x];
                glyphOpacity = Max(glyphOpacity, src[x]);
            }
        }
        if (glyphOpacity)
        {
            sumMaxOpacity += glyphOpacity;
            ++samples;
        }
    }

    // Clamp the minimum possible value to avoid overbrightening
    if (samples)
        avgMaxOpacity = Max(sumMaxOpacity / samples, 128);

    if (avgMaxOpacity < 255)
    {
        // Apply the scaling value if necessary
        float scale = 255.0f / avgMaxOpacity;
        for (unsigned i = 0; i < newFace->glyphs_.Size(); ++i)
        {
            for (int y = 0; y < newFace->glyphs_[i].height_; ++y)
            {
                unsigned char* dest = imageData + texWidth * (y + newFace->glyphs_[i].y_) + newFace->glyphs_[i].x_;
                for (int x = 0; x < newFace->glyphs_[i].width_; ++x)
                {
                    int pixel = dest[x];
                    dest[x] = Min((int)(pixel * scale), 255);
                }
            }
        }
    }

    FT_Done_Face(face);

    // Create the texture and load the image into it
    SharedPtr<Texture2D> texture(new Texture2D(context_));
    texture->SetNumLevels(1); // No mipmaps
    texture->SetAddressMode(COORD_U, ADDRESS_BORDER);
    texture->SetAddressMode(COORD_V, ADDRESS_BORDER),
    texture->SetBorderColor(Color(0.0f, 0.0f, 0.0f, 0.0f));
    if (!texture->SetSize(texWidth, texHeight, Graphics::GetAlphaFormat()) || !texture->Load(image, true))
        return 0;

    SetMemoryUse(GetMemoryUse() + texWidth * texHeight);
    newFace->texture_ = StaticCast<Texture>(texture);
    faces_[pointSize] = newFace;
    return newFace;
}
<commit_msg>Go through available glyphs more intelligently.<commit_after>//
// Urho3D Engine
// Copyright (c) 2008-2012 Lasse rni
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "Precompiled.h"
#include "AreaAllocator.h"
#include "Context.h"
#include "Deserializer.h"
#include "Font.h"
#include "Graphics.h"
#include "Log.h"
#include "Profiler.h"
#include "Texture2D.h"

#include "ft2build.h"
#include FT_FREETYPE_H

#include "DebugNew.h"

/// FreeType library subsystem.
class FreeTypeLibrary : public Object
{
    OBJECT(FreeTypeLibrary);

public:
    /// Construct.
    FreeTypeLibrary(Context* context) :
        Object(context)
    {
        FT_Error error = FT_Init_FreeType(&mLibrary);
        if (error)
            LOGERROR("Could not initialize FreeType library");
    }

    /// Destruct.
    virtual ~FreeTypeLibrary()
    {
        FT_Done_FreeType(mLibrary);
    }

    FT_Library getLibrary() const { return mLibrary; }

private:
    /// FreeType library.
    FT_Library mLibrary;
};

FontFace::FontFace() :
    hasKerning_(false)
{
}

FontFace::~FontFace()
{
}

const FontGlyph& FontFace::GetGlyph(unsigned c) const
{
    Map<unsigned, unsigned>::ConstIterator i = glyphMapping_.Find(c);
    if (i != glyphMapping_.End())
        return glyphs_[i->second_];
    else
        return glyphs_[0];
}

short FontFace::GetKerning(unsigned c, unsigned d) const
{
    if (!hasKerning_)
        return 0;

    if (c == '\n' || d == '\n')
        return 0;

    unsigned leftIndex = 0;
    unsigned rightIndex = 0;
    Map<unsigned, unsigned>::ConstIterator leftIt = glyphMapping_.Find(c);
    Map<unsigned, unsigned>::ConstIterator rightIt = glyphMapping_.Find(c);
    if (leftIt != glyphMapping_.End())
        leftIndex = leftIt->second_;
    if (rightIt != glyphMapping_.End())
        rightIndex = rightIt->second_;

    Map<unsigned, unsigned>::ConstIterator kerningIt = glyphs_[leftIndex].kerning_.Find(rightIndex);
    if (kerningIt != glyphs_[leftIndex].kerning_.End())
        return kerningIt->second_;
    else
        return 0;
}

OBJECTTYPESTATIC(FreeTypeLibrary);
OBJECTTYPESTATIC(Font);

Font::Font(Context* context) :
    Resource(context),
    fontDataSize_(0)
{
    // Create & initialize FreeType library if it does not exist yet
    if (!GetSubsystem<FreeTypeLibrary>())
        context_->RegisterSubsystem(new FreeTypeLibrary(context_));
}

Font::~Font()
{
}

void Font::RegisterObject(Context* context)
{
    context->RegisterFactory<Font>();
}

bool Font::Load(Deserializer& source)
{
    PROFILE(LoadFont);

    faces_.Clear();

    fontDataSize_ = source.GetSize();
    if (fontDataSize_)
    {
        fontData_ = new unsigned char[fontDataSize_];
        if (source.Read(&fontData_[0], fontDataSize_) != fontDataSize_)
            return false;
    }
    else
    {
        fontData_.Reset();
        return false;
    }

    SetMemoryUse(fontDataSize_);
    return true;
}

const FontFace* Font::GetFace(int pointSize)
{
    Map<int, SharedPtr<FontFace> >::ConstIterator i = faces_.Find(pointSize);
    if (i != faces_.End())
        return i->second_;

    PROFILE(GetFontFace);

    FT_Face face;
    FT_Error error;
    FT_Library library = GetSubsystem<FreeTypeLibrary>()->getLibrary();

    if (pointSize <= 0)
    {
        LOGERROR("Zero or negative point size");
        return 0;
    }

    if (!fontDataSize_)
    {
        LOGERROR("Font not loaded");
        return 0;
    }

    error = FT_New_Memory_Face(library, &fontData_[0], fontDataSize_, 0, &face);
    if (error)
    {
        LOGERROR("Could not create font face");
        return 0;
    }
    error = FT_Set_Char_Size(face, 0, pointSize * 64, FONT_DPI, FONT_DPI);
    if (error)
    {
        FT_Done_Face(face);
        LOGERROR("Could not set font point size " + String(pointSize));
        return 0;
    }

    SharedPtr<FontFace> newFace(new FontFace());

    FT_GlyphSlot slot = face->glyph;
    unsigned numGlyphs = 0;

    // Build glyph mapping
    FT_UInt glyphIndex;
    FT_ULong charCode = FT_Get_First_Char(face, &glyphIndex);
    while (glyphIndex != 0)
    {
        numGlyphs = Max((int)glyphIndex + 1, (int)numGlyphs);
        newFace->glyphMapping_[charCode] = glyphIndex;
        charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
    }

    LOGDEBUG("Font face has " + String(numGlyphs) + " glyphs");

    // Load each of the glyphs to see the sizes & store other information
    int maxOffsetY = 0;
    int maxHeight = 0;

    for (unsigned i = 0; i < numGlyphs; ++i)
    {
        FontGlyph newGlyph;

        error = FT_Load_Glyph(face, i, FT_LOAD_DEFAULT);
        if (!error)
        {
            // Note: position within texture will be filled later
            newGlyph.width_ = (short)((slot->metrics.width) >> 6);
            newGlyph.height_ = (short)((slot->metrics.height) >> 6);
            newGlyph.offsetX_ = (short)((slot->metrics.horiBearingX) >> 6);
            newGlyph.offsetY_ = (short)((face->size->metrics.ascender - slot->metrics.horiBearingY) >> 6);
            newGlyph.advanceX_ = (short)((slot->metrics.horiAdvance) >> 6);

            maxOffsetY = Max(maxOffsetY, newGlyph.offsetY_);
            maxHeight = Max(maxHeight, newGlyph.height_);
        }
        else
        {
            newGlyph.width_ = 0;
            newGlyph.height_ = 0;
            newGlyph.offsetX_ = 0;
            newGlyph.offsetY_ = 0;
            newGlyph.advanceX_ = 0;
        }

        newFace->glyphs_.Push(newGlyph);
    }

    // Store kerning if face has kerning information
    if (FT_HAS_KERNING(face))
    {
        newFace->hasKerning_ = true;
        unsigned numGlyphs = newFace->glyphs_.Size();

        for (unsigned i = 0; i < numGlyphs; ++i)
        {
            for (unsigned j = 0; j < numGlyphs; ++j)
            {
                FT_Vector vector;
                FT_Get_Kerning(face, i, j, FT_KERNING_DEFAULT, &vector);
                newFace->glyphs_[i].kerning_[j] = (short)(vector.x >> 6);
            }
        }
    }

    // Store point size and the height of a row. Use the height of the tallest font if taller than the specified row height
    newFace->pointSize_ = pointSize;
    newFace->rowHeight_ = Max((face->size->metrics.height + 63) >> 6, maxHeight);

    // Now try to pack into the smallest possible texture
    int texWidth = FONT_TEXTURE_MIN_SIZE;
    int texHeight = FONT_TEXTURE_MIN_SIZE;
    bool doubleHorizontal = true;

    for (;;)
    {
        bool success = true;

        // Check first for theoretical possible fit. If it fails, there is no need to try to fit
        int totalArea = 0;
        for (unsigned i = 0; i < newFace->glyphs_.Size(); ++i)
            totalArea += (newFace->glyphs_[i].width_ + 1) * (newFace->glyphs_[i].height_ + 1);

        if (totalArea > texWidth * texHeight)
            success = false;
        else
        {
            AreaAllocator allocator(texWidth, texHeight);
            for (unsigned i = 0; i < newFace->glyphs_.Size(); ++i)
            {
                if (newFace->glyphs_[i].width_ && newFace->glyphs_[i].height_)
                {
                    int x, y;
                    // Reserve an empty border between glyphs for filtering
                    if (!allocator.Allocate(newFace->glyphs_[i].width_ + 1, newFace->glyphs_[i].height_ + 1, x, y))
                    {
                        success = false;
                        break;
                    }
                    else
                    {
                        newFace->glyphs_[i].x_ = x;
                        newFace->glyphs_[i].y_ = y;
                    }
                }
                else
                {
                    newFace->glyphs_[i].x_ = 0;
                    newFace->glyphs_[i].y_ = 0;
                }
            }
        }

        if (!success)
        {
            // Alternate between doubling the horizontal and the vertical dimension
            if (doubleHorizontal)
                texWidth <<= 1;
            else
                texHeight <<= 1;

            if (texWidth > FONT_TEXTURE_MAX_SIZE || texHeight > FONT_TEXTURE_MAX_SIZE)
            {
                FT_Done_Face(face);
                LOGERROR("Font face could not be fit into the largest possible texture");
                return 0;
            }
            doubleHorizontal = !doubleHorizontal;
        }
        else
            break;
    }

    // Create the image for rendering the fonts
    SharedPtr<Image> image(new Image(context_));
    image->SetSize(texWidth, texHeight, 1);

    // First clear the whole image
    unsigned char* imageData = image->GetData();
    for (int y = 0; y < texHeight; ++y)
    {
        unsigned char* dest = imageData + texWidth * y;
        memset(dest, 0, texWidth);
    }

    // Render glyphs into texture, and find out a scaling value in case font uses less than full opacity (thin outlines)
    unsigned char avgMaxOpacity = 255;
    unsigned sumMaxOpacity = 0;
    unsigned samples = 0;
    for (unsigned i = 0; i < newFace->glyphs_.Size(); ++i)
    {
        if (!newFace->glyphs_[i].width_ || !newFace->glyphs_[i].height_)
            continue;

        FT_Load_Glyph(face, i, FT_LOAD_DEFAULT);
        FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);

        unsigned char glyphOpacity = 0;
        for (int y = 0; y < newFace->glyphs_[i].height_; ++y)
        {
            unsigned char* src = slot->bitmap.buffer + slot->bitmap.pitch * y;
            unsigned char* dest = imageData + texWidth * (y + newFace->glyphs_[i].y_) + newFace->glyphs_[i].x_;

            for (int x = 0; x < newFace->glyphs_[i].width_; ++x)
            {
                dest[x] = src[x];
                glyphOpacity = Max(glyphOpacity, src[x]);
            }
        }
        if (glyphOpacity)
        {
            sumMaxOpacity += glyphOpacity;
            ++samples;
        }
    }

    // Clamp the minimum possible value to avoid overbrightening
    if (samples)
        avgMaxOpacity = Max(sumMaxOpacity / samples, 128);

    if (avgMaxOpacity < 255)
    {
        // Apply the scaling value if necessary
        float scale = 255.0f / avgMaxOpacity;
        for (unsigned i = 0; i < newFace->glyphs_.Size(); ++i)
        {
            for (int y = 0; y < newFace->glyphs_[i].height_; ++y)
            {
                unsigned char* dest = imageData + texWidth * (y + newFace->glyphs_[i].y_) + newFace->glyphs_[i].x_;
                for (int x = 0; x < newFace->glyphs_[i].width_; ++x)
                {
                    int pixel = dest[x];
                    dest[x] = Min((int)(pixel * scale), 255);
                }
            }
        }
    }

    FT_Done_Face(face);

    // Create the texture and load the image into it
    SharedPtr<Texture2D> texture(new Texture2D(context_));
    texture->SetNumLevels(1); // No mipmaps
    texture->SetAddressMode(COORD_U, ADDRESS_BORDER);
    texture->SetAddressMode(COORD_V, ADDRESS_BORDER),
    texture->SetBorderColor(Color(0.0f, 0.0f, 0.0f, 0.0f));
    if (!texture->SetSize(texWidth, texHeight, Graphics::GetAlphaFormat()) || !texture->Load(image, true))
        return 0;

    SetMemoryUse(GetMemoryUse() + texWidth * texHeight);
    newFace->texture_ = StaticCast<Texture>(texture);
    faces_[pointSize] = newFace;
    return newFace;
}
<|endoftext|>


<commit_before>#include "alarm_mgr.h"
#include <iostream>
#include <sqlite/execute.hpp>
#include <sqlite/query.hpp>

AlarmMgr::AlarmMgr() : AlarmMgr::AlarmMgr("alarm.db") {}
AlarmMgr::AlarmMgr(std::string alarmdb_name) : alarmdb(alarmdb_name)
{
    try
    {
        sqlite::execute(alarmdb, "CREATE TABLE alarms"
                "("
                " id INTEGER PRIMARY KEY,"
                " series_name TEXT,"
                " dow INT,"
                " hr INT,"
                " min INT,"
                " start_date DATE,"
                " stop_date DATE,"
                " last_run DATETIME"
                ");", true);
    }
    catch(std::exception const & e)
    {
        std::cerr << e.what() << std::endl;
    }
}
AlarmMgr::~AlarmMgr() {}

void AlarmMgr::check_alarms()
{
    // Get the time.
    time_t rawtime;
    time(&rawtime);
    struct tm* now = localtime (&rawtime);

    sqlite::query q(alarmdb, "SELECT * FROM alarms" // Find an alarm that
            " WHERE start_date<=strftime('%s', 'now')" // Has started
            " AND stop_date>=strftime('%s', 'now', 'start of day', '+1 day')" // Has not expired
            " AND last_run<=strftime('%s','now', '-1 minute');"); // and has not been run.
    boost::shared_ptr<sqlite::result> result = q.get_result();
    while(result->next_row())
    {
        if( (result->get_int((int)col_names::dow) == now->tm_wday || // If the alarm is for this day
             result->get_int((int)col_names::dow) == -1) && // Or every day
             result->get_int((int)col_names::hr)  == now->tm_hour  && // and for this hour
             result->get_int((int)col_names::min) == now->tm_min) // and for this minute
        {
            // Activate alarm.
            m_signal_alarm_activated.emit(result->get_string((int)col_names::series_name));

            // Update alarm last run time.
            sqlite::execute upd(alarmdb, "UPDATE alarms SET"
                    " 'last_run'=strftime('%s','now') WHERE id == ?;");
            upd.bind(1, result->get_int((int)col_names::id));
            upd();
        }
    }
}

void AlarmMgr::set_alarm(std::string alarmid, tm* alarm_time, tm* start_date, tm* stop_date) {
    // Convert start and stop times to unix timestamps.
    time_t start_time = mktime(start_date);
    time_t stop_time = mktime(stop_date);

    sqlite::execute ins(alarmdb, "INSERT INTO alarms VALUES(?, ?, ?, ?, ?, ?, ?, ?);");
    // Insert columns are 1-indexed. Querys are 0-indexed.
    ins.bind(1+(int)col_names::id); // Binds null to id. Autogenerated.
    ins.bind(1+(int)col_names::series_name, alarmid);
    ins.bind(1+(int)col_names::dow,         alarm_time->tm_wday);
    ins.bind(1+(int)col_names::hr,          alarm_time->tm_hour);
    ins.bind(1+(int)col_names::min,         alarm_time->tm_min);
    ins.bind(1+(int)col_names::start_date,  start_time);
    ins.bind(1+(int)col_names::stop_date,   stop_time);
    ins.bind(1+(int)col_names::last_run,    0);
    ins();
}

void AlarmMgr::deactivate_alarm(std::string alarmid, bool snooze)
{
    m_signal_alarm_deactivated.emit(alarmid);
    if(snooze)
    {
        time_t rawtime;
        time(&rawtime);

        struct tm start_date = *localtime(&rawtime);

        struct tm alarm_time = *localtime(&rawtime);
        alarm_time.tm_min = alarm_time.tm_min + 5;

        struct tm end_date = *localtime(&rawtime);
        end_date.tm_mday = end_date.tm_mday + 1;

        set_alarm(alarmid+"-snoozed", &alarm_time, &start_date, &end_date);
    }
}

void AlarmMgr::deactivate_alarm()
{
    m_signal_alarm_deactivated.emit("*");
}

AlarmMgr::type_signal_alarm AlarmMgr::signal_alarm_activated()
{
    return m_signal_alarm_activated;
}

AlarmMgr::type_signal_alarm AlarmMgr::signal_alarm_deactivated()
{
    return m_signal_alarm_deactivated;
}
<commit_msg>Fixed issue discovered when building on Pi.<commit_after>#include "alarm_mgr.h"
#include <iostream>
#include <sqlite/execute.hpp>
#include <sqlite/query.hpp>

AlarmMgr::AlarmMgr() : AlarmMgr::AlarmMgr("alarm.db") {}
AlarmMgr::AlarmMgr(std::string alarmdb_name) : alarmdb(alarmdb_name)
{
    try
    {
        sqlite::execute(alarmdb, "CREATE TABLE alarms"
                "("
                " id INTEGER PRIMARY KEY,"
                " series_name TEXT,"
                " dow INT,"
                " hr INT,"
                " min INT,"
                " start_date DATE,"
                " stop_date DATE,"
                " last_run DATETIME"
                ");", true);
    }
    catch(std::exception const & e)
    {
        std::cerr << e.what() << std::endl;
    }
}
AlarmMgr::~AlarmMgr() {}

void AlarmMgr::check_alarms()
{
    // Get the time.
    time_t rawtime;
    time(&rawtime);
    struct tm* now = localtime (&rawtime);

    sqlite::query q(alarmdb, "SELECT * FROM alarms" // Find an alarm that
            " WHERE start_date<=strftime('%s', 'now')" // Has started
            " AND stop_date>=strftime('%s', 'now', 'start of day', '+1 day')" // Has not expired
            " AND last_run<=strftime('%s','now', '-1 minute');"); // and has not been run.
    boost::shared_ptr<sqlite::result> result = q.get_result();
    while(result->next_row())
    {
        if( (result->get_int((int)col_names::dow) == now->tm_wday || // If the alarm is for this day
             result->get_int((int)col_names::dow) == -1) && // Or every day
             result->get_int((int)col_names::hr)  == now->tm_hour  && // and for this hour
             result->get_int((int)col_names::min) == now->tm_min) // and for this minute
        {
            // Activate alarm.
            m_signal_alarm_activated.emit(result->get_string((int)col_names::series_name));

            // Update alarm last run time.
            sqlite::execute upd(alarmdb, "UPDATE alarms SET"
                    " 'last_run'=strftime('%s','now') WHERE id == ?;");
            upd.bind(1, result->get_int((int)col_names::id));
            upd();
        }
    }
}

void AlarmMgr::set_alarm(std::string alarmid, tm* alarm_time, tm* start_date, tm* stop_date) {
    // Convert start and stop times to unix timestamps.
    int32_t start_time = mktime(start_date);
    int32_t stop_time = mktime(stop_date);

    sqlite::execute ins(alarmdb, "INSERT INTO alarms VALUES(?, ?, ?, ?, ?, ?, ?, ?);");
    // Insert columns are 1-indexed. Querys are 0-indexed.
    ins.bind(1+(int)col_names::id); // Binds null to id. Autogenerated.
    ins.bind(1+(int)col_names::series_name, alarmid);
    ins.bind(1+(int)col_names::dow,         alarm_time->tm_wday);
    ins.bind(1+(int)col_names::hr,          alarm_time->tm_hour);
    ins.bind(1+(int)col_names::min,         alarm_time->tm_min);
    ins.bind(1+(int)col_names::start_date,  start_time);
    ins.bind(1+(int)col_names::stop_date,   stop_time);
    ins.bind(1+(int)col_names::last_run,    0);
    ins();
}

void AlarmMgr::deactivate_alarm(std::string alarmid, bool snooze)
{
    m_signal_alarm_deactivated.emit(alarmid);
    if(snooze)
    {
        time_t rawtime;
        time(&rawtime);

        struct tm start_date = *localtime(&rawtime);

        struct tm alarm_time = *localtime(&rawtime);
        alarm_time.tm_min = alarm_time.tm_min + 5;

        struct tm end_date = *localtime(&rawtime);
        end_date.tm_mday = end_date.tm_mday + 1;

        set_alarm(alarmid+"-snoozed", &alarm_time, &start_date, &end_date);
    }
}

void AlarmMgr::deactivate_alarm()
{
    m_signal_alarm_deactivated.emit("*");
}

AlarmMgr::type_signal_alarm AlarmMgr::signal_alarm_activated()
{
    return m_signal_alarm_activated;
}

AlarmMgr::type_signal_alarm AlarmMgr::signal_alarm_deactivated()
{
    return m_signal_alarm_deactivated;
}
<|endoftext|>


<commit_before>#ifndef SIGNAL_DEFINITIONS_HPP
#define SIGNAL_DEFINITIONS_HPP

#include "wayfire/view.hpp"
#include "wayfire/output.hpp"

/* signal definitions */
/* convenience functions are provided to get some basic info from the signal */
struct _view_signal : public wf::signal_data_t
{
    wayfire_view view;
};
wayfire_view get_signaled_view(wf::signal_data_t *data);

/**
 * attach-view is a signal emitted by an output. It is emitted whenever a view's
 * output is set to the given output.
 *
 * layer-attach-view is a signal emitted by an output. It is emitted whenever a
 * view is added to a layer on the output, where it was not in any layer on the
 * output previously.
 */
using attach_view_signal     = _view_signal;

/**
 * detach-view is a signal emitted by an output. It is emitted whenever a view's
 * output is no longer the given output, or the view is about to be destroyed.
 *
 * layer-detach-view is a signal emitted by an output. It is emitted whenever a
 * view is no longer in a layer of the given output.
 */
using detach_view_signal    = _view_signal;
using unmap_view_signal      = _view_signal;
using pre_unmap_view_signal  = _view_signal;

struct map_view_signal : public _view_signal
{
    /* Indicates whether the position already has its initial posittion */
    bool is_positioned = false;
};

/* Indicates the view is no longer available, for ex. it has been minimized
 * or unmapped */
using view_disappeared_signal = _view_signal;

using focus_view_signal      = _view_signal;
using view_set_parent_signal = _view_signal;
using move_request_signal    = _view_signal;
using title_changed_signal   = _view_signal;
using app_id_changed_signal  = _view_signal;

struct resize_request_signal : public _view_signal
{
    uint32_t edges;
};

/* sent when the view geometry changes */
struct view_geometry_changed_signal : public _view_signal
{
    wf::geometry_t old_geometry;
};

struct view_tiled_signal : public _view_signal
{
    uint32_t edges;
    bool carried_out = false;
    wf::geometry_t desired_size;
};

/**
 * The view-fullscreen-request and view-fullscreen signals are emitted on the view's output when the view's fullscreen state changes.
 * view-fullscreen-request is emitted when the view needs to be fullscreened, but has not been fullscreened yet.
 * view-fullscreen is emitted whenever the view's fullscreen state actually changes.
 * state is true if the view is fullscreen and false otherwise.
 * carried_out should be set by the listener if it handles the signal,
 * by setting the view fullscreen.
 * desired_size is the intended size for the fullscreen view
 * but may be undefined (0,0 0x0).
 */
struct view_fullscreen_signal : public _view_signal
{
    bool state;
    bool carried_out = false;
    wf::geometry_t desired_size;
};

struct view_minimize_request_signal : public _view_signal
{
    bool state;
    /* If some plugin wants to delay the (un)minimize of the view, it needs to
     * listen for the view-minimize-request and set carried_out to true.
     * It is a hint to core that the action will be (or already was) performed
     * by a plugin, and minimized state shouldn't be further changed by core */
    bool carried_out = false;
};

/* same as both change_viewport_request and change_viewport_notify */
struct change_viewport_signal : public wf::signal_data_t
{
    bool carried_out;
    wf::point_t old_viewport, new_viewport;
};
using change_viewport_notify = change_viewport_signal;

/* sent when the workspace implementation actually reserves the workarea */
struct reserved_workarea_signal : public wf::signal_data_t
{
    wf::geometry_t old_workarea;
    wf::geometry_t new_workarea;
};

// TODO: this is a private signal, maybe we should hide it? */
struct _surface_map_state_changed_signal : public wf::signal_data_t
{
    wf::surface_interface_t *surface;
};

/* Part 2: Signals from wf::output_layout_t */
struct _output_signal : public wf::signal_data_t
{
    wf::output_t *output;
};

wf::output_t *get_signaled_output(wf::signal_data_t *data);

using output_added_signal = _output_signal;
using output_removed_signal = _output_signal;

namespace wf
{
    class input_device_t;
    /* Used in the tablet-mode and lid-state signals from core */
    struct switch_signal : public wf::signal_data_t
    {
        nonstd::observer_ptr<input_device_t> device;
        bool state;
    };

    /* in input-device-added and input-device-removed signals from core */
    struct input_device_signal : public signal_data_t
    {
        nonstd::observer_ptr<input_device_t> device;
    };

    /**
     * Used for the following events:
     *
     * pointer_motion, pointer_motion_abs, pointer_button, pointer_axis,
     * pointer_swipe_begin, pointer_swipe_update, pointer_swipe_end,
     * pointer_pinch_begin, pointer_pinch_update, pointer_pinch_end,
     *
     * keyboard_key,
     *
     * touch_down, touch_up, touch_motion,
     *
     * tablet_proximity, tablet_axis, tablet_button, tablet_tip
     *
     * The template parameter is the corresponding type of wlr events.
     *
     * The input event signals are sent from core whenever a new input from an
     * input device arrives. The events are sent before any processing is done,
     * and they are independent of plugin input grabs and other wayfire input
     * mechanisms.
     *
     * The event data can be modified by plugins, and then the modified event
     * will be used instead. However plugins which modify the event must ensure
     * that subsequent events are adjusted accordingly as well.
     */
    template<class wlr_event_t>
    struct input_event_signal : public wf::signal_data_t
    {
        /* The event as it has arrived from wlroots */
        wlr_event_t *event;
    };

    /**
     * decoration-state-updated signal is emitted when the value of
     * view::should_be_decorated() changes.
     *
     * decoration-state-updated-view is emitted on the output of the view.
     */
    using decoration_state_updated_signal = _view_signal;

    /**
     * view-move-to-output signal is emitted by core just before a view is moved
     * from one output to another.
     */
    struct view_move_to_output_signal : public signal_data_t
    {
        /* The view being moved */
        wayfire_view view;
        /* The output the view was on */
        wf::output_t *old_output;
        /* The output the view is being moved to. */
        wf::output_t *new_output;
    };
}

#endif
<commit_msg>signal-definitions: reindent namespaced signals<commit_after>#ifndef SIGNAL_DEFINITIONS_HPP
#define SIGNAL_DEFINITIONS_HPP

#include "wayfire/view.hpp"
#include "wayfire/output.hpp"

/* signal definitions */
/* convenience functions are provided to get some basic info from the signal */
struct _view_signal : public wf::signal_data_t
{
    wayfire_view view;
};
wayfire_view get_signaled_view(wf::signal_data_t *data);

/**
 * attach-view is a signal emitted by an output. It is emitted whenever a view's
 * output is set to the given output.
 *
 * layer-attach-view is a signal emitted by an output. It is emitted whenever a
 * view is added to a layer on the output, where it was not in any layer on the
 * output previously.
 */
using attach_view_signal     = _view_signal;

/**
 * detach-view is a signal emitted by an output. It is emitted whenever a view's
 * output is no longer the given output, or the view is about to be destroyed.
 *
 * layer-detach-view is a signal emitted by an output. It is emitted whenever a
 * view is no longer in a layer of the given output.
 */
using detach_view_signal    = _view_signal;
using unmap_view_signal      = _view_signal;
using pre_unmap_view_signal  = _view_signal;

struct map_view_signal : public _view_signal
{
    /* Indicates whether the position already has its initial posittion */
    bool is_positioned = false;
};

/* Indicates the view is no longer available, for ex. it has been minimized
 * or unmapped */
using view_disappeared_signal = _view_signal;

using focus_view_signal      = _view_signal;
using view_set_parent_signal = _view_signal;
using move_request_signal    = _view_signal;
using title_changed_signal   = _view_signal;
using app_id_changed_signal  = _view_signal;

struct resize_request_signal : public _view_signal
{
    uint32_t edges;
};

/* sent when the view geometry changes */
struct view_geometry_changed_signal : public _view_signal
{
    wf::geometry_t old_geometry;
};

struct view_tiled_signal : public _view_signal
{
    uint32_t edges;
    bool carried_out = false;
    wf::geometry_t desired_size;
};

/**
 * The view-fullscreen-request and view-fullscreen signals are emitted on the view's output when the view's fullscreen state changes.
 * view-fullscreen-request is emitted when the view needs to be fullscreened, but has not been fullscreened yet.
 * view-fullscreen is emitted whenever the view's fullscreen state actually changes.
 * state is true if the view is fullscreen and false otherwise.
 * carried_out should be set by the listener if it handles the signal,
 * by setting the view fullscreen.
 * desired_size is the intended size for the fullscreen view
 * but may be undefined (0,0 0x0).
 */
struct view_fullscreen_signal : public _view_signal
{
    bool state;
    bool carried_out = false;
    wf::geometry_t desired_size;
};

struct view_minimize_request_signal : public _view_signal
{
    bool state;
    /* If some plugin wants to delay the (un)minimize of the view, it needs to
     * listen for the view-minimize-request and set carried_out to true.
     * It is a hint to core that the action will be (or already was) performed
     * by a plugin, and minimized state shouldn't be further changed by core */
    bool carried_out = false;
};

/* same as both change_viewport_request and change_viewport_notify */
struct change_viewport_signal : public wf::signal_data_t
{
    bool carried_out;
    wf::point_t old_viewport, new_viewport;
};
using change_viewport_notify = change_viewport_signal;

/* sent when the workspace implementation actually reserves the workarea */
struct reserved_workarea_signal : public wf::signal_data_t
{
    wf::geometry_t old_workarea;
    wf::geometry_t new_workarea;
};

// TODO: this is a private signal, maybe we should hide it? */
struct _surface_map_state_changed_signal : public wf::signal_data_t
{
    wf::surface_interface_t *surface;
};

/* Part 2: Signals from wf::output_layout_t */
struct _output_signal : public wf::signal_data_t
{
    wf::output_t *output;
};

wf::output_t *get_signaled_output(wf::signal_data_t *data);

using output_added_signal = _output_signal;
using output_removed_signal = _output_signal;

namespace wf
{
class input_device_t;
/* Used in the tablet-mode and lid-state signals from core */
struct switch_signal : public wf::signal_data_t
    {
        nonstd::observer_ptr<input_device_t> device;
        bool state;
    };

/* in input-device-added and input-device-removed signals from core */
struct input_device_signal : public signal_data_t
    {
        nonstd::observer_ptr<input_device_t> device;
    };

/**
 * Used for the following events:
 *
 * pointer_motion, pointer_motion_abs, pointer_button, pointer_axis,
 * pointer_swipe_begin, pointer_swipe_update, pointer_swipe_end,
 * pointer_pinch_begin, pointer_pinch_update, pointer_pinch_end,
 *
 * keyboard_key,
 *
 * touch_down, touch_up, touch_motion,
 *
 * tablet_proximity, tablet_axis, tablet_button, tablet_tip
 *
 * The template parameter is the corresponding type of wlr events.
 *
 * The input event signals are sent from core whenever a new input from an
 * input device arrives. The events are sent before any processing is done,
 * and they are independent of plugin input grabs and other wayfire input
 * mechanisms.
 *
 * The event data can be modified by plugins, and then the modified event
 * will be used instead. However plugins which modify the event must ensure
 * that subsequent events are adjusted accordingly as well.
 */
template<class wlr_event_t>
    struct input_event_signal : public wf::signal_data_t
{
    /* The event as it has arrived from wlroots */
    wlr_event_t *event;
};

/**
 * decoration-state-updated signal is emitted when the value of
 * view::should_be_decorated() changes.
 *
 * decoration-state-updated-view is emitted on the output of the view.
 */
using decoration_state_updated_signal = _view_signal;

/**
 * view-move-to-output signal is emitted by core just before a view is moved
 * from one output to another.
 */
struct view_move_to_output_signal : public signal_data_t
{
    /* The view being moved */
    wayfire_view view;
    /* The output the view was on */
    wf::output_t *old_output;
    /* The output the view is being moved to. */
    wf::output_t *new_output;
};
}

#endif
<|endoftext|>


<commit_before>#ifndef GCONFLAYER_HXX_
#include "gconflayer.hxx"
#endif

#ifndef _COM_SUN_STAR_CONFIGURATION_BACKEND_PROPERTYINFO_HPP_
#include <com/sun/star/configuration/backend/PropertyInfo.hpp>
#endif

#ifndef _COM_SUN_STAR_CONFIGURATION_BACKEND_XLAYERCONTENTDESCIBER_HPP_
#include <com/sun/star/configuration/backend/XLayerContentDescriber.hpp>
#endif

#ifndef _RTL_STRBUF_HXX_
#include <rtl/strbuf.hxx>
#endif

#ifndef _OSL_SECURITY_HXX_
#include <osl/security.hxx>
#endif

#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif

#ifndef _OSL_THREAD_H_
#include <osl/thread.h>
#endif

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif

//==============================================================================

GconfLayer::GconfLayer( const uno::Reference<uno::XComponentContext>& xContext,
    const ConfigurationValue pConfigurationValuesList[],
    const sal_Int32 nConfigurationValues,
    const char * pPreloadValuesList[] )
    :m_pConfigurationValuesList( pConfigurationValuesList )
    ,m_nConfigurationValues( nConfigurationValues )
    ,m_pPreloadValuesList( pPreloadValuesList )
{
    //Create instance of LayerContentDescriber Service
    rtl::OUString const k_sLayerDescriberService( RTL_CONSTASCII_USTRINGPARAM(
        "com.sun.star.comp.configuration.backend.LayerDescriber" ) );

    typedef uno::Reference<backend::XLayerContentDescriber> LayerDescriber;
    uno::Reference< lang::XMultiComponentFactory > xServiceManager = xContext->getServiceManager();
    if( xServiceManager.is() )
    {
        m_xLayerContentDescriber = LayerDescriber::query(
            xServiceManager->createInstanceWithContext( k_sLayerDescriberService, xContext ) );
    }
    else
    {
        OSL_TRACE( "Could not retrieve ServiceManager" );
    }
}

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

uno::Any makeAnyOfGconfValue( GConfValue *aGconfValue )
{
    switch( aGconfValue->type )
    {
        case GCONF_VALUE_BOOL:
            return uno::makeAny( (sal_Bool) gconf_value_get_bool( aGconfValue ) );

        case GCONF_VALUE_INT:
            return uno::makeAny( (sal_Int32) gconf_value_get_int( aGconfValue ) );

        case GCONF_VALUE_STRING:
            return uno::makeAny( OStringToOUString( rtl::OString(
                gconf_value_get_string(aGconfValue) ), RTL_TEXTENCODING_UTF8 ) );

        default:
            fprintf( stderr, "makeAnyOfGconfValue: Type not handled.\n" );
            break;
    }

    return uno::Any();
}

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

uno::Any translateToOOo( const ConfigurationValue aValue, GConfValue *aGconfValue )
{
    switch( aValue.nSettingId )
    {
        case SETTING_PROXY_MODE:
        {
            rtl::OUString aProxyMode;
            uno::Any aOriginalValue = makeAnyOfGconfValue( aGconfValue );
            aOriginalValue >>= aProxyMode;

            if( aProxyMode.equals( rtl::OUString::createFromAscii( "manual" ) ) )
                return uno::makeAny( (sal_Int32) 1 );
            else if( aProxyMode.equals( rtl::OUString::createFromAscii( "none" ) ) )
                return uno::makeAny( (sal_Int32) 0 );
        }
            break;

        case SETTING_MAILER_PROGRAM:
        {
            rtl::OUString aMailer;
            uno::Any aOriginalValue = makeAnyOfGconfValue( aGconfValue );
            aOriginalValue >>= aMailer;
            sal_Int32 nIndex = 0;
            return uno::makeAny( aMailer.getToken( 0, ' ', nIndex ) );
        }

#ifdef ENABLE_LOCKDOWN
        // "short" values need to be returned a sal_Int16
        case SETTING_FONT_ANTI_ALIASING_MIN_PIXEL:
        case SETTING_SYMBOL_SET:
        {
            sal_Int32 nShortValue;
            uno::Any aOriginalValue = makeAnyOfGconfValue( aGconfValue );
            aOriginalValue >>= nShortValue;
            return uno::makeAny( (sal_Int16) nShortValue );
        }
            break;
#endif // ENABLE_LOCKDOWN

        // "boolean" values that need a string to be returned
        case SETTING_ENABLE_ACCESSIBILITY:
#ifdef ENABLE_LOCKDOWN
        case SETTING_DISABLE_PRINTING:
#endif // ENABLE_LOCKDOWN
        {
            sal_Bool bBooleanValue;
            uno::Any aOriginalValue = makeAnyOfGconfValue( aGconfValue );
            aOriginalValue >>= bBooleanValue;
            return uno::makeAny( rtl::OUString::valueOf( (sal_Bool) bBooleanValue ) );
        }

        case SETTING_WORK_DIRECTORY:
        {
            return uno::makeAny( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$(work)/Documents" ) ) );
        }

        case SETTING_USER_GIVENNAME:
        {
            rtl::OUString aCompleteName( rtl::OStringToOUString(
                g_get_real_name(), osl_getThreadTextEncoding() ) );
            sal_Int32 nIndex = 0;
            rtl::OUString aGivenName;
            do
                aGivenName = aCompleteName.getToken( 0, ' ', nIndex );
            while ( nIndex == 0 );

            return uno::makeAny( aGivenName );

        }

        case SETTING_USER_SURNAME:
        {
            rtl::OUString aCompleteName( rtl::OStringToOUString(
                g_get_real_name(), osl_getThreadTextEncoding() ) );
            sal_Int32 nIndex = 0;
            rtl::OUString aSurname;
            do
                aSurname = aCompleteName.getToken( 0, ' ', nIndex );
            while ( nIndex >= 0 );

            return uno::makeAny( aSurname );
        }

        default:
            fprintf( stderr, "Unhandled setting to translate.\n" );
            break;
    }

    return uno::Any();
}

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

sal_Bool SAL_CALL isDependencySatisfied( const ConfigurationValue aValue )
{
    switch( aValue.nDependsOn )
    {
        case SETTING_PROXY_MODE:
        {
            GConfClient* aClient = GconfBackend::getGconfClient();
            GConfValue* aGconfValue = gconf_client_get( aClient, GCONF_PROXY_MODE_KEY, NULL );

            if( ( aGconfValue != NULL ) && ( g_strcasecmp( "manual", gconf_value_get_string( aGconfValue ) ) == 0 ) )
                return sal_True;
        }
            break;

        case SETTING_WORK_DIRECTORY:
        {
            osl::Security aSecurity;
            rtl::OUString aDocumentsDirURL;
            if ( aSecurity.getHomeDir( aDocumentsDirURL ) )
            {
                aDocumentsDirURL += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/Documents" ) );
                osl::Directory aDocumentsDir( aDocumentsDirURL );

                if( osl::FileBase::E_None == aDocumentsDir.open() )
                    return sal_True;
            }
        }
            break;

        case SETTING_USER_GIVENNAME:
        {
            rtl::OUString aCompleteName( rtl::OStringToOUString(
                g_get_real_name(), osl_getThreadTextEncoding() ) );
            if( !aCompleteName.equalsAscii( "Unknown" ) )
                return sal_True;
        }
            break;

        case SETTING_USER_SURNAME:
        {
            rtl::OUString aCompleteName( rtl::OStringToOUString(
                g_get_real_name(), osl_getThreadTextEncoding() ) );
            if( !aCompleteName.equalsAscii( "Unknown" ) )
            {
                if( aCompleteName.trim().indexOf(rtl::OUString::createFromAscii(" "), 0) != -1 )
                    return sal_True;
            }
        }
            break;

#ifdef ENABLE_LOCKDOWN
        case SETTING_AUTO_SAVE:
        {
            GConfClient* aClient = GconfBackend::getGconfClient();
            GConfValue* aGconfValue = gconf_client_get( aClient, GCONF_AUTO_SAVE_KEY, NULL );

            if( ( aGconfValue != NULL ) && gconf_value_get_bool( aGconfValue ) )
                return sal_True;
        }
            break;
#endif // ENABLE_LOCKDOWN

        default:
            fprintf( stderr, "Unhandled setting to check dependency.\n" );
            break;
    }

    return sal_False;
}

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

void SAL_CALL GconfLayer::readData( const uno::Reference<backend::XLayerHandler>& xHandler )
    throw ( backend::MalformedDataException, lang::NullPointerException,
            lang::WrappedTargetException, uno::RuntimeException )
{
    if( ! m_xLayerContentDescriber.is() )
    {
        throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
            "Could not create com.sun.star.configuration.backend.LayerContentDescriber Service"
        ) ), static_cast < backend::XLayer * > (this) );
    }

    uno::Sequence<backend::PropertyInfo> aPropInfoList( m_nConfigurationValues );
    sal_Int32 nProperties = 0;

    GConfClient* aClient = GconfBackend::getGconfClient();
    GConfValue* aGconfValue;
    int i = 0;

    while( m_pPreloadValuesList[i] != NULL )
        gconf_client_preload( aClient, m_pPreloadValuesList[i++], GCONF_CLIENT_PRELOAD_ONELEVEL, NULL );

    for( i = 0; i < m_nConfigurationValues; i++ )
    {
        aGconfValue = gconf_client_get( aClient, m_pConfigurationValuesList[i].GconfItem, NULL );

        if( ( m_pConfigurationValuesList[i].nDependsOn != SETTINGS_LAST ) && !isDependencySatisfied( m_pConfigurationValuesList[i] ) )
            continue;

        if( aGconfValue != NULL )
        {
            aPropInfoList[nProperties].Name      = rtl::OUString::createFromAscii( m_pConfigurationValuesList[i].OOoConfItem );
            aPropInfoList[nProperties].Type      = rtl::OUString::createFromAscii( m_pConfigurationValuesList[i].OOoConfValueType );
            aPropInfoList[nProperties].Protected = m_pConfigurationValuesList[i].bLocked;

            if( m_pConfigurationValuesList[i].bNeedsTranslation )
                aPropInfoList[nProperties].Value = translateToOOo( m_pConfigurationValuesList[i], aGconfValue );
            else
                aPropInfoList[nProperties].Value = makeAnyOfGconfValue( aGconfValue );

            nProperties++;
        }
    }

    if( nProperties > 0 )
    {
        aPropInfoList.realloc( nProperties );
        m_xLayerContentDescriber->describeLayer( xHandler, aPropInfoList );
    }
}

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

rtl::OUString SAL_CALL GconfLayer::getTimestamp( void )
    throw (uno::RuntimeException)
{
    // Return a hash of the values as timestamp to avoid regenerating
    // the binary cache on each office launch.
    rtl::OStringBuffer aTimeStamp;

    // Make sure the timestamp differs from beta
    sal_Int32 nHashCode = 0;

    GConfClient* aClient = GconfBackend::getGconfClient();
    GConfValue* aGconfValue;
    int i = 0;

    while( m_pPreloadValuesList[i] != NULL )
        gconf_client_preload( aClient, m_pPreloadValuesList[i++], GCONF_CLIENT_PRELOAD_ONELEVEL, NULL );

    for( i = 0; i < m_nConfigurationValues; i++ )
    {
        aGconfValue = gconf_client_get( aClient, m_pConfigurationValuesList[i].GconfItem, NULL );

        if( aGconfValue != NULL )
        {
            switch( aGconfValue->type )
            {
                case GCONF_VALUE_BOOL:
                    nHashCode ^= (sal_Int32) !gconf_value_get_bool( aGconfValue );
                    break;

                case GCONF_VALUE_INT:
                    nHashCode ^= (sal_Int32) gconf_value_get_int( aGconfValue );
                    break;

                case GCONF_VALUE_STRING:
                    nHashCode ^= (sal_Int32) g_str_hash( gconf_value_get_string( aGconfValue ) );
                    break;

                default:
                    fprintf( stderr, "getTimestamp: Type not handled.\n" );
                    break;
            }
            nHashCode = (nHashCode << 5) - nHashCode;
        }
    }

    return rtl::OUString::valueOf( nHashCode );
}
<commit_msg>INTEGRATION: CWS pathoptions01 (1.7.10); FILE MERGED 2006/07/11 12:04:22 obr 1.7.10.1: #i66461#  has moved to Paths.xcs<commit_after>#ifndef GCONFLAYER_HXX_
#include "gconflayer.hxx"
#endif

#ifndef _COM_SUN_STAR_CONFIGURATION_BACKEND_PROPERTYINFO_HPP_
#include <com/sun/star/configuration/backend/PropertyInfo.hpp>
#endif

#ifndef _COM_SUN_STAR_CONFIGURATION_BACKEND_XLAYERCONTENTDESCIBER_HPP_
#include <com/sun/star/configuration/backend/XLayerContentDescriber.hpp>
#endif

#ifndef _RTL_STRBUF_HXX_
#include <rtl/strbuf.hxx>
#endif

#ifndef _OSL_SECURITY_HXX_
#include <osl/security.hxx>
#endif

#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif

#ifndef _OSL_THREAD_H_
#include <osl/thread.h>
#endif

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif

//==============================================================================

GconfLayer::GconfLayer( const uno::Reference<uno::XComponentContext>& xContext,
    const ConfigurationValue pConfigurationValuesList[],
    const sal_Int32 nConfigurationValues,
    const char * pPreloadValuesList[] )
    :m_pConfigurationValuesList( pConfigurationValuesList )
    ,m_nConfigurationValues( nConfigurationValues )
    ,m_pPreloadValuesList( pPreloadValuesList )
{
    //Create instance of LayerContentDescriber Service
    rtl::OUString const k_sLayerDescriberService( RTL_CONSTASCII_USTRINGPARAM(
        "com.sun.star.comp.configuration.backend.LayerDescriber" ) );

    typedef uno::Reference<backend::XLayerContentDescriber> LayerDescriber;
    uno::Reference< lang::XMultiComponentFactory > xServiceManager = xContext->getServiceManager();
    if( xServiceManager.is() )
    {
        m_xLayerContentDescriber = LayerDescriber::query(
            xServiceManager->createInstanceWithContext( k_sLayerDescriberService, xContext ) );
    }
    else
    {
        OSL_TRACE( "Could not retrieve ServiceManager" );
    }
}

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

uno::Any makeAnyOfGconfValue( GConfValue *aGconfValue )
{
    switch( aGconfValue->type )
    {
        case GCONF_VALUE_BOOL:
            return uno::makeAny( (sal_Bool) gconf_value_get_bool( aGconfValue ) );

        case GCONF_VALUE_INT:
            return uno::makeAny( (sal_Int32) gconf_value_get_int( aGconfValue ) );

        case GCONF_VALUE_STRING:
            return uno::makeAny( OStringToOUString( rtl::OString(
                gconf_value_get_string(aGconfValue) ), RTL_TEXTENCODING_UTF8 ) );

        default:
            fprintf( stderr, "makeAnyOfGconfValue: Type not handled.\n" );
            break;
    }

    return uno::Any();
}

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

uno::Any translateToOOo( const ConfigurationValue aValue, GConfValue *aGconfValue )
{
    switch( aValue.nSettingId )
    {
        case SETTING_PROXY_MODE:
        {
            rtl::OUString aProxyMode;
            uno::Any aOriginalValue = makeAnyOfGconfValue( aGconfValue );
            aOriginalValue >>= aProxyMode;

            if( aProxyMode.equals( rtl::OUString::createFromAscii( "manual" ) ) )
                return uno::makeAny( (sal_Int32) 1 );
            else if( aProxyMode.equals( rtl::OUString::createFromAscii( "none" ) ) )
                return uno::makeAny( (sal_Int32) 0 );
        }
            break;

        case SETTING_MAILER_PROGRAM:
        {
            rtl::OUString aMailer;
            uno::Any aOriginalValue = makeAnyOfGconfValue( aGconfValue );
            aOriginalValue >>= aMailer;
            sal_Int32 nIndex = 0;
            return uno::makeAny( aMailer.getToken( 0, ' ', nIndex ) );
        }

#ifdef ENABLE_LOCKDOWN
        // "short" values need to be returned a sal_Int16
        case SETTING_FONT_ANTI_ALIASING_MIN_PIXEL:
        case SETTING_SYMBOL_SET:
        {
            sal_Int32 nShortValue;
            uno::Any aOriginalValue = makeAnyOfGconfValue( aGconfValue );
            aOriginalValue >>= nShortValue;
            return uno::makeAny( (sal_Int16) nShortValue );
        }
            break;
#endif // ENABLE_LOCKDOWN

        // "boolean" values that need a string to be returned
        case SETTING_ENABLE_ACCESSIBILITY:
#ifdef ENABLE_LOCKDOWN
        case SETTING_DISABLE_PRINTING:
#endif // ENABLE_LOCKDOWN
        {
            sal_Bool bBooleanValue;
            uno::Any aOriginalValue = makeAnyOfGconfValue( aGconfValue );
            aOriginalValue >>= bBooleanValue;
            return uno::makeAny( rtl::OUString::valueOf( (sal_Bool) bBooleanValue ) );
        }

        case SETTING_WORK_DIRECTORY:
        {
            osl::Security aSecurity;
            rtl::OUString aDocumentsDirURL;
            if ( aSecurity.getHomeDir( aDocumentsDirURL ) )
                aDocumentsDirURL += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/Documents" ) );
            return uno::makeAny( aDocumentsDirURL );
        }

        case SETTING_USER_GIVENNAME:
        {
            rtl::OUString aCompleteName( rtl::OStringToOUString(
                g_get_real_name(), osl_getThreadTextEncoding() ) );
            sal_Int32 nIndex = 0;
            rtl::OUString aGivenName;
            do
                aGivenName = aCompleteName.getToken( 0, ' ', nIndex );
            while ( nIndex == 0 );

            return uno::makeAny( aGivenName );

        }

        case SETTING_USER_SURNAME:
        {
            rtl::OUString aCompleteName( rtl::OStringToOUString(
                g_get_real_name(), osl_getThreadTextEncoding() ) );
            sal_Int32 nIndex = 0;
            rtl::OUString aSurname;
            do
                aSurname = aCompleteName.getToken( 0, ' ', nIndex );
            while ( nIndex >= 0 );

            return uno::makeAny( aSurname );
        }

        default:
            fprintf( stderr, "Unhandled setting to translate.\n" );
            break;
    }

    return uno::Any();
}

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

sal_Bool SAL_CALL isDependencySatisfied( const ConfigurationValue aValue )
{
    switch( aValue.nDependsOn )
    {
        case SETTING_PROXY_MODE:
        {
            GConfClient* aClient = GconfBackend::getGconfClient();
            GConfValue* aGconfValue = gconf_client_get( aClient, GCONF_PROXY_MODE_KEY, NULL );

            if( ( aGconfValue != NULL ) && ( g_strcasecmp( "manual", gconf_value_get_string( aGconfValue ) ) == 0 ) )
                return sal_True;
        }
            break;

        case SETTING_WORK_DIRECTORY:
        {
            osl::Security aSecurity;
            rtl::OUString aDocumentsDirURL;
            if ( aSecurity.getHomeDir( aDocumentsDirURL ) )
            {
                aDocumentsDirURL += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/Documents" ) );
                osl::Directory aDocumentsDir( aDocumentsDirURL );

                if( osl::FileBase::E_None == aDocumentsDir.open() )
                    return sal_True;
            }
        }
            break;

        case SETTING_USER_GIVENNAME:
        {
            rtl::OUString aCompleteName( rtl::OStringToOUString(
                g_get_real_name(), osl_getThreadTextEncoding() ) );
            if( !aCompleteName.equalsAscii( "Unknown" ) )
                return sal_True;
        }
            break;

        case SETTING_USER_SURNAME:
        {
            rtl::OUString aCompleteName( rtl::OStringToOUString(
                g_get_real_name(), osl_getThreadTextEncoding() ) );
            if( !aCompleteName.equalsAscii( "Unknown" ) )
            {
                if( aCompleteName.trim().indexOf(rtl::OUString::createFromAscii(" "), 0) != -1 )
                    return sal_True;
            }
        }
            break;

#ifdef ENABLE_LOCKDOWN
        case SETTING_AUTO_SAVE:
        {
            GConfClient* aClient = GconfBackend::getGconfClient();
            GConfValue* aGconfValue = gconf_client_get( aClient, GCONF_AUTO_SAVE_KEY, NULL );

            if( ( aGconfValue != NULL ) && gconf_value_get_bool( aGconfValue ) )
                return sal_True;
        }
            break;
#endif // ENABLE_LOCKDOWN

        default:
            fprintf( stderr, "Unhandled setting to check dependency.\n" );
            break;
    }

    return sal_False;
}

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

void SAL_CALL GconfLayer::readData( const uno::Reference<backend::XLayerHandler>& xHandler )
    throw ( backend::MalformedDataException, lang::NullPointerException,
            lang::WrappedTargetException, uno::RuntimeException )
{
    if( ! m_xLayerContentDescriber.is() )
    {
        throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
            "Could not create com.sun.star.configuration.backend.LayerContentDescriber Service"
        ) ), static_cast < backend::XLayer * > (this) );
    }

    uno::Sequence<backend::PropertyInfo> aPropInfoList( m_nConfigurationValues );
    sal_Int32 nProperties = 0;

    GConfClient* aClient = GconfBackend::getGconfClient();
    GConfValue* aGconfValue;
    int i = 0;

    while( m_pPreloadValuesList[i] != NULL )
        gconf_client_preload( aClient, m_pPreloadValuesList[i++], GCONF_CLIENT_PRELOAD_ONELEVEL, NULL );

    for( i = 0; i < m_nConfigurationValues; i++ )
    {
        aGconfValue = gconf_client_get( aClient, m_pConfigurationValuesList[i].GconfItem, NULL );

        if( ( m_pConfigurationValuesList[i].nDependsOn != SETTINGS_LAST ) && !isDependencySatisfied( m_pConfigurationValuesList[i] ) )
            continue;

        if( aGconfValue != NULL )
        {
            aPropInfoList[nProperties].Name      = rtl::OUString::createFromAscii( m_pConfigurationValuesList[i].OOoConfItem );
            aPropInfoList[nProperties].Type      = rtl::OUString::createFromAscii( m_pConfigurationValuesList[i].OOoConfValueType );
            aPropInfoList[nProperties].Protected = m_pConfigurationValuesList[i].bLocked;

            if( m_pConfigurationValuesList[i].bNeedsTranslation )
                aPropInfoList[nProperties].Value = translateToOOo( m_pConfigurationValuesList[i], aGconfValue );
            else
                aPropInfoList[nProperties].Value = makeAnyOfGconfValue( aGconfValue );

            nProperties++;
        }
    }

    if( nProperties > 0 )
    {
        aPropInfoList.realloc( nProperties );
        m_xLayerContentDescriber->describeLayer( xHandler, aPropInfoList );
    }
}

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

rtl::OUString SAL_CALL GconfLayer::getTimestamp( void )
    throw (uno::RuntimeException)
{
    // Return a hash of the values as timestamp to avoid regenerating
    // the binary cache on each office launch.
    rtl::OStringBuffer aTimeStamp;

    // Make sure the timestamp differs from beta
    sal_Int32 nHashCode = 0;

    GConfClient* aClient = GconfBackend::getGconfClient();
    GConfValue* aGconfValue;
    int i = 0;

    while( m_pPreloadValuesList[i] != NULL )
        gconf_client_preload( aClient, m_pPreloadValuesList[i++], GCONF_CLIENT_PRELOAD_ONELEVEL, NULL );

    for( i = 0; i < m_nConfigurationValues; i++ )
    {
        aGconfValue = gconf_client_get( aClient, m_pConfigurationValuesList[i].GconfItem, NULL );

        if( aGconfValue != NULL )
        {
            switch( aGconfValue->type )
            {
                case GCONF_VALUE_BOOL:
                    nHashCode ^= (sal_Int32) !gconf_value_get_bool( aGconfValue );
                    break;

                case GCONF_VALUE_INT:
                    nHashCode ^= (sal_Int32) gconf_value_get_int( aGconfValue );
                    break;

                case GCONF_VALUE_STRING:
                    nHashCode ^= (sal_Int32) g_str_hash( gconf_value_get_string( aGconfValue ) );
                    break;

                default:
                    fprintf( stderr, "getTimestamp: Type not handled.\n" );
                    break;
            }
            nHashCode = (nHashCode << 5) - nHashCode;
        }
    }

    return rtl::OUString::valueOf( nHashCode );
}
<|endoftext|>


<commit_before>#ifndef GCONFLAYER_HXX_
#define GCONFLAYER_HXX_

#ifndef GCONFBACKEND_HXX_
#include "gconfbackend.hxx"
#endif // GCONFBACKEND_HXX_

#ifndef _COM_SUN_STAR_CONFIGURATION_BACKEND_XLAYER_HPP_
#include <com/sun/star/configuration/backend/XLayer.hpp>
#endif // _COM_SUN_STAR_CONFIGURATION_BACKEND_XLAYER_HPP_

#ifndef _COM_SUN_STAR_CONFIGURATION_BACKEND_BACKENDACCESSEXCEPTION_HPP_
#include <com/sun/star/configuration/backend/BackendAccessException.hpp>
#endif // _COM_SUN_STAR_CONFIGURATION_BACKEND_BACKENDACCESSEXCEPTION_HPP_

#ifndef _COM_SUN_STAR_CONFIGURATION_BACKEND_XLAYERCONTENTDESCIBER_HPP_
#include <com/sun/star/configuration/backend/XLayerContentDescriber.hpp>
#endif // _COM_SUN_STAR_CONFIGURATION_BACKEND_XLAYERCONTENTDESCIBER_HPP_

#ifndef _COM_SUN_STAR_UTIL_XTIMESTAMPED_HPP_
#include <com/sun/star/util/XTimeStamped.hpp>
#endif // _COM_SUN_STAR_UTIL_XTIMESTAMPED_HPP_

#ifndef _CPPUHELPER_IMPLBASE2_HXX_
#include <cppuhelper/implbase2.hxx>
#endif // _CPPUHELPER_IMPLBASE2_HXX_

#define GCONF_PROXY_MODE_KEY "/system/proxy/mode"
#define GCONF_AUTO_SAVE_KEY  "/apps/openoffice/auto_save"

enum ConfigurationSetting
{
    SETTING_PROXY_MODE,
    SETTING_PROXY_HTTP_HOST,
    SETTING_PROXY_HTTP_PORT,
    SETTING_PROXY_FTP_HOST,
    SETTING_PROXY_FTP_PORT,
    SETTING_ENABLE_ACCESSIBILITY,
    SETTING_MAILER_PROGRAM,
    SETTING_WORK_DIRECTORY,
    SETTING_USER_GIVENNAME,
    SETTING_USER_SURNAME,

#ifdef ENABLE_LOCKDOWN

    SETTING_DISABLE_PRINTING,
    SETTING_USE_SYSTEM_FILE_DIALOG,
    SETTING_DISABLE_UI_CUSTOMIZATION,
    SETTING_PRINTING_MODIFIES_DOCUMENT,
    SETTING_SHOW_ICONS_IN_MENUS,
    SETTING_SHOW_INACTIVE_MENUITEMS,
    SETTING_SHOW_FONT_PREVIEW,
    SETTING_SHOW_FONT_HISTORY,
    SETTING_ENABLE_OPENGL,
    SETTING_OPTIMIZE_OPENGL,
    SETTING_SAVE_DOCUMENT_WINDOWS,
    SETTING_SAVE_DOCUMENT_VIEW_INFO,
    SETTING_USE_SYSTEM_FONT,
    SETTING_USE_FONT_ANTI_ALIASING,
    SETTING_FONT_ANTI_ALIASING_MIN_PIXEL,
    SETTING_WARN_CREATE_PDF,
    SETTING_WARN_PRINT_DOC,
    SETTING_WARN_SAVEORSEND_DOC,
    SETTING_WARN_SIGN_DOC,
    SETTING_REMOVE_PERSONAL_INFO,
    SETTING_RECOMMEND_PASSWORD,
    SETTING_UNDO_STEPS,
    SETTING_SYMBOL_SET,
    SETTING_MACRO_SECURITY_LEVEL,
    SETTING_CREATE_BACKUP,
    SETTING_WARN_ALIEN_FORMAT,
    SETTING_AUTO_SAVE,
    SETTING_AUTO_SAVE_INTERVAL,
    SETTING_WRITER_DEFAULT_DOC_FORMAT,
    SETTING_IMPRESS_DEFAULT_DOC_FORMAT,
    SETTING_CALC_DEFAULT_DOC_FORMAT,

#endif // ENABLE_LOCKDOWN

    SETTINGS_LAST
};

struct ConfigurationValue
{
    const ConfigurationSetting nSettingId;
    const gchar *GconfItem;
    const char *OOoConfItem;
    const char *OOoConfValueType;
    const sal_Bool bLocked;
    const sal_Bool bNeedsTranslation;
    const ConfigurationSetting nDependsOn;
};

namespace css = com::sun::star ;
namespace uno = css::uno ;
namespace lang = css::lang ;
namespace backend = css::configuration::backend ;
namespace util = css::util ;

/**
  Implementation of the XLayer interface for the Gconf values mapped into
  the org.openoffice.* configuration component.
  */
class GconfLayer : public cppu::WeakImplHelper2<backend::XLayer, util::XTimeStamped>
{
public :
    /**
      Constructor given the component context

      @param xContext       The component context
    */

    GconfLayer( const uno::Reference<uno::XComponentContext>& xContext,
                const ConfigurationValue pConfigurationValuesList[],
                const sal_Int32 nConfigurationValues,
                const char * pPreloadValuesList[] );

    // XLayer
    virtual void SAL_CALL readData(
        const uno::Reference<backend::XLayerHandler>& xHandler)
        throw ( backend::MalformedDataException,
                lang::NullPointerException,
                lang::WrappedTargetException,
                uno::RuntimeException );

    // XTimeStamped
    virtual rtl::OUString SAL_CALL getTimestamp(void)
            throw (uno::RuntimeException);

    protected:

    /** Destructor */
    ~GconfLayer(void) {}

private :
    uno::Reference<backend::XLayerContentDescriber> m_xLayerContentDescriber;
    const ConfigurationValue* m_pConfigurationValuesList;
    const sal_Int32 m_nConfigurationValues;
    const char** m_pPreloadValuesList;
  } ;

#endif // GCONFLAYER
<commit_msg>INTEGRATION: CWS shellfix04 (1.5.66); FILE MERGED 2006/10/12 13:08:27 obr 1.5.66.1: #i67985# patch applied<commit_after>#ifndef GCONFLAYER_HXX_
#define GCONFLAYER_HXX_

#ifndef GCONFBACKEND_HXX_
#include "gconfbackend.hxx"
#endif // GCONFBACKEND_HXX_

#ifndef _COM_SUN_STAR_CONFIGURATION_BACKEND_XLAYER_HPP_
#include <com/sun/star/configuration/backend/XLayer.hpp>
#endif // _COM_SUN_STAR_CONFIGURATION_BACKEND_XLAYER_HPP_

#ifndef _COM_SUN_STAR_CONFIGURATION_BACKEND_BACKENDACCESSEXCEPTION_HPP_
#include <com/sun/star/configuration/backend/BackendAccessException.hpp>
#endif // _COM_SUN_STAR_CONFIGURATION_BACKEND_BACKENDACCESSEXCEPTION_HPP_

#ifndef _COM_SUN_STAR_CONFIGURATION_BACKEND_XLAYERCONTENTDESCIBER_HPP_
#include <com/sun/star/configuration/backend/XLayerContentDescriber.hpp>
#endif // _COM_SUN_STAR_CONFIGURATION_BACKEND_XLAYERCONTENTDESCIBER_HPP_

#ifndef _COM_SUN_STAR_UTIL_XTIMESTAMPED_HPP_
#include <com/sun/star/util/XTimeStamped.hpp>
#endif // _COM_SUN_STAR_UTIL_XTIMESTAMPED_HPP_

#ifndef _CPPUHELPER_IMPLBASE2_HXX_
#include <cppuhelper/implbase2.hxx>
#endif // _CPPUHELPER_IMPLBASE2_HXX_

#define GCONF_PROXY_MODE_KEY "/system/proxy/mode"
#define GCONF_AUTO_SAVE_KEY  "/apps/openoffice/auto_save"

enum ConfigurationSetting
{
    SETTING_PROXY_MODE,
    SETTING_PROXY_HTTP_HOST,
    SETTING_PROXY_HTTP_PORT,
    SETTING_PROXY_FTP_HOST,
    SETTING_PROXY_FTP_PORT,
    SETTING_ENABLE_ACCESSIBILITY,
    SETTING_MAILER_PROGRAM,
    SETTING_WORK_DIRECTORY,
    SETTING_SOURCEVIEWFONT_NAME,
    SETTING_SOURCEVIEWFONT_HEIGHT,
    SETTING_USER_GIVENNAME,
    SETTING_USER_SURNAME,

#ifdef ENABLE_LOCKDOWN

    SETTING_DISABLE_PRINTING,
    SETTING_USE_SYSTEM_FILE_DIALOG,
    SETTING_DISABLE_UI_CUSTOMIZATION,
    SETTING_PRINTING_MODIFIES_DOCUMENT,
    SETTING_SHOW_ICONS_IN_MENUS,
    SETTING_SHOW_INACTIVE_MENUITEMS,
    SETTING_SHOW_FONT_PREVIEW,
    SETTING_SHOW_FONT_HISTORY,
    SETTING_ENABLE_OPENGL,
    SETTING_OPTIMIZE_OPENGL,
    SETTING_SAVE_DOCUMENT_WINDOWS,
    SETTING_SAVE_DOCUMENT_VIEW_INFO,
    SETTING_USE_SYSTEM_FONT,
    SETTING_USE_FONT_ANTI_ALIASING,
    SETTING_FONT_ANTI_ALIASING_MIN_PIXEL,
    SETTING_WARN_CREATE_PDF,
    SETTING_WARN_PRINT_DOC,
    SETTING_WARN_SAVEORSEND_DOC,
    SETTING_WARN_SIGN_DOC,
    SETTING_REMOVE_PERSONAL_INFO,
    SETTING_RECOMMEND_PASSWORD,
    SETTING_UNDO_STEPS,
    SETTING_SYMBOL_SET,
    SETTING_MACRO_SECURITY_LEVEL,
    SETTING_CREATE_BACKUP,
    SETTING_WARN_ALIEN_FORMAT,
    SETTING_AUTO_SAVE,
    SETTING_AUTO_SAVE_INTERVAL,
    SETTING_WRITER_DEFAULT_DOC_FORMAT,
    SETTING_IMPRESS_DEFAULT_DOC_FORMAT,
    SETTING_CALC_DEFAULT_DOC_FORMAT,

#endif // ENABLE_LOCKDOWN

    SETTINGS_LAST
};

struct ConfigurationValue
{
    const ConfigurationSetting nSettingId;
    const gchar *GconfItem;
    const char *OOoConfItem;
    const char *OOoConfValueType;
    const sal_Bool bLocked;
    const sal_Bool bNeedsTranslation;
    const ConfigurationSetting nDependsOn;
};

namespace css = com::sun::star ;
namespace uno = css::uno ;
namespace lang = css::lang ;
namespace backend = css::configuration::backend ;
namespace util = css::util ;

/**
  Implementation of the XLayer interface for the Gconf values mapped into
  the org.openoffice.* configuration component.
  */
class GconfLayer : public cppu::WeakImplHelper2<backend::XLayer, util::XTimeStamped>
{
public :
    /**
      Constructor given the component context

      @param xContext       The component context
    */

    GconfLayer( const uno::Reference<uno::XComponentContext>& xContext,
                const ConfigurationValue pConfigurationValuesList[],
                const sal_Int32 nConfigurationValues,
                const char * pPreloadValuesList[] );

    // XLayer
    virtual void SAL_CALL readData(
        const uno::Reference<backend::XLayerHandler>& xHandler)
        throw ( backend::MalformedDataException,
                lang::NullPointerException,
                lang::WrappedTargetException,
                uno::RuntimeException );

    // XTimeStamped
    virtual rtl::OUString SAL_CALL getTimestamp(void)
            throw (uno::RuntimeException);

    protected:

    /** Destructor */
    ~GconfLayer(void) {}

private :
    uno::Reference<backend::XLayerContentDescriber> m_xLayerContentDescriber;
    const ConfigurationValue* m_pConfigurationValuesList;
    const sal_Int32 m_nConfigurationValues;
    const char** m_pPreloadValuesList;
  } ;

#endif // GCONFLAYER
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "probe.h"

#include "msvcprobe.h"
#include "xcodeprobe.h"

#include <logging/translator.h>
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/profile.h>
#include <tools/settings.h>

#include <QDir>
#include <QFileInfo>
#include <QProcess>
#include <QStringList>
#include <QTextStream>

#include <cstdio>

using namespace qbs;
using Internal::HostOsInfo;
using Internal::Tr;

static QTextStream qStdout(stdout);
static QTextStream qStderr(stderr);

static QString findExecutable(const QString &fileName)
{
    const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
    foreach (const QString &ppath, path.split(HostOsInfo::pathListSeparator())) {
        const QString fullPath = ppath + QLatin1Char('/') + fileName;
        if (QFileInfo(fullPath).exists())
            return QDir::cleanPath(fullPath);
    }
    return QString();
}

static QString qsystem(const QString &exe, const QStringList &args = QStringList())
{
    QProcess p;
    p.setProcessChannelMode(QProcess::MergedChannels);
    p.start(exe, args);
    if (!p.waitForStarted()) {
        throw qbs::ErrorInfo(Tr::tr("Failed to start compiler '%1': %2")
                             .arg(exe, p.errorString()));
    }
    if (!p.waitForFinished() || p.exitCode() != 0)
        throw qbs::ErrorInfo(Tr::tr("Failed to run compiler '%1': %2").arg(exe, p.errorString()));
    return QString::fromLocal8Bit(p.readAll());
}

static QStringList validMinGWMachines()
{
    // List of MinGW machine names (gcc -dumpmachine) recognized by Qbs
    return QStringList()
            << QLatin1String("mingw32") << QLatin1String("mingw64")
            << QLatin1String("i686-w64-mingw32") << QLatin1String("x86_64-w64-mingw32")
            << QLatin1String("i586-mingw32msvc") << QLatin1String("amd64-mingw32msvc");
}

static QStringList completeToolchainList(const QString &toolchainName)
{
    QStringList toolchains(toolchainName);
    if (toolchainName == QLatin1String("clang"))
        toolchains << QLatin1String("llvm") << QLatin1String("gcc");
    else if (toolchainName == QLatin1String("mingw"))
        toolchains << QLatin1String("gcc");
    return toolchains;
}

static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
{
    if (compilerName.contains(QLatin1String("clang")))
        return completeToolchainList(QLatin1String("clang"));
    if (compilerName.contains(QLatin1String("llvm")))
        return QStringList() << QLatin1String("llvm") << QLatin1String("gcc");
    if (compilerName.contains(QLatin1String("gcc")))
        return QStringList() << QLatin1String("gcc");
    if (compilerName == QLatin1String("cl.exe"))
        return QStringList() << QLatin1String("msvc");
    return QStringList();
}

static QString actualCompilerFilePath(const QString &compilerFilePath)
{
    const QFileInfo cfi(compilerFilePath);
    QString compilerFileName = cfi.fileName();

    // People usually want to compile C++. Since we currently link via
    // the compiler executable, using the plain C compiler will likely lead to linking problems.
    compilerFileName.replace(QLatin1String("gcc"), QLatin1String("g++"));
    compilerFileName.replace(QLatin1String("clang"), QLatin1String("clang++"));
    return cfi.absolutePath() + QLatin1Char('/') + compilerFileName;
}

static QString gccMachineName(const QString &compilerFilePath)
{
    return qsystem(compilerFilePath, QStringList() << QLatin1String("-dumpmachine")).trimmed();
}

static void setCommonProperties(Profile &profile, const QString &compilerFilePath,
                                const QStringList &toolchainTypes, const QString &architecture)
{
    QFileInfo cfi(compilerFilePath);
    profile.setValue(QLatin1String("cpp.toolchainInstallPath"), cfi.absolutePath());
    profile.setValue(QLatin1String("cpp.compilerName"), cfi.fileName());
    profile.setValue(QLatin1String("qbs.toolchain"), toolchainTypes);
    profile.setValue(QLatin1String("qbs.architecture"),
                     HostOsInfo::canonicalArchitecture(architecture));
    profile.setValue(QLatin1String("qbs.endianness"),
                     HostOsInfo::defaultEndianness(architecture));
}

static Profile createMingwProfile(const QString &_compilerFilePath, Settings *settings,
        const QString &profileName = QString())
{
    const QString compilerFilePath = actualCompilerFilePath(_compilerFilePath);
    const QString machineName = gccMachineName(compilerFilePath);
    const QStringList compilerTriplet = machineName.split(QLatin1Char('-'));
    if (!validMinGWMachines().contains(machineName)) {
        throw qbs::ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.")
                .arg(machineName));
    }
    Profile profile(!profileName.isEmpty() ? profileName : machineName, settings);
    profile.removeProfile();
    profile.setValue(QLatin1String("qbs.targetOS"), QStringList(QLatin1String("windows")));
    setCommonProperties(profile, compilerFilePath, completeToolchainList(QLatin1String("mingw")),
                        compilerTriplet.first());
    qStdout << Tr::tr("Profile '%1' created for '%2'.").arg(profile.name(), compilerFilePath)
            << endl;
    return profile;
}

static Profile createGccProfile(const QString &_compilerFilePath, Settings *settings,
                                const QStringList &toolchainTypes, const QString &profileName)
{
    const QString compilerFilePath = actualCompilerFilePath(_compilerFilePath);
    const QString machineName = gccMachineName(compilerFilePath);
    const QStringList compilerTriplet = machineName.split(QLatin1Char('-'));
    if (compilerTriplet.count() < 2) {
        throw qbs::ErrorInfo(Tr::tr("Architecture '%1' of compiler at '%1' not understood.")
                             .arg(compilerFilePath, machineName));
    }
    Profile profile(profileName, settings);
    setCommonProperties(profile, compilerFilePath, toolchainTypes, compilerTriplet.first());
    const QString compilerName = QFileInfo(compilerFilePath).fileName();
    if (compilerName.contains(QLatin1Char('-'))) {
        QStringList nameParts = compilerName.split(QLatin1Char('-'));
        profile.setValue(QLatin1String("cpp.compilerName"), nameParts.takeLast());
        profile.setValue(QLatin1String("cpp.toolchainPrefix"),
                         nameParts.join(QLatin1String("-")) + QLatin1Char('-'));
    }
    qStdout << Tr::tr("Profile '%1' created for '%2'.").arg(profile.name(), compilerFilePath)
            << endl;
    return profile;
}

static void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compilerName)
{
    qStdout << Tr::tr("Trying to detect %1...").arg(compilerName) << endl;

    const QString crossCompilePrefix = QString::fromLocal8Bit(qgetenv("CROSS_COMPILE"));
    const QString compilerFilePath = findExecutable(crossCompilePrefix + compilerName);
    if (!QFileInfo(compilerFilePath).exists()) {
        qStderr << Tr::tr("%1 not found.").arg(compilerName) << endl;
        return;
    }
    const QString profileName = QFileInfo(compilerFilePath).completeBaseName();
    const QStringList toolchainTypes = toolchainTypeFromCompilerName(compilerName);
    profiles << createGccProfile(compilerFilePath, settings, toolchainTypes, profileName);
}

static void mingwProbe(Settings *settings, QList<Profile> &profiles)
{
    const QString gccPath
            = findExecutable(HostOsInfo::appendExecutableSuffix(QLatin1String("gcc")));
    if (!gccPath.isEmpty())
        profiles << createMingwProfile(gccPath, settings);
}

void probe(Settings *settings)
{
    QList<Profile> profiles;
    if (HostOsInfo::isWindowsHost()) {
        msvcProbe(settings, profiles);
        mingwProbe(settings, profiles);
    } else if (HostOsInfo::isOsxHost()) {
        xcodeProbe(settings, profiles);
        gccProbe(settings, profiles, QLatin1String("gcc"));
        gccProbe(settings, profiles, QLatin1String("clang"));
    } else {
        gccProbe(settings, profiles, QLatin1String("gcc"));
        gccProbe(settings, profiles, QLatin1String("clang"));
    }

    if (profiles.isEmpty()) {
        qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << endl;
    } else if (profiles.count() == 1 && settings->defaultProfile().isEmpty()) {
        const QString profileName = profiles.first().name();
        qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << endl;
        settings->setValue(QLatin1String("defaultProfile"), profileName);
    }
}

void createProfile(const QString &profileName, const QString &toolchainType,
                   const QString &compilerFilePath, Settings *settings)
{
    QStringList toolchainTypes;
    if (toolchainType.isEmpty())
        toolchainTypes = toolchainTypeFromCompilerName(QFileInfo(compilerFilePath).fileName());
    else
        toolchainTypes = completeToolchainList(toolchainType);

    if (toolchainTypes.contains(QLatin1String("msvc"))) {
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: MSVC toolchains can only be created "
                                    "via the auto-detection mechanism."));
    }

    if (toolchainTypes.contains(QLatin1String("mingw")))
        createMingwProfile(compilerFilePath, settings, profileName);
    else if (toolchainTypes.contains(QLatin1String("gcc")))
        createGccProfile(compilerFilePath, settings, toolchainTypes, profileName);
    else
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type."));
}
<commit_msg>Detect MinGW on all platforms.<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "probe.h"

#include "msvcprobe.h"
#include "xcodeprobe.h"

#include <logging/translator.h>
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/profile.h>
#include <tools/settings.h>

#include <QDir>
#include <QFileInfo>
#include <QProcess>
#include <QStringList>
#include <QTextStream>

#include <cstdio>

using namespace qbs;
using Internal::HostOsInfo;
using Internal::Tr;

static QTextStream qStdout(stdout);
static QTextStream qStderr(stderr);

static QString findExecutable(const QString &fileName)
{
    const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
    foreach (const QString &ppath, path.split(HostOsInfo::pathListSeparator())) {
        const QString fullPath = ppath + QLatin1Char('/') + fileName;
        if (QFileInfo(fullPath).exists())
            return QDir::cleanPath(fullPath);
    }
    return QString();
}

static QString qsystem(const QString &exe, const QStringList &args = QStringList())
{
    QProcess p;
    p.setProcessChannelMode(QProcess::MergedChannels);
    p.start(exe, args);
    if (!p.waitForStarted()) {
        throw qbs::ErrorInfo(Tr::tr("Failed to start compiler '%1': %2")
                             .arg(exe, p.errorString()));
    }
    if (!p.waitForFinished() || p.exitCode() != 0)
        throw qbs::ErrorInfo(Tr::tr("Failed to run compiler '%1': %2").arg(exe, p.errorString()));
    return QString::fromLocal8Bit(p.readAll());
}

static QStringList validMinGWMachines()
{
    // List of MinGW machine names (gcc -dumpmachine) recognized by Qbs
    return QStringList()
            << QLatin1String("mingw32") << QLatin1String("mingw64")
            << QLatin1String("i686-w64-mingw32") << QLatin1String("x86_64-w64-mingw32")
            << QLatin1String("i586-mingw32msvc") << QLatin1String("amd64-mingw32msvc");
}

static QStringList completeToolchainList(const QString &toolchainName)
{
    QStringList toolchains(toolchainName);
    if (toolchainName == QLatin1String("clang"))
        toolchains << QLatin1String("llvm") << QLatin1String("gcc");
    else if (toolchainName == QLatin1String("mingw"))
        toolchains << QLatin1String("gcc");
    return toolchains;
}

static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
{
    if (compilerName.contains(QLatin1String("clang")))
        return completeToolchainList(QLatin1String("clang"));
    if (compilerName.contains(QLatin1String("llvm")))
        return QStringList() << QLatin1String("llvm") << QLatin1String("gcc");
    if (compilerName.contains(QLatin1String("gcc")))
        return QStringList() << QLatin1String("gcc");
    if (compilerName == QLatin1String("cl.exe"))
        return QStringList() << QLatin1String("msvc");
    return QStringList();
}

static QString actualCompilerFilePath(const QString &compilerFilePath)
{
    const QFileInfo cfi(compilerFilePath);
    QString compilerFileName = cfi.fileName();

    // People usually want to compile C++. Since we currently link via
    // the compiler executable, using the plain C compiler will likely lead to linking problems.
    compilerFileName.replace(QLatin1String("gcc"), QLatin1String("g++"));
    compilerFileName.replace(QLatin1String("clang"), QLatin1String("clang++"));
    return cfi.absolutePath() + QLatin1Char('/') + compilerFileName;
}

static QString gccMachineName(const QString &compilerFilePath)
{
    return qsystem(compilerFilePath, QStringList() << QLatin1String("-dumpmachine")).trimmed();
}

static void setCommonProperties(Profile &profile, const QString &compilerFilePath,
                                const QStringList &toolchainTypes, const QString &architecture)
{
    QFileInfo cfi(compilerFilePath);
    profile.setValue(QLatin1String("cpp.toolchainInstallPath"), cfi.absolutePath());
    profile.setValue(QLatin1String("cpp.compilerName"), cfi.fileName());
    profile.setValue(QLatin1String("qbs.toolchain"), toolchainTypes);
    profile.setValue(QLatin1String("qbs.architecture"),
                     HostOsInfo::canonicalArchitecture(architecture));
    profile.setValue(QLatin1String("qbs.endianness"),
                     HostOsInfo::defaultEndianness(architecture));
}

static Profile createMingwProfile(const QString &_compilerFilePath, Settings *settings,
        const QString &profileName = QString())
{
    const QString compilerFilePath = actualCompilerFilePath(_compilerFilePath);
    const QString machineName = gccMachineName(compilerFilePath);
    const QStringList compilerTriplet = machineName.split(QLatin1Char('-'));
    if (!validMinGWMachines().contains(machineName)) {
        throw qbs::ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.")
                .arg(machineName));
    }
    Profile profile(!profileName.isEmpty() ? profileName : machineName, settings);
    profile.removeProfile();
    profile.setValue(QLatin1String("qbs.targetOS"), QStringList(QLatin1String("windows")));
    setCommonProperties(profile, compilerFilePath, completeToolchainList(QLatin1String("mingw")),
                        compilerTriplet.first());
    qStdout << Tr::tr("Profile '%1' created for '%2'.").arg(profile.name(), compilerFilePath)
            << endl;
    return profile;
}

static Profile createGccProfile(const QString &_compilerFilePath, Settings *settings,
                                const QStringList &toolchainTypes, const QString &profileName)
{
    const QString compilerFilePath = actualCompilerFilePath(_compilerFilePath);
    const QString machineName = gccMachineName(compilerFilePath);
    const QStringList compilerTriplet = machineName.split(QLatin1Char('-'));
    if (compilerTriplet.count() < 2) {
        throw qbs::ErrorInfo(Tr::tr("Architecture '%1' of compiler at '%1' not understood.")
                             .arg(compilerFilePath, machineName));
    }
    Profile profile(profileName, settings);
    setCommonProperties(profile, compilerFilePath, toolchainTypes, compilerTriplet.first());
    const QString compilerName = QFileInfo(compilerFilePath).fileName();
    if (compilerName.contains(QLatin1Char('-'))) {
        QStringList nameParts = compilerName.split(QLatin1Char('-'));
        profile.setValue(QLatin1String("cpp.compilerName"), nameParts.takeLast());
        profile.setValue(QLatin1String("cpp.toolchainPrefix"),
                         nameParts.join(QLatin1String("-")) + QLatin1Char('-'));
    }
    qStdout << Tr::tr("Profile '%1' created for '%2'.").arg(profile.name(), compilerFilePath)
            << endl;
    return profile;
}

static void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compilerName)
{
    qStdout << Tr::tr("Trying to detect %1...").arg(compilerName) << endl;

    const QString crossCompilePrefix = QString::fromLocal8Bit(qgetenv("CROSS_COMPILE"));
    const QString compilerFilePath = findExecutable(crossCompilePrefix + compilerName);
    if (!QFileInfo(compilerFilePath).exists()) {
        qStderr << Tr::tr("%1 not found.").arg(compilerName) << endl;
        return;
    }
    const QString profileName = QFileInfo(compilerFilePath).completeBaseName();
    const QStringList toolchainTypes = toolchainTypeFromCompilerName(compilerName);
    profiles << createGccProfile(compilerFilePath, settings, toolchainTypes, profileName);
}

static void mingwProbe(Settings *settings, QList<Profile> &profiles)
{
    // List of possible compiler binary names for this platform
    QStringList compilerNames;
    if (HostOsInfo::isWindowsHost()) {
        compilerNames << QLatin1String("gcc");
    } else {
        foreach (const QString &machineName, validMinGWMachines()) {
            compilerNames << machineName + QLatin1String("-gcc");
        }
    }

    foreach (const QString &compilerName, compilerNames) {
        const QString gccPath
                = findExecutable(HostOsInfo::appendExecutableSuffix(compilerName));
        if (!gccPath.isEmpty())
            profiles << createMingwProfile(gccPath, settings);
    }
}

void probe(Settings *settings)
{
    QList<Profile> profiles;
    if (HostOsInfo::isWindowsHost()) {
        msvcProbe(settings, profiles);
    } else {
        gccProbe(settings, profiles, QLatin1String("gcc"));
        gccProbe(settings, profiles, QLatin1String("clang"));

        if (HostOsInfo::isOsxHost()) {
            xcodeProbe(settings, profiles);
        }
    }

    mingwProbe(settings, profiles);

    if (profiles.isEmpty()) {
        qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << endl;
    } else if (profiles.count() == 1 && settings->defaultProfile().isEmpty()) {
        const QString profileName = profiles.first().name();
        qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << endl;
        settings->setValue(QLatin1String("defaultProfile"), profileName);
    }
}

void createProfile(const QString &profileName, const QString &toolchainType,
                   const QString &compilerFilePath, Settings *settings)
{
    QStringList toolchainTypes;
    if (toolchainType.isEmpty())
        toolchainTypes = toolchainTypeFromCompilerName(QFileInfo(compilerFilePath).fileName());
    else
        toolchainTypes = completeToolchainList(toolchainType);

    if (toolchainTypes.contains(QLatin1String("msvc"))) {
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: MSVC toolchains can only be created "
                                    "via the auto-detection mechanism."));
    }

    if (toolchainTypes.contains(QLatin1String("mingw")))
        createMingwProfile(compilerFilePath, settings, profileName);
    else if (toolchainTypes.contains(QLatin1String("gcc")))
        createGccProfile(compilerFilePath, settings, toolchainTypes, profileName);
    else
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type."));
}
<|endoftext|>