<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///\file RenderTestFem3DCorotational.cpp render test for Fem3D with corotational elements

#include <memory>

#include "SurgSim/Blocks/TransferPhysicsToPointCloudBehavior.h"
#include "SurgSim/Framework/BasicSceneElement.h"
#include "SurgSim/Graphics/OsgPointCloudRepresentation.h"
#include "SurgSim/Math/OdeState.h"
#include "SurgSim/Math/Quaternion.h"
#include "SurgSim/Math/RigidTransform.h"
#include "SurgSim/Math/Vector.h"
#include "SurgSim/Physics/Fem3DRepresentation.h"
#include "SurgSim/Physics/Fem3DElementCorotationalTetrahedron.h"
#include "SurgSim/Physics/RenderTests/RenderTest.h"

using SurgSim::Blocks::TransferPhysicsToPointCloudBehavior;
using SurgSim::Framework::BasicSceneElement;
using SurgSim::Graphics::OsgPointCloudRepresentation;
using SurgSim::Physics::Fem3DRepresentation;
using SurgSim::Physics::FemElement;
using SurgSim::Physics::Fem3DElementCorotationalTetrahedron;
using SurgSim::Math::Vector3d;

namespace
{

std::shared_ptr<SurgSim::Framework::SceneElement> createTetrahedronFem3D(const std::string& name,
		const SurgSim::Math::RigidTransform3d& pose, SurgSim::Math::Vector4d color,
		SurgSim::Math::IntegrationScheme integrationScheme)
{
	// Physics Representation
	std::shared_ptr<Fem3DRepresentation> physicsRepresentation;
	physicsRepresentation = std::make_shared<Fem3DRepresentation>(name + " Physics");
	physicsRepresentation->setIntegrationScheme(integrationScheme);
	physicsRepresentation->setRayleighDampingMass(1e-2);
	physicsRepresentation->setRayleighDampingStiffness(1e-3);

	std::array<Vector3d, 8> vertices = {{
			Vector3d(-0.5, -0.5, -0.5),
			Vector3d(0.5, -0.5, -0.5),
			Vector3d(-0.5,  0.5, -0.5),
			Vector3d(0.5,  0.5, -0.5),
			Vector3d(-0.5, -0.5,  0.5),
			Vector3d(0.5, -0.5,  0.5),
			Vector3d(-0.5,  0.5,  0.5),
			Vector3d(0.5,  0.5,  0.5)
		}
	};

	// Cube decomposition into 5 tetrahedrons
	// https://www.math.ucdavis.edu/~deloera/CURRENT_INTERESTS/cube.html
	std::array< std::array<size_t, 4>, 5> tetrahedrons = {{
			{{4, 7, 1, 2}}, // CCW (47)cross(41) . (42) > 0
			{{4, 1, 7, 5}}, // CCW (41)cross(47) . (45) > 0
			{{4, 2, 1, 0}}, // CCW (42)cross(41) . (40) > 0
			{{4, 7, 2, 6}}, // CCW (47)cross(42) . (46) > 0
			{{1, 2, 7, 3}}  // CCW (12)cross(17) . (13) > 0
		}
	};

	std::array<size_t, 2> boundaryConditionsNodeIdx = {{0, 1}};

	std::shared_ptr<SurgSim::Math::OdeState> initialState = std::make_shared<SurgSim::Math::OdeState>();
	initialState->setNumDof(physicsRepresentation->getNumDofPerNode(), 8);

	for (size_t i = 0; i != vertices.size(); i++)
	{
		initialState->getPositions().segment(i * 3, 3) = vertices[i];
	}

	for (auto index = boundaryConditionsNodeIdx.cbegin(); index != boundaryConditionsNodeIdx.cend(); ++index)
	{
		initialState->addBoundaryCondition(*index);
	}
	physicsRepresentation->setInitialState(initialState);

	for (auto tetrahedron = tetrahedrons.cbegin(); tetrahedron != tetrahedrons.cend(); ++tetrahedron)
	{
		std::shared_ptr<FemElement> element = std::make_shared<Fem3DElementCorotationalTetrahedron>(*tetrahedron);
		element->setMassDensity(8000.0);
		element->setPoissonRatio(0.45);
		element->setYoungModulus(1.0e6);
		physicsRepresentation->addFemElement(element);
	}

	// Graphics Representation
	std::shared_ptr<OsgPointCloudRepresentation> graphicsRepresentation;
	graphicsRepresentation = std::make_shared<OsgPointCloudRepresentation>(name + " Graphics object ");
	graphicsRepresentation->setLocalPose(pose);
	graphicsRepresentation->setColor(color);
	graphicsRepresentation->setPointSize(3.0f);
	graphicsRepresentation->setLocalActive(true);

	// Scene Element
	std::shared_ptr<BasicSceneElement> femSceneElement = std::make_shared<BasicSceneElement>(name);
	femSceneElement->addComponent(physicsRepresentation);
	femSceneElement->addComponent(graphicsRepresentation);

	auto physicsToGraphics =
		std::make_shared<TransferPhysicsToPointCloudBehavior>("Physics to Graphics deformable points");
	physicsToGraphics->setSource(physicsRepresentation);
	physicsToGraphics->setTarget(graphicsRepresentation);
	femSceneElement->addComponent(physicsToGraphics);

	return femSceneElement;
}

}; // anonymous namespace

namespace SurgSim
{

namespace Physics
{

TEST_F(RenderTests, VisualTestFem3DCorotatioal)
{
	using SurgSim::Math::makeRigidTranslation;

	// Cube with corotational tetrahedron FemElement
	scene->addSceneElement(createTetrahedronFem3D("CorotationalTetrahedronElement Euler Explicit",
						   makeRigidTranslation(Vector3d(-4.0, 1.0, -1.0)),
						   SurgSim::Math::Vector4d(1, 0, 0, 1),
						   SurgSim::Math::INTEGRATIONSCHEME_EXPLICIT_EULER));

	scene->addSceneElement(createTetrahedronFem3D("CorotatinoalTetrahedronElement Modified Euler Explicit",
						   makeRigidTranslation(Vector3d(-2.0, 1.0, -1.0)),
						   SurgSim::Math::Vector4d(0.5, 0, 0, 1),
						   SurgSim::Math::INTEGRATIONSCHEME_MODIFIED_EXPLICIT_EULER));

	scene->addSceneElement(createTetrahedronFem3D("CorotatinoalTetrahedronElement Runge Kutta 4",
						   makeRigidTranslation(Vector3d(0.0, 1.0, -1.0)),
						   SurgSim::Math::Vector4d(0, 1, 0, 1),
						   SurgSim::Math::INTEGRATIONSCHEME_RUNGE_KUTTA_4));

	scene->addSceneElement(createTetrahedronFem3D("CorotatinoalTetrahedronElement Fem 3D Euler Implicit",
						   makeRigidTranslation(Vector3d(2.0, 1.0, -1.0)),
						   SurgSim::Math::Vector4d(0, 0, 1, 1),
						   SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER));

	scene->addSceneElement(createTetrahedronFem3D("CorotatinoalTetrahedronElement Fem 3D Static",
						   makeRigidTranslation(Vector3d(4.0, 1.0, -1.0)),
						   SurgSim::Math::Vector4d(1, 1, 1, 1),
						   SurgSim::Math::INTEGRATIONSCHEME_STATIC));

	runTest(Vector3d(0.0, 0.0, 7.0), Vector3d::Zero(), 5000.0);
}

}; // namespace Physics

}; // namespace SurgSim
<commit_msg>Fix typo in UnitTest name<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///\file RenderTestFem3DCorotational.cpp render test for Fem3D with corotational elements

#include <memory>

#include "SurgSim/Blocks/TransferPhysicsToPointCloudBehavior.h"
#include "SurgSim/Framework/BasicSceneElement.h"
#include "SurgSim/Graphics/OsgPointCloudRepresentation.h"
#include "SurgSim/Math/OdeState.h"
#include "SurgSim/Math/Quaternion.h"
#include "SurgSim/Math/RigidTransform.h"
#include "SurgSim/Math/Vector.h"
#include "SurgSim/Physics/Fem3DRepresentation.h"
#include "SurgSim/Physics/Fem3DElementCorotationalTetrahedron.h"
#include "SurgSim/Physics/RenderTests/RenderTest.h"

using SurgSim::Blocks::TransferPhysicsToPointCloudBehavior;
using SurgSim::Framework::BasicSceneElement;
using SurgSim::Graphics::OsgPointCloudRepresentation;
using SurgSim::Physics::Fem3DRepresentation;
using SurgSim::Physics::FemElement;
using SurgSim::Physics::Fem3DElementCorotationalTetrahedron;
using SurgSim::Math::Vector3d;

namespace
{

std::shared_ptr<SurgSim::Framework::SceneElement> createTetrahedronFem3D(const std::string& name,
		const SurgSim::Math::RigidTransform3d& pose, SurgSim::Math::Vector4d color,
		SurgSim::Math::IntegrationScheme integrationScheme)
{
	// Physics Representation
	std::shared_ptr<Fem3DRepresentation> physicsRepresentation;
	physicsRepresentation = std::make_shared<Fem3DRepresentation>(name + " Physics");
	physicsRepresentation->setIntegrationScheme(integrationScheme);
	physicsRepresentation->setRayleighDampingMass(1e-2);
	physicsRepresentation->setRayleighDampingStiffness(1e-3);

	std::array<Vector3d, 8> vertices = {{
			Vector3d(-0.5, -0.5, -0.5),
			Vector3d(0.5, -0.5, -0.5),
			Vector3d(-0.5,  0.5, -0.5),
			Vector3d(0.5,  0.5, -0.5),
			Vector3d(-0.5, -0.5,  0.5),
			Vector3d(0.5, -0.5,  0.5),
			Vector3d(-0.5,  0.5,  0.5),
			Vector3d(0.5,  0.5,  0.5)
		}
	};

	// Cube decomposition into 5 tetrahedrons
	// https://www.math.ucdavis.edu/~deloera/CURRENT_INTERESTS/cube.html
	std::array< std::array<size_t, 4>, 5> tetrahedrons = {{
			{{4, 7, 1, 2}}, // CCW (47)cross(41) . (42) > 0
			{{4, 1, 7, 5}}, // CCW (41)cross(47) . (45) > 0
			{{4, 2, 1, 0}}, // CCW (42)cross(41) . (40) > 0
			{{4, 7, 2, 6}}, // CCW (47)cross(42) . (46) > 0
			{{1, 2, 7, 3}}  // CCW (12)cross(17) . (13) > 0
		}
	};

	std::array<size_t, 2> boundaryConditionsNodeIdx = {{0, 1}};

	std::shared_ptr<SurgSim::Math::OdeState> initialState = std::make_shared<SurgSim::Math::OdeState>();
	initialState->setNumDof(physicsRepresentation->getNumDofPerNode(), 8);

	for (size_t i = 0; i != vertices.size(); i++)
	{
		initialState->getPositions().segment(i * 3, 3) = vertices[i];
	}

	for (auto index = boundaryConditionsNodeIdx.cbegin(); index != boundaryConditionsNodeIdx.cend(); ++index)
	{
		initialState->addBoundaryCondition(*index);
	}
	physicsRepresentation->setInitialState(initialState);

	for (auto tetrahedron = tetrahedrons.cbegin(); tetrahedron != tetrahedrons.cend(); ++tetrahedron)
	{
		std::shared_ptr<FemElement> element = std::make_shared<Fem3DElementCorotationalTetrahedron>(*tetrahedron);
		element->setMassDensity(8000.0);
		element->setPoissonRatio(0.45);
		element->setYoungModulus(1.0e6);
		physicsRepresentation->addFemElement(element);
	}

	// Graphics Representation
	std::shared_ptr<OsgPointCloudRepresentation> graphicsRepresentation;
	graphicsRepresentation = std::make_shared<OsgPointCloudRepresentation>(name + " Graphics object ");
	graphicsRepresentation->setLocalPose(pose);
	graphicsRepresentation->setColor(color);
	graphicsRepresentation->setPointSize(3.0f);
	graphicsRepresentation->setLocalActive(true);

	// Scene Element
	std::shared_ptr<BasicSceneElement> femSceneElement = std::make_shared<BasicSceneElement>(name);
	femSceneElement->addComponent(physicsRepresentation);
	femSceneElement->addComponent(graphicsRepresentation);

	auto physicsToGraphics =
		std::make_shared<TransferPhysicsToPointCloudBehavior>("Physics to Graphics deformable points");
	physicsToGraphics->setSource(physicsRepresentation);
	physicsToGraphics->setTarget(graphicsRepresentation);
	femSceneElement->addComponent(physicsToGraphics);

	return femSceneElement;
}

}; // anonymous namespace

namespace SurgSim
{

namespace Physics
{

TEST_F(RenderTests, VisualTestFem3DCorotational)
{
	using SurgSim::Math::makeRigidTranslation;

	// Cube with corotational tetrahedron FemElement
	scene->addSceneElement(createTetrahedronFem3D("CorotationalTetrahedronElement Euler Explicit",
						   makeRigidTranslation(Vector3d(-4.0, 1.0, -1.0)),
						   SurgSim::Math::Vector4d(1, 0, 0, 1),
						   SurgSim::Math::INTEGRATIONSCHEME_EXPLICIT_EULER));

	scene->addSceneElement(createTetrahedronFem3D("CorotatinoalTetrahedronElement Modified Euler Explicit",
						   makeRigidTranslation(Vector3d(-2.0, 1.0, -1.0)),
						   SurgSim::Math::Vector4d(0.5, 0, 0, 1),
						   SurgSim::Math::INTEGRATIONSCHEME_MODIFIED_EXPLICIT_EULER));

	scene->addSceneElement(createTetrahedronFem3D("CorotatinoalTetrahedronElement Runge Kutta 4",
						   makeRigidTranslation(Vector3d(0.0, 1.0, -1.0)),
						   SurgSim::Math::Vector4d(0, 1, 0, 1),
						   SurgSim::Math::INTEGRATIONSCHEME_RUNGE_KUTTA_4));

	scene->addSceneElement(createTetrahedronFem3D("CorotatinoalTetrahedronElement Fem 3D Euler Implicit",
						   makeRigidTranslation(Vector3d(2.0, 1.0, -1.0)),
						   SurgSim::Math::Vector4d(0, 0, 1, 1),
						   SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER));

	scene->addSceneElement(createTetrahedronFem3D("CorotatinoalTetrahedronElement Fem 3D Static",
						   makeRigidTranslation(Vector3d(4.0, 1.0, -1.0)),
						   SurgSim::Math::Vector4d(1, 1, 1, 1),
						   SurgSim::Math::INTEGRATIONSCHEME_STATIC));

	runTest(Vector3d(0.0, 0.0, 7.0), Vector3d::Zero(), 5000.0);
}

}; // namespace Physics

}; // namespace SurgSim
<|endoftext|>


<commit_before>/*
 *  This file is part of Poedit (https://poedit.net)
 *
 *  Copyright (C) 2013-2019 Vaclav Slavik
 *
 *  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 "languagectrl.h"

#include "str_helpers.h"
#include "hidpi.h"

#include <wx/config.h>
#include <wx/sizer.h>
#include <wx/stattext.h>

#ifdef __WXOSX__

@interface LanguagesDataSource : NSObject<NSComboBoxDataSource>
@property const wxArrayString *data;
@property NSArray<NSString*>* items;
@end

@implementation LanguagesDataSource

- (id)initWithItems:(const wxArrayString*)items
{
    self = [super init];
    if (self)
    {
        self.data = items;
        NSMutableArray<NSString*> *a = [NSMutableArray arrayWithCapacity:items->size()];
        for (auto i: *items)
            [a addObject:str::to_NS(i)];
        self.items = a;
    }
    return self;
}

- (NSInteger)numberOfItemsInComboBox:(NSComboBox *)aComboBox;
{
    #pragma unused(aComboBox)
    return [self.items count];
}

- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(NSInteger)index;
{
    #pragma unused(aComboBox)
    if (index >=0 && index < self.data->size())
        return [self.items objectAtIndex:index];
    else
        return @"";
}

- (NSUInteger)comboBox:(NSComboBox *)aComboBox indexOfItemWithStringValue:(NSString *)string;
{
    #pragma unused(aComboBox)
    auto found = self.data->Index(str::to_wx(string), false/*case sensitive*/);
    return (found != wxNOT_FOUND) ? found : NSNotFound;
}

- (NSString *)comboBox:(NSComboBox *)aComboBox completedString:(NSString *)string;
{
    #pragma unused(aComboBox)
    for (NSString *item in self.items) {
        if ([item compare:string
                  options:NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch
                    range:NSMakeRange(0, std::min([item length], [string length]))
                   locale:[NSLocale currentLocale]] == NSOrderedSame)
        {
            return item;
        }
    }
    return nil;
}

@end

struct LanguageCtrl::impl
{
    impl(const wxArrayString& items_)
    {
        items = &items_;
        dataSource = [[LanguagesDataSource alloc] initWithItems:items];
    }

    const wxArrayString *items;
    LanguagesDataSource *dataSource;
};

int LanguageCtrl::FindString(const wxString& s, bool bCase) const
{
    return m_impl->items->Index(s, bCase);
}

wxString LanguageCtrl::GetString(unsigned int n) const
{
    return m_impl->items->Item(n);
}

#endif // __WXOSX__

IMPLEMENT_DYNAMIC_CLASS(LanguageCtrl, wxComboBox)

LanguageCtrl::LanguageCtrl() : m_inited(false)
{
}

LanguageCtrl::LanguageCtrl(wxWindow *parent, wxWindowID winid, Language lang)
    : wxComboBox(parent, winid)
{
    Init(lang);
}

void LanguageCtrl::Init(Language lang)
{
    SetHint(_("Language Code or Name (e.g. en_GB)"));

    // wxGTK must have the value set before autocompletion to avoid annoying
    // popups in some (hard to determine) cases.
#ifdef __WXGTK__
    if (lang.IsValid())
        SetValue(lang.FormatForRoundtrip());
#endif

    static wxArrayString choices;
    if (choices.empty())
    {
        for (auto x: Language::AllFormattedNames())
            choices.push_back(x);
    }

#ifdef __WXOSX__
    m_impl.reset(new impl(choices));
    NSComboBox *cb = (NSComboBox*) GetHandle();
    cb.completes = YES;
    cb.usesDataSource = YES;
    cb.dataSource = m_impl->dataSource;
#else
    Set(choices);
    AutoComplete(choices);
#endif

    m_inited = true;

    // ...but wxMSW requires the opposite, otherwise the text wouldn't appear.
#ifndef __WXGTK__
    if (lang.IsValid())
        SetValue(lang.FormatForRoundtrip());
#endif
}

void LanguageCtrl::SetLang(const Language& lang)
{
    if (!m_inited)
        Init(lang);
    else
        SetValue(lang.FormatForRoundtrip());
}

Language LanguageCtrl::GetLang() const
{
    return Language::TryParse(GetValue().Strip(wxString::both).ToStdWstring());
}

#ifdef __WXMSW__
wxSize LanguageCtrl::DoGetBestSize() const
{
    // wxComboBox's implementation is insanely slow, at least on MSW.
    // Hardcode a value instead, it doesn't matter for Poedit's use anyway,
    // this control's best size is not the determining factor.
    return GetSizeFromTextSize(100);
}
#endif

LanguageDialog::LanguageDialog(wxWindow *parent)
    : wxDialog(parent, wxID_ANY, _("Translation Language")),
      m_validatedLang(-1)
{
    auto lang = GetLastChosen();

    auto sizer = new wxBoxSizer(wxVERTICAL);

    auto label = new wxStaticText(this, wxID_ANY, _("Language of the translation:"));
    m_language = new LanguageCtrl(this, wxID_ANY, lang);
    m_language->SetMinSize(wxSize(PX(300),-1));
    auto buttons = CreateButtonSizer(wxOK | wxCANCEL);

#ifdef __WXOSX__
    sizer->AddSpacer(PX(10));
    sizer->Add(label, wxSizerFlags().PXBorderAll());
    sizer->Add(m_language, wxSizerFlags().Expand().PXDoubleBorder(wxLEFT|wxRIGHT));
    sizer->Add(buttons, wxSizerFlags().Expand());
#else
    sizer->AddSpacer(PX(10));
    sizer->Add(label, wxSizerFlags().PXDoubleBorder(wxLEFT|wxRIGHT));
    sizer->Add(m_language, wxSizerFlags().Expand().PXDoubleBorder(wxLEFT|wxRIGHT));
    sizer->Add(buttons, wxSizerFlags().Expand().PXBorderAll());
#endif

    m_language->Bind(wxEVT_TEXT,     [=](wxCommandEvent& e){ m_validatedLang = -1; e.Skip(); });
    m_language->Bind(wxEVT_COMBOBOX, [=](wxCommandEvent& e){ m_validatedLang = -1; e.Skip(); });

    Bind(wxEVT_UPDATE_UI,
        [=](wxUpdateUIEvent& e){ e.Enable(Validate()); },
        wxID_OK);

    SetSizerAndFit(sizer);
    CenterOnParent();

    m_language->SetFocus();

#ifdef __WXOSX__
    // Workaround wx bug: http://trac.wxwidgets.org/ticket/9521
    m_language->SelectAll();

    // Workaround broken Enter handling:
    Bind(wxEVT_CHAR_HOOK, [=](wxKeyEvent& e){
        if (e.GetKeyCode() == WXK_RETURN)
        {
            auto button = GetDefaultItem();
            wxCommandEvent event(wxEVT_BUTTON, button->GetId());
            event.SetEventObject(button);
            button->ProcessWindowEvent(event);
        }
        else
        {
            e.Skip();
        }
    });
#endif // __WXOSX__
}

bool LanguageDialog::Validate()
{
    if (m_validatedLang == -1)
    {
        m_validatedLang = m_language->IsValid() ? 1 : 0;
    }

    return m_validatedLang == 1;
}

void LanguageDialog::EndModal(int retval)
{
    if (retval == wxID_OK)
    {
        SetLastChosen(GetLang());
    }
    wxDialog::EndModal(retval);
}

void LanguageDialog::SetLang(const Language& lang)
{
    m_validatedLang = -1;
    m_language->SetLang(lang);
}

Language LanguageDialog::GetLastChosen()
{
    wxString langcode = wxConfigBase::Get()->Read("/last_translation_lang", "");
    Language lang;
    if (!langcode.empty())
        lang = Language::TryParse(langcode.ToStdWstring());
    return lang;
}

void LanguageDialog::SetLastChosen(Language lang)
{
    wxConfigBase::Get()->Write("/last_translation_lang", lang.Code().c_str());
}

<commit_msg>Fix language control not having initial value w/ GTK+<commit_after>/*
 *  This file is part of Poedit (https://poedit.net)
 *
 *  Copyright (C) 2013-2019 Vaclav Slavik
 *
 *  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 "languagectrl.h"

#include "str_helpers.h"
#include "hidpi.h"

#include <wx/config.h>
#include <wx/sizer.h>
#include <wx/stattext.h>

#ifdef __WXOSX__

@interface LanguagesDataSource : NSObject<NSComboBoxDataSource>
@property const wxArrayString *data;
@property NSArray<NSString*>* items;
@end

@implementation LanguagesDataSource

- (id)initWithItems:(const wxArrayString*)items
{
    self = [super init];
    if (self)
    {
        self.data = items;
        NSMutableArray<NSString*> *a = [NSMutableArray arrayWithCapacity:items->size()];
        for (auto i: *items)
            [a addObject:str::to_NS(i)];
        self.items = a;
    }
    return self;
}

- (NSInteger)numberOfItemsInComboBox:(NSComboBox *)aComboBox;
{
    #pragma unused(aComboBox)
    return [self.items count];
}

- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(NSInteger)index;
{
    #pragma unused(aComboBox)
    if (index >=0 && index < self.data->size())
        return [self.items objectAtIndex:index];
    else
        return @"";
}

- (NSUInteger)comboBox:(NSComboBox *)aComboBox indexOfItemWithStringValue:(NSString *)string;
{
    #pragma unused(aComboBox)
    auto found = self.data->Index(str::to_wx(string), false/*case sensitive*/);
    return (found != wxNOT_FOUND) ? found : NSNotFound;
}

- (NSString *)comboBox:(NSComboBox *)aComboBox completedString:(NSString *)string;
{
    #pragma unused(aComboBox)
    for (NSString *item in self.items) {
        if ([item compare:string
                  options:NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch
                    range:NSMakeRange(0, std::min([item length], [string length]))
                   locale:[NSLocale currentLocale]] == NSOrderedSame)
        {
            return item;
        }
    }
    return nil;
}

@end

struct LanguageCtrl::impl
{
    impl(const wxArrayString& items_)
    {
        items = &items_;
        dataSource = [[LanguagesDataSource alloc] initWithItems:items];
    }

    const wxArrayString *items;
    LanguagesDataSource *dataSource;
};

int LanguageCtrl::FindString(const wxString& s, bool bCase) const
{
    return m_impl->items->Index(s, bCase);
}

wxString LanguageCtrl::GetString(unsigned int n) const
{
    return m_impl->items->Item(n);
}

#endif // __WXOSX__

IMPLEMENT_DYNAMIC_CLASS(LanguageCtrl, wxComboBox)

LanguageCtrl::LanguageCtrl() : m_inited(false)
{
}

LanguageCtrl::LanguageCtrl(wxWindow *parent, wxWindowID winid, Language lang)
    : wxComboBox(parent, winid)
{
    Init(lang);
}

void LanguageCtrl::Init(Language lang)
{
    SetHint(_("Language Code or Name (e.g. en_GB)"));

    // wxGTK must have the value set before autocompletion (but also after it
    // below) to avoid annoying popups in some (hard to determine) cases.
#ifdef __WXGTK__
    if (lang.IsValid())
        SetValue(lang.FormatForRoundtrip());
#endif

    static wxArrayString choices;
    if (choices.empty())
    {
        for (auto x: Language::AllFormattedNames())
            choices.push_back(x);
    }

#ifdef __WXOSX__
    m_impl.reset(new impl(choices));
    NSComboBox *cb = (NSComboBox*) GetHandle();
    cb.completes = YES;
    cb.usesDataSource = YES;
    cb.dataSource = m_impl->dataSource;
#else
    Set(choices);
    AutoComplete(choices);
#endif

    m_inited = true;

    if (lang.IsValid())
        SetValue(lang.FormatForRoundtrip());
}

void LanguageCtrl::SetLang(const Language& lang)
{
    if (!m_inited)
        Init(lang);
    else
        SetValue(lang.FormatForRoundtrip());
}

Language LanguageCtrl::GetLang() const
{
    return Language::TryParse(GetValue().Strip(wxString::both).ToStdWstring());
}

#ifdef __WXMSW__
wxSize LanguageCtrl::DoGetBestSize() const
{
    // wxComboBox's implementation is insanely slow, at least on MSW.
    // Hardcode a value instead, it doesn't matter for Poedit's use anyway,
    // this control's best size is not the determining factor.
    return GetSizeFromTextSize(100);
}
#endif

LanguageDialog::LanguageDialog(wxWindow *parent)
    : wxDialog(parent, wxID_ANY, _("Translation Language")),
      m_validatedLang(-1)
{
    auto lang = GetLastChosen();

    auto sizer = new wxBoxSizer(wxVERTICAL);

    auto label = new wxStaticText(this, wxID_ANY, _("Language of the translation:"));
    m_language = new LanguageCtrl(this, wxID_ANY, lang);
    m_language->SetMinSize(wxSize(PX(300),-1));
    auto buttons = CreateButtonSizer(wxOK | wxCANCEL);

#ifdef __WXOSX__
    sizer->AddSpacer(PX(10));
    sizer->Add(label, wxSizerFlags().PXBorderAll());
    sizer->Add(m_language, wxSizerFlags().Expand().PXDoubleBorder(wxLEFT|wxRIGHT));
    sizer->Add(buttons, wxSizerFlags().Expand());
#else
    sizer->AddSpacer(PX(10));
    sizer->Add(label, wxSizerFlags().PXDoubleBorder(wxLEFT|wxRIGHT));
    sizer->Add(m_language, wxSizerFlags().Expand().PXDoubleBorder(wxLEFT|wxRIGHT));
    sizer->Add(buttons, wxSizerFlags().Expand().PXBorderAll());
#endif

    m_language->Bind(wxEVT_TEXT,     [=](wxCommandEvent& e){ m_validatedLang = -1; e.Skip(); });
    m_language->Bind(wxEVT_COMBOBOX, [=](wxCommandEvent& e){ m_validatedLang = -1; e.Skip(); });

    Bind(wxEVT_UPDATE_UI,
        [=](wxUpdateUIEvent& e){ e.Enable(Validate()); },
        wxID_OK);

    SetSizerAndFit(sizer);
    CenterOnParent();

    m_language->SetFocus();

#ifdef __WXOSX__
    // Workaround wx bug: http://trac.wxwidgets.org/ticket/9521
    m_language->SelectAll();

    // Workaround broken Enter handling:
    Bind(wxEVT_CHAR_HOOK, [=](wxKeyEvent& e){
        if (e.GetKeyCode() == WXK_RETURN)
        {
            auto button = GetDefaultItem();
            wxCommandEvent event(wxEVT_BUTTON, button->GetId());
            event.SetEventObject(button);
            button->ProcessWindowEvent(event);
        }
        else
        {
            e.Skip();
        }
    });
#endif // __WXOSX__
}

bool LanguageDialog::Validate()
{
    if (m_validatedLang == -1)
    {
        m_validatedLang = m_language->IsValid() ? 1 : 0;
    }

    return m_validatedLang == 1;
}

void LanguageDialog::EndModal(int retval)
{
    if (retval == wxID_OK)
    {
        SetLastChosen(GetLang());
    }
    wxDialog::EndModal(retval);
}

void LanguageDialog::SetLang(const Language& lang)
{
    m_validatedLang = -1;
    m_language->SetLang(lang);
}

Language LanguageDialog::GetLastChosen()
{
    wxString langcode = wxConfigBase::Get()->Read("/last_translation_lang", "");
    Language lang;
    if (!langcode.empty())
        lang = Language::TryParse(langcode.ToStdWstring());
    return lang;
}

void LanguageDialog::SetLastChosen(Language lang)
{
    wxConfigBase::Get()->Write("/last_translation_lang", lang.Code().c_str());
}

<|endoftext|>


<commit_before>/*
 * Author: Mihai T Panu <mihai.tudor.panu@intel.com>
 * Copyright (c) 2015 Intel Corporation.
 *
 * 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 <unistd.h>
#include <signal.h>
#include <iostream>
#include "grovemd.h"
#include "jhd1313m1.h"
#include "rfr359f.h"
#include "hmc5883l.h"
#include "grovevdiv.h"

using namespace std;
using namespace upm;

bool running = true;

// Handler for POSIX signals
void signalHandler(int signo)
{
  if (signo == SIGINT)
    running = false;
}

int main(int argc, char **argv)
{
  signal(SIGINT, signalHandler);
  // Instantiate an I2C Grove Motor Driver on default I2C bus
  GroveMD *motors = new GroveMD(GROVEMD_I2C_BUS, GROVEMD_DEFAULT_I2C_ADDR);

  // Main event loop
  while(running){

  }

  cout << "Exiting..." << endl;

  delete motors;
  return 0;
}
<commit_msg>robotics: added full implementation for demo<commit_after>/*
 * Author: Mihai T Panu <mihai.tudor.panu@intel.com>
 * Copyright (c) 2015 Intel Corporation.
 *
 * 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 <unistd.h>
#include <signal.h>
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include "grovemd.h"
#include "jhd1313m1.h"
#include "rfr359f.h"
#include "hmc5883l.h"
#include "grovevdiv.h"

using namespace std;
using namespace upm;

mutex crit;
bool running = true;

bool blockedFL = false;
bool blockedFR = false;
bool blockedRL = false;
bool blockedRR = false;

bool batteryLow = true;
const float batteryThreshold = 7.2f;

const string heading = "--|--N--|--|--E--|--|--S--|--|--W--|--|--N--|--";

// Handler for POSIX signals
void signalHandler(int signo)
{
  if (signo == SIGINT){
    running = false;
  }
}

// Heading display on LCD
void displayHeading(Jhd1313m1 *lcd, Hmc5883l *compass){

    // You can set your declination in radians for more accurate readings
    //compass->set_declination(0.2749);

    while(running){
        compass->update();

        // Round the heading returned by compass and turn it into an index
        // from 0 to 36 for the heading string
        int hdg = int(compass->heading() + 0.5f);
        int hdg_index = hdg / 10;

        // Write the heading on the first line, lcd->clear() is not needed since
        // we write the entire line
        crit.lock();
        lcd->setCursor(0, 0);
        lcd->write("HDG: " + heading.substr(hdg_index, 11));
        crit.unlock();

        // Update readings and display every 250 ms
        usleep(250000);
    }
}

// Battery level display on LCD
void displayBattery(Jhd1313m1 *lcd, GroveVDiv *divider){

    // Variable used for flashing LCD red when battery is low
    uint8_t red = 0x3F;

    while(running){
        // Read 50 samples each with 2 ms in between (100 ms total)
        int avgValue = divider->value(50);
        // Convert the value to voltage at 3x gain and 5V reference
        // Also subtract half a unit for improved accuracy in the 6~8V range
        float voltage = divider->computedValue(3, avgValue) - 0.5f;
        string displayStr = to_string(voltage);
        displayStr = displayStr.substr(0, 4);

        // Write the battery voltage on the second line of the display
        crit.lock();
        lcd->setCursor(1, 0);
        lcd->write("Batt: " + displayStr + " V    ");
        crit.unlock();

        // Battery low, flash LCD and refresh more often
        if(voltage < 7.2f)
        {
            batteryLow = true;
            lcd->setColor(red, 0x00, 0x00);
            // Toggle red bits
            red = ~red;
            sleep(2);
        }
        else{
            // Battery was considered low but new reading is above threshold
            // Thus return to normal operation mode and make the LCD green
            if(batteryLow){
                lcd->setColor(0x00, 0xCF, 0x00);
            }
            batteryLow = false;
            // Refresh every 5 seconds
            sleep(5);
        }
    }
}

// IR sensors thread
void distanceIR(GroveMD *motors, RFR359F *fl, RFR359F *fr, RFR359F *rl, RFR359F *rr){
    while(running){
        // Set the corresponding sensor variable when an object is detected
        if(fl->objectDetected()){
            blockedFL = true;
        }
        else{
            blockedFL = false;
        }
        if(fr->objectDetected()){
            blockedFR = true;
        }
        else{
            blockedFR = false;
        }
        if(rl->objectDetected()){
            blockedRL = true;
        }
        else{
            blockedRL = false;
        }
        if(rr->objectDetected()){
            blockedRR = true;
        }
        else{
            blockedRR = false;
        }
        // Stop the motors if any sensor was triggered
        if(blockedFL || blockedFR || blockedRL || blockedRR){
            motors->setMotorSpeeds(0, 0);
        }
        // Refresh every 10 ms
        usleep(10000);
    }
}

int main(int argc, char **argv)
{
  // Register signal handler
  signal(SIGINT, signalHandler);

  // Instantiate an I2C Grove Motor Driver on default I2C bus
  GroveMD *motors = new GroveMD(GROVEMD_I2C_BUS, GROVEMD_DEFAULT_I2C_ADDR);
  if(motors == NULL){
      cerr << "Failed to initialize the motor driver." << endl;
      exit(EXIT_FAILURE);
  }

  // Initialize the Grove RGB Backlit LCD using implicit
  // 0x62 for RGB_ADDRESS and 0x3E for LCD_ADDRESS
  Jhd1313m1 *lcd = new upm::Jhd1313m1(0);
  if(lcd == NULL){
      cerr << "Failed to initialize the LCD." << endl;
      exit(EXIT_FAILURE);
  }

  // Instantiate the HMC5883 compass on default bus
  Hmc5883l *compass = new Hmc5883l(0);
  if(compass == NULL){
      cerr << "Failed to initialize the HMC5883 compass." << endl;
      exit(EXIT_FAILURE);
  }

  // Instantiate the Grove Voltage Divider on pin A0
  GroveVDiv *divider = new GroveVDiv(0);
  if(divider == NULL){
      cerr << "Failed to initialize the voltage divider." << endl;
      exit(EXIT_FAILURE);
  }

  // Instantiate 4 Grove IR Distance Interrupters on pins D2, D4, D6, D8
  RFR359F *frontLeftIR = new RFR359F(2);
  RFR359F *frontRightIR = new RFR359F(4);
  RFR359F *rearLeftIR = new RFR359F(6);
  RFR359F *rearRightIR = new RFR359F(8);

  if(frontLeftIR == NULL || frontRightIR == NULL || rearLeftIR == NULL || rearRightIR == NULL){
      cerr << "Failed to initialize one of the IR sensors." << endl;
      exit(EXIT_FAILURE);
  }

  // Start independent threads for the different components
  thread comp (displayHeading, lcd, compass);
  thread batt (displayBattery, lcd, divider);
  thread collision (distanceIR, motors, frontLeftIR, frontRightIR, rearLeftIR, rearRightIR);

  // Main event and control loop
  // Commands are given through stdin as tuples of the form <CMD_NAME SPEED>
  // Except for the <stop> command and are case sensitive
  while(running){

      string command;
      int speed;

      // Wait command from stdin
      cin.clear();
      cin >> command;
      if(command == "stop" || command.empty()){
          // Stop rover
          motors->setMotorSpeeds(0, 0);
          cout << "Rover stopping!" << endl;
          continue;
      }
      // Read speed
      cin >> speed;
      // Check against non-numbers entered in string
      if(cin.fail()){
          cerr << "Error: Bad input! Please check your command and try again." << endl;
          continue;
      }
      // Check for proper range
      if(speed < 0 || speed > 255){
          cerr << "Error: Speed needs to be between 0 to 255." << endl;
          continue;
      }
      // Direction is set based on command/keyword
      if(command == "fwd" && (!blockedFL || !blockedFR)){
          motors->setMotorDirections(GroveMD::DIR_CW, GroveMD::DIR_CW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover going forward at speed " << speed << endl;
      }
      else if(command == "left"  && (!blockedFL || !blockedRL)){
          motors->setMotorDirections(GroveMD::DIR_CCW, GroveMD::DIR_CW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover turning left at speed " << speed << endl;
      }
      else if(command == "right" && (!blockedFR || !blockedRR)){
          motors->setMotorDirections(GroveMD::DIR_CW, GroveMD::DIR_CCW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover turning right at speed " << speed << endl;
      }
      else if(command == "rev"  && (!blockedRL || !blockedRR)){
          motors->setMotorDirections(GroveMD::DIR_CCW, GroveMD::DIR_CCW);
          motors->setMotorSpeeds(speed, speed);
          cout << "Rover in reverse at speed " << speed << endl;
      }
      else{
          motors->setMotorSpeeds(0, 0);
          cout << "Command not supported or direction blocked!" << endl;
      }
  }

  // Clean up and exit
  comp.join();
  batt.join();
  collision.join();

  // Turn off LCD
  lcd->setColor(0x00, 0x00, 0x00);
  lcd->clear();

  cout << "Exiting..." << endl;

  delete compass;
  delete divider;
  delete motors;
  return 0;
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2014-2015 DataStax

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "uuids.hpp"

#include "cassandra.h"
#include "get_time.hpp"
#include "logger.hpp"
#include "md5.hpp"
#include "serialization.hpp"
#include "scoped_lock.hpp"
#include "external_types.hpp"

#include <stdio.h>
#include <ctype.h>

#define TIME_OFFSET_BETWEEN_UTC_AND_EPOCH 0x01B21DD213814000LL // Nanoseconds
#define MIN_CLOCK_SEQ_AND_NODE 0x8080808080808080LL
#define MAX_CLOCK_SEQ_AND_NODE 0x7f7f7f7f7f7f7f7fLL

static uint64_t to_milliseconds(uint64_t timestamp) {
  return timestamp / 10000L;
}

static uint64_t from_unix_timestamp(uint64_t timestamp) {
  return (timestamp * 10000L) + TIME_OFFSET_BETWEEN_UTC_AND_EPOCH;
}

static uint64_t set_version(uint64_t timestamp, uint8_t version) {
  return (timestamp & 0x0FFFFFFFFFFFFFFFLL) | (static_cast<uint64_t>(version) << 60);
}

extern "C" {

CassUuidGen* cass_uuid_gen_new() {
  return CassUuidGen::to(new cass::UuidGen());
}

CassUuidGen* cass_uuid_gen_new_with_node(cass_uint64_t node) {
  return CassUuidGen::to(new cass::UuidGen(node));
}

void cass_uuid_gen_free(CassUuidGen* uuid_gen) {
  delete uuid_gen->from();
}

void cass_uuid_gen_time(CassUuidGen* uuid_gen, CassUuid* output) {
  uuid_gen->generate_time(output);
}

void cass_uuid_gen_random(CassUuidGen* uuid_gen, CassUuid* output) {
  uuid_gen->generate_random(output);
}

void cass_uuid_gen_from_time(CassUuidGen* uuid_gen, cass_uint64_t timestamp, CassUuid* output) {
  uuid_gen->from_time(timestamp, output);
}

void cass_uuid_min_from_time(cass_uint64_t timestamp, CassUuid* output) {
  output->time_and_version = set_version(timestamp, 1);
  output->clock_seq_and_node = MIN_CLOCK_SEQ_AND_NODE;
}

void cass_uuid_max_from_time(cass_uint64_t timestamp, CassUuid* output) {
  output->time_and_version = set_version(timestamp, 1);
  output->clock_seq_and_node = MAX_CLOCK_SEQ_AND_NODE;
}

cass_uint64_t cass_uuid_timestamp(CassUuid uuid) {
  uint64_t timestamp = uuid.time_and_version & 0x0FFFFFFFFFFFFFFFLL; // Clear version
  return to_milliseconds(timestamp - TIME_OFFSET_BETWEEN_UTC_AND_EPOCH);
}

cass_uint8_t cass_uuid_version(CassUuid uuid) {
  return (uuid.time_and_version >> 60) & 0x0F;
}

void cass_uuid_string(CassUuid uuid, char* output) {
  size_t pos = 0;
  char encoded[16];
  cass::encode_uuid(encoded, uuid);
  for (size_t i = 0; i < 16; ++i) {
    char buf[3] = { '\0' };
    sprintf(buf, "%02x", static_cast<uint8_t>(encoded[i]));
    if (i == 4 || i == 6 || i == 8 || i == 10) {
      output[pos++] = '-';
    }
    output[pos++] = buf[0];
    output[pos++] = buf[1];
  }
  output[pos] = '\0';
}

CassError cass_uuid_from_string(const char* str,
                                CassUuid* output) {
  if (str == NULL) {
    return CASS_ERROR_LIB_BAD_PARAMS;
  }

  return cass_uuid_from_string_n(str, strlen(str),
                                 output);
}

CassError cass_uuid_from_string_n(const char* str,
                                  size_t str_length,
                                  CassUuid* output) {
  const char* pos = str;
  char buf[16];

  if (str == NULL || str_length != 36) {
    return CASS_ERROR_LIB_BAD_PARAMS;
  }

  for (size_t i = 0; i < 16; ++i) {
    if (*pos == '-') pos++;
    unsigned int byte;
    intptr_t bytes_left = str - pos;
    if (bytes_left >= 2 || !isxdigit(*pos) || !isxdigit(*(pos + 1))) {
      return CASS_ERROR_LIB_BAD_PARAMS;
    }
    sscanf(pos, "%2x", &byte);
    buf[i] = static_cast<char>(byte);
    pos += 2;
  }

  cass::decode_uuid(buf, output);

  return CASS_OK;
}

} // extern "C"

namespace cass {

UuidGen::UuidGen()
  : clock_seq_and_node_(0)
  , last_timestamp_(0LL)
  , ng_(get_random_seed(MT19937_64::DEFAULT_SEED)){
  uv_mutex_init(&mutex_);

  Md5 md5;
  bool has_unique = false;
  uv_interface_address_t* addresses;
  int address_count;

#if UV_VERSION_MAJOR == 0
    if (uv_interface_addresses(&addresses, &address_count).code == UV_OK) {
#else
    if (uv_interface_addresses(&addresses, &address_count) == 0) {
#endif
    for (int i = 0; i < address_count; ++i) {
      char buf[256];
      uv_interface_address_t address = addresses[i];
      md5.update(reinterpret_cast<const uint8_t*>(address.name), strlen(address.name));
      if (address.address.address4.sin_family == AF_INET) {
        uv_ip4_name(&address.address.address4, buf, sizeof(buf));
        md5.update(reinterpret_cast<const uint8_t*>(buf), strlen(buf));
        has_unique = true;
      } else if (address.address.address4.sin_family == AF_INET6) {
        uv_ip6_name(&address.address.address6, buf, sizeof(buf));
        md5.update(reinterpret_cast<const uint8_t*>(buf), strlen(buf));
        has_unique = true;
      }
    }
    uv_free_interface_addresses(addresses, address_count);
  }

  uint64_t node = 0;
  if (has_unique) {
    uv_cpu_info_t* cpu_infos;
    int cpu_count;
#if UV_VERSION_MAJOR == 0
    if (uv_cpu_info(&cpu_infos, &cpu_count).code == UV_OK) {
#else
    if (uv_cpu_info(&cpu_infos, &cpu_count) == 0) {
#endif
      for (int i = 0; i < cpu_count; ++i) {
        uv_cpu_info_t cpu_info = cpu_infos[i];
        md5.update(reinterpret_cast<const uint8_t*>(cpu_info.model), strlen(cpu_info.model));
      }
      uv_free_cpu_info(cpu_infos, cpu_count);
    }

    uint8_t hash[16];
    md5.final(hash);

    for (int i = 0; i < 6; ++i) {
      node |= (0x00000000000000FFLL & (long)hash[i]) << (i * 8);
    }
  } else {
    LOG_INFO("Unable to determine unique data for this node. Generating a random node value.");
    node = ng_() & 0x0000FFFFFFFFFFFFLL;
  }

  node |= 0x0000010000000000LL; // Multicast bit

  set_clock_seq_and_node(node);
}

UuidGen::UuidGen(uint64_t node)
  : clock_seq_and_node_(0)
  , last_timestamp_(0LL)
  , ng_(get_random_seed(MT19937_64::DEFAULT_SEED)){
  uv_mutex_init(&mutex_);
  set_clock_seq_and_node(node & 0x0000FFFFFFFFFFFFLL);
}

UuidGen::~UuidGen() {
  uv_mutex_destroy(&mutex_);
}

void UuidGen::generate_time(CassUuid* output) {
  output->time_and_version = set_version(monotonic_timestamp(), 1);
  output->clock_seq_and_node = clock_seq_and_node_;
}

void UuidGen::from_time(uint64_t timestamp, CassUuid* output) {
  output->time_and_version = set_version(from_unix_timestamp(timestamp), 1);
  output->clock_seq_and_node = clock_seq_and_node_;
}

void UuidGen::generate_random(CassUuid* output) {
  ScopedMutex lock(&mutex_);
  uint64_t time_and_version = ng_();
  uint64_t clock_seq_and_node = ng_();
  lock.unlock();

  output->time_and_version = set_version(time_and_version, 4);
  output->clock_seq_and_node = (clock_seq_and_node & 0x3FFFFFFFFFFFFFFFLL) | 0x8000000000000000LL; // RFC4122 variant
}

void UuidGen::set_clock_seq_and_node(uint64_t node) {
  uint64_t clock_seq = ng_();
  clock_seq_and_node_ |= (clock_seq & 0x0000000000003FFFLL) << 48;
  clock_seq_and_node_ |= 0x8000000000000000LL; // RFC4122 variant
  clock_seq_and_node_ |= node;
}

uint64_t UuidGen::monotonic_timestamp() {
  while (true) {
    uint64_t now = from_unix_timestamp(get_time_since_epoch_ms());
    uint64_t last = last_timestamp_.load();
    if (now > last) {
      if (last_timestamp_.compare_exchange_strong(last, now)) {
        return now;
      }
    } else {
      uint64_t last_ms = to_milliseconds(last);
      if (to_milliseconds(now) < last_ms) {
        return last_timestamp_.fetch_add(1);
      }
      uint64_t candidate = last + 1;
      if (to_milliseconds(candidate) == last_ms &&
          last_timestamp_.compare_exchange_strong(last, candidate)) {
        return candidate;
      }
    }
  }
}

} // namespace cass
<commit_msg>Add timestamp conversion in cass_uuid_min/max_from_time() function to be consistent with cass_uuid_gen_from_time() function. CPP-283<commit_after>/*
  Copyright (c) 2014-2015 DataStax

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "uuids.hpp"

#include "cassandra.h"
#include "get_time.hpp"
#include "logger.hpp"
#include "md5.hpp"
#include "serialization.hpp"
#include "scoped_lock.hpp"
#include "external_types.hpp"

#include <stdio.h>
#include <ctype.h>

#define TIME_OFFSET_BETWEEN_UTC_AND_EPOCH 0x01B21DD213814000LL // Nanoseconds
#define MIN_CLOCK_SEQ_AND_NODE 0x8080808080808080LL
#define MAX_CLOCK_SEQ_AND_NODE 0x7f7f7f7f7f7f7f7fLL

static uint64_t to_milliseconds(uint64_t timestamp) {
  return timestamp / 10000L;
}

static uint64_t from_unix_timestamp(uint64_t timestamp) {
  return (timestamp * 10000L) + TIME_OFFSET_BETWEEN_UTC_AND_EPOCH;
}

static uint64_t set_version(uint64_t timestamp, uint8_t version) {
  return (timestamp & 0x0FFFFFFFFFFFFFFFLL) | (static_cast<uint64_t>(version) << 60);
}

extern "C" {

CassUuidGen* cass_uuid_gen_new() {
  return CassUuidGen::to(new cass::UuidGen());
}

CassUuidGen* cass_uuid_gen_new_with_node(cass_uint64_t node) {
  return CassUuidGen::to(new cass::UuidGen(node));
}

void cass_uuid_gen_free(CassUuidGen* uuid_gen) {
  delete uuid_gen->from();
}

void cass_uuid_gen_time(CassUuidGen* uuid_gen, CassUuid* output) {
  uuid_gen->generate_time(output);
}

void cass_uuid_gen_random(CassUuidGen* uuid_gen, CassUuid* output) {
  uuid_gen->generate_random(output);
}

void cass_uuid_gen_from_time(CassUuidGen* uuid_gen, cass_uint64_t timestamp, CassUuid* output) {
  uuid_gen->from_time(timestamp, output);
}

void cass_uuid_min_from_time(cass_uint64_t timestamp, CassUuid* output) {
  output->time_and_version = set_version(from_unix_timestamp(timestamp), 1);
  output->clock_seq_and_node = MIN_CLOCK_SEQ_AND_NODE;
}

void cass_uuid_max_from_time(cass_uint64_t timestamp, CassUuid* output) {
  output->time_and_version = set_version(from_unix_timestamp(timestamp), 1);
  output->clock_seq_and_node = MAX_CLOCK_SEQ_AND_NODE;
}

cass_uint64_t cass_uuid_timestamp(CassUuid uuid) {
  uint64_t timestamp = uuid.time_and_version & 0x0FFFFFFFFFFFFFFFLL; // Clear version
  return to_milliseconds(timestamp - TIME_OFFSET_BETWEEN_UTC_AND_EPOCH);
}

cass_uint8_t cass_uuid_version(CassUuid uuid) {
  return (uuid.time_and_version >> 60) & 0x0F;
}

void cass_uuid_string(CassUuid uuid, char* output) {
  size_t pos = 0;
  char encoded[16];
  cass::encode_uuid(encoded, uuid);
  for (size_t i = 0; i < 16; ++i) {
    char buf[3] = { '\0' };
    sprintf(buf, "%02x", static_cast<uint8_t>(encoded[i]));
    if (i == 4 || i == 6 || i == 8 || i == 10) {
      output[pos++] = '-';
    }
    output[pos++] = buf[0];
    output[pos++] = buf[1];
  }
  output[pos] = '\0';
}

CassError cass_uuid_from_string(const char* str,
                                CassUuid* output) {
  if (str == NULL) {
    return CASS_ERROR_LIB_BAD_PARAMS;
  }

  return cass_uuid_from_string_n(str, strlen(str),
                                 output);
}

CassError cass_uuid_from_string_n(const char* str,
                                  size_t str_length,
                                  CassUuid* output) {
  const char* pos = str;
  char buf[16];

  if (str == NULL || str_length != 36) {
    return CASS_ERROR_LIB_BAD_PARAMS;
  }

  for (size_t i = 0; i < 16; ++i) {
    if (*pos == '-') pos++;
    unsigned int byte;
    intptr_t bytes_left = str - pos;
    if (bytes_left >= 2 || !isxdigit(*pos) || !isxdigit(*(pos + 1))) {
      return CASS_ERROR_LIB_BAD_PARAMS;
    }
    sscanf(pos, "%2x", &byte);
    buf[i] = static_cast<char>(byte);
    pos += 2;
  }

  cass::decode_uuid(buf, output);

  return CASS_OK;
}

} // extern "C"

namespace cass {

UuidGen::UuidGen()
  : clock_seq_and_node_(0)
  , last_timestamp_(0LL)
  , ng_(get_random_seed(MT19937_64::DEFAULT_SEED)){
  uv_mutex_init(&mutex_);

  Md5 md5;
  bool has_unique = false;
  uv_interface_address_t* addresses;
  int address_count;

#if UV_VERSION_MAJOR == 0
    if (uv_interface_addresses(&addresses, &address_count).code == UV_OK) {
#else
    if (uv_interface_addresses(&addresses, &address_count) == 0) {
#endif
    for (int i = 0; i < address_count; ++i) {
      char buf[256];
      uv_interface_address_t address = addresses[i];
      md5.update(reinterpret_cast<const uint8_t*>(address.name), strlen(address.name));
      if (address.address.address4.sin_family == AF_INET) {
        uv_ip4_name(&address.address.address4, buf, sizeof(buf));
        md5.update(reinterpret_cast<const uint8_t*>(buf), strlen(buf));
        has_unique = true;
      } else if (address.address.address4.sin_family == AF_INET6) {
        uv_ip6_name(&address.address.address6, buf, sizeof(buf));
        md5.update(reinterpret_cast<const uint8_t*>(buf), strlen(buf));
        has_unique = true;
      }
    }
    uv_free_interface_addresses(addresses, address_count);
  }

  uint64_t node = 0;
  if (has_unique) {
    uv_cpu_info_t* cpu_infos;
    int cpu_count;
#if UV_VERSION_MAJOR == 0
    if (uv_cpu_info(&cpu_infos, &cpu_count).code == UV_OK) {
#else
    if (uv_cpu_info(&cpu_infos, &cpu_count) == 0) {
#endif
      for (int i = 0; i < cpu_count; ++i) {
        uv_cpu_info_t cpu_info = cpu_infos[i];
        md5.update(reinterpret_cast<const uint8_t*>(cpu_info.model), strlen(cpu_info.model));
      }
      uv_free_cpu_info(cpu_infos, cpu_count);
    }

    uint8_t hash[16];
    md5.final(hash);

    for (int i = 0; i < 6; ++i) {
      node |= (0x00000000000000FFLL & (long)hash[i]) << (i * 8);
    }
  } else {
    LOG_INFO("Unable to determine unique data for this node. Generating a random node value.");
    node = ng_() & 0x0000FFFFFFFFFFFFLL;
  }

  node |= 0x0000010000000000LL; // Multicast bit

  set_clock_seq_and_node(node);
}

UuidGen::UuidGen(uint64_t node)
  : clock_seq_and_node_(0)
  , last_timestamp_(0LL)
  , ng_(get_random_seed(MT19937_64::DEFAULT_SEED)){
  uv_mutex_init(&mutex_);
  set_clock_seq_and_node(node & 0x0000FFFFFFFFFFFFLL);
}

UuidGen::~UuidGen() {
  uv_mutex_destroy(&mutex_);
}

void UuidGen::generate_time(CassUuid* output) {
  output->time_and_version = set_version(monotonic_timestamp(), 1);
  output->clock_seq_and_node = clock_seq_and_node_;
}

void UuidGen::from_time(uint64_t timestamp, CassUuid* output) {
  output->time_and_version = set_version(from_unix_timestamp(timestamp), 1);
  output->clock_seq_and_node = clock_seq_and_node_;
}

void UuidGen::generate_random(CassUuid* output) {
  ScopedMutex lock(&mutex_);
  uint64_t time_and_version = ng_();
  uint64_t clock_seq_and_node = ng_();
  lock.unlock();

  output->time_and_version = set_version(time_and_version, 4);
  output->clock_seq_and_node = (clock_seq_and_node & 0x3FFFFFFFFFFFFFFFLL) | 0x8000000000000000LL; // RFC4122 variant
}

void UuidGen::set_clock_seq_and_node(uint64_t node) {
  uint64_t clock_seq = ng_();
  clock_seq_and_node_ |= (clock_seq & 0x0000000000003FFFLL) << 48;
  clock_seq_and_node_ |= 0x8000000000000000LL; // RFC4122 variant
  clock_seq_and_node_ |= node;
}

uint64_t UuidGen::monotonic_timestamp() {
  while (true) {
    uint64_t now = from_unix_timestamp(get_time_since_epoch_ms());
    uint64_t last = last_timestamp_.load();
    if (now > last) {
      if (last_timestamp_.compare_exchange_strong(last, now)) {
        return now;
      }
    } else {
      uint64_t last_ms = to_milliseconds(last);
      if (to_milliseconds(now) < last_ms) {
        return last_timestamp_.fetch_add(1);
      }
      uint64_t candidate = last + 1;
      if (to_milliseconds(candidate) == last_ms &&
          last_timestamp_.compare_exchange_strong(last, candidate)) {
        return candidate;
      }
    }
  }
}

} // namespace cass
<|endoftext|>


<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    utils/classify.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

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

    Kleopatra is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "classify.h"

#include <QString>
#include <QStringList>
#include <QFile>
#include <QFileInfo>
#include <QtAlgorithms>

#include <boost/range.hpp>

#ifdef __GNUC__
# include <ext/algorithm>
#endif

#include <functional>

using namespace boost;
using namespace Kleo::Class;

namespace {

    static const struct _classification {
        char extension[4];
        unsigned int classification;
    } classifications[] = {
        // ordered by extension
        { "asc", OpenPGP|  Ascii  | OpaqueSignature|DetachedSignature|CipherText|AnyCertStoreType },
        { "crt", CMS    | Binary  | Certificate },
        { "der", CMS    | Binary  | Certificate },
        { "gpg", OpenPGP| Binary  | OpaqueSignature|CipherText|AnyCertStoreType },
        { "p10", CMS    |  Ascii  | CertificateRequest },
        { "p12", CMS    | Binary  | ExportedPSM },
        { "p7c", CMS    | Binary  | Certificate  },
        { "p7m", CMS    | Binary  | CipherText },
        { "p7s", CMS    | Binary  | AnySignature },
        { "pem", CMS    |  Ascii  | AnyType },
        { "sig", OpenPGP|AnyFormat| DetachedSignature },
    };

    static const unsigned int defaultClassification = NoClass;

    template <template <typename U> class Op>
    struct ByExtension {
        typedef bool result_type;

        template <typename T>
        bool operator()( const T & lhs, const T & rhs ) const {
            return Op<int>()( qstricmp( lhs.extension, rhs.extension ), 0 );
        }
        template <typename T>
        bool operator()( const T & lhs, const char * rhs ) const {
            return Op<int>()( qstricmp( lhs.extension, rhs ), 0 );
        }
        template <typename T>
        bool operator()( const char * lhs, const T & rhs ) const {
            return Op<int>()( qstricmp( lhs, rhs.extension ), 0 );
        }
        bool operator()( const char * lhs, const char * rhs ) const {
            return Op<int>()( qstricmp( lhs, rhs ), 0 );
        }
    };

}

unsigned int Kleo::classify( const QString & filename ) {
#ifdef __GNUC__
    assert( __gnu_cxx::is_sorted( begin( classifications ), end( classifications ), ByExtension<std::less>() ) );
#endif

    const QFileInfo fi( filename );

    const _classification * const it = qBinaryFind( begin( classifications ), end( classifications ),
                                                    fi.suffix().toLatin1().constData(),
                                                    ByExtension<std::less>() );
    if ( it == end( classifications ) )
        return defaultClassification;
    else
        return it->classification;
}

static QString chopped( QString s, unsigned int n ) {
    s.chop( n );
    return s;
}

/*!
  \return the data file that corresponds to the signature file \a
  signatureFileName, or QString(), if no such file can be found.
*/
QString Kleo::findSignedData( const QString & signatureFileName ) {
    if ( !mayBeDetachedSignature( signatureFileName ) )
        return QString();
    const QString baseName = chopped( signatureFileName, 4 );
    return QFile::exists( baseName ) ? baseName : QString() ;
}

/*!
  \return all (existing) candiate signature files for \a signedDataFileName

  Note that there can very well be more than one such file, e.g. if
  the same data file was signed by both CMS and OpenPGP certificates.
*/
QStringList Kleo::findSignatures( const QString & signedDataFileName ) {
    QStringList result;
    for ( unsigned int i = 0, end = size( classifications ) ; i < end ; ++i )
        if ( classifications[i].classification & DetachedSignature ) {
            const QString candiate = signedDataFileName + '.' + classifications[i].extension;
            if ( QFile::exists( candiate ) )
                result.push_back( candiate );
        }
    return result;
}

/*!
  \return the (likely) output filename for \a inputFileName, or
  "inputFileName.out" if none can be determined.
*/
QString Kleo::outputFileName( const QString & inputFileName ) {
    const QFileInfo fi( inputFileName );

    if ( qBinaryFind( begin( classifications ), end( classifications ),
                      fi.suffix().toLatin1().constData(),
                      ByExtension<std::less>() ) == end( classifications ) )
        return inputFileName + ".out";
    else
        return chopped( inputFileName, 4 );
}

/*!
  \return the commonly used extension for files of type
  \a classification, or NULL if none such exists.
*/
const char * Kleo::outputFileExtension( unsigned int classification ) {
    for ( unsigned int i = 0 ; i < sizeof classifications / sizeof *classifications ; ++i )
        if ( ( classifications[i].classification & classification ) == classification )
            return classifications[i].extension;
    return 0;
}
<commit_msg>Peek into ascii formats to determine a more exact classification.<commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    utils/classify.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

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

    Kleopatra is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "classify.h"

#include <QString>
#include <QStringList>
#include <QFile>
#include <QFileInfo>
#include <QtAlgorithms>
#include <QByteArrayMatcher>

#include <boost/range.hpp>

#ifdef __GNUC__
# include <ext/algorithm>
#endif

#include <functional>

using namespace boost;
using namespace Kleo::Class;

namespace {

    const unsigned int ExamineContentHint = 0x8000;

    static const struct _classification {
        char extension[4];
        unsigned int classification;
    } classifications[] = {
        // ordered by extension
        { "asc", OpenPGP|  Ascii  | OpaqueSignature|DetachedSignature|CipherText|AnyCertStoreType | ExamineContentHint },
        { "crt", CMS    | Binary  | Certificate },
        { "der", CMS    | Binary  | Certificate },
        { "gpg", OpenPGP| Binary  | OpaqueSignature|CipherText|AnyCertStoreType },
        { "p10", CMS    |  Ascii  | CertificateRequest },
        { "p12", CMS    | Binary  | ExportedPSM },
        { "p7c", CMS    | Binary  | Certificate  },
        { "p7m", CMS    | Binary  | CipherText },
        { "p7s", CMS    | Binary  | AnySignature },
        { "pem", CMS    |  Ascii  | AnyType | ExamineContentHint },
        { "sig", OpenPGP|AnyFormat| DetachedSignature },
    };

    static const unsigned int defaultClassification = NoClass;

    template <template <typename U> class Op>
    struct ByExtension {
        typedef bool result_type;

        template <typename T>
        bool operator()( const T & lhs, const T & rhs ) const {
            return Op<int>()( qstricmp( lhs.extension, rhs.extension ), 0 );
        }
        template <typename T>
        bool operator()( const T & lhs, const char * rhs ) const {
            return Op<int>()( qstricmp( lhs.extension, rhs ), 0 );
        }
        template <typename T>
        bool operator()( const char * lhs, const T & rhs ) const {
            return Op<int>()( qstricmp( lhs, rhs.extension ), 0 );
        }
        bool operator()( const char * lhs, const char * rhs ) const {
            return Op<int>()( qstricmp( lhs, rhs ), 0 );
        }
    };

    static const struct _content_classification {
        char content[28];
        unsigned int classification;
    } content_classifications[] = {
        { "MESSAGE",           OpaqueSignature|CipherText },
        { "PRIVATE KEY BLOCK", ExportedPSM },
        { "PUBLIC KEY BLOCK",  Certificate },
        { "SIGNATURE",         DetachedSignature },
    };

    template <template <typename U> class Op>
    struct ByContent {
        typedef bool result_type;

        const unsigned int N;
        explicit ByContent( unsigned int n ) : N( n ) {}

        template <typename T>
        bool operator()( const T & lhs, const T & rhs ) const {
            return Op<int>()( qstrncmp( lhs.content, rhs.content, N ), 0 );
        }
        template <typename T>
        bool operator()( const T & lhs, const char * rhs ) const {
            return Op<int>()( qstrncmp( lhs.content, rhs, N ), 0 );
        }
        template <typename T>
        bool operator()( const char * lhs, const T & rhs ) const {
            return Op<int>()( qstrncmp( lhs, rhs.content, N ), 0 );
        }
        bool operator()( const char * lhs, const char * rhs ) const {
            return Op<int>()( qstrncmp( lhs, rhs, N ), 0 );
        }
    };

}

unsigned int Kleo::classify( const QString & filename ) {
#ifdef __GNUC__
    assert( __gnu_cxx::is_sorted( begin( classifications ), end( classifications ), ByExtension<std::less>() ) );
    assert( __gnu_cxx::is_sorted( begin( content_classifications ), end( content_classifications ), ByContent<std::less>(100) ) );
#endif

    const QFileInfo fi( filename );

    const _classification * const it = qBinaryFind( begin( classifications ), end( classifications ),
                                                    fi.suffix().toLatin1().constData(),
                                                    ByExtension<std::less>() );
    if ( it == end( classifications ) )
        return defaultClassification;
    if ( !( it->classification & ExamineContentHint ) )
        return it->classification;

    QFile file( filename );
    if ( !file.open( QIODevice::ReadOnly|QIODevice::Text ) )
        return it->classification;

    const QByteArray read = file.read( 1024 );

    static const char beginString[] = "-----BEGIN ";
    static const QByteArrayMatcher beginMatcher( beginString );
    int pos = beginMatcher.indexIn( read );
    if ( pos < 0 )
        return it->classification;
    pos += sizeof beginString - 1;

    const bool pgp = qstrncmp( read.data() + pos, "PGP ", 4 ) == 0;
    if ( pgp )
        pos += 4;

    const int epos = read.indexOf( "-----\n", pos );
    if ( epos < 0 )
        return it->classification;

    const _content_classification * const cit
        = qBinaryFind( begin( content_classifications ), end( content_classifications ),
                       read.data() + pos, ByContent<std::less>( epos - pos ) );

    if ( cit == end( content_classifications ) )
        return it->classification;
    else
        return cit->classification | ( pgp ? OpenPGP : CMS );
}

static QString chopped( QString s, unsigned int n ) {
    s.chop( n );
    return s;
}

/*!
  \return the data file that corresponds to the signature file \a
  signatureFileName, or QString(), if no such file can be found.
*/
QString Kleo::findSignedData( const QString & signatureFileName ) {
    if ( !mayBeDetachedSignature( signatureFileName ) )
        return QString();
    const QString baseName = chopped( signatureFileName, 4 );
    return QFile::exists( baseName ) ? baseName : QString() ;
}

/*!
  \return all (existing) candiate signature files for \a signedDataFileName

  Note that there can very well be more than one such file, e.g. if
  the same data file was signed by both CMS and OpenPGP certificates.
*/
QStringList Kleo::findSignatures( const QString & signedDataFileName ) {
    QStringList result;
    for ( unsigned int i = 0, end = size( classifications ) ; i < end ; ++i )
        if ( classifications[i].classification & DetachedSignature ) {
            const QString candiate = signedDataFileName + '.' + classifications[i].extension;
            if ( QFile::exists( candiate ) )
                result.push_back( candiate );
        }
    return result;
}

/*!
  \return the (likely) output filename for \a inputFileName, or
  "inputFileName.out" if none can be determined.
*/
QString Kleo::outputFileName( const QString & inputFileName ) {
    const QFileInfo fi( inputFileName );

    if ( qBinaryFind( begin( classifications ), end( classifications ),
                      fi.suffix().toLatin1().constData(),
                      ByExtension<std::less>() ) == end( classifications ) )
        return inputFileName + ".out";
    else
        return chopped( inputFileName, 4 );
}

/*!
  \return the commonly used extension for files of type
  \a classification, or NULL if none such exists.
*/
const char * Kleo::outputFileExtension( unsigned int classification ) {
    for ( unsigned int i = 0 ; i < sizeof classifications / sizeof *classifications ; ++i )
        if ( ( classifications[i].classification & classification ) == classification )
            return classifications[i].extension;
    return 0;
}
<|endoftext|>


<commit_before>/*
  This file is part of KOrganizer.
  Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
  Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>

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

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "datenavigator.h"
#include "koglobals.h"

#include <kcalendarsystem.h>
#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>

using namespace KCal;

DateNavigator::DateNavigator( QObject *parent ) : QObject( parent )
{
  mSelectedDates.append( QDate::currentDate() );
}

DateNavigator::~DateNavigator()
{
}

DateList DateNavigator::selectedDates()
{
  return mSelectedDates;
}

int DateNavigator::datesCount() const
{
  return mSelectedDates.count();
}

void DateNavigator::selectDates( const DateList &dateList )
{
  if ( dateList.count() > 0 ) {
    mSelectedDates = dateList;
    emitSelected();
  }
}

void DateNavigator::selectDate( const QDate &date )
{
  QDate d = date;

  if ( !d.isValid() ) {
    kDebug() << "an invalid date was passed as a parameter!";
    d = QDate::currentDate();
  }

  mSelectedDates.clear();
  mSelectedDates.append( d );

  emitSelected();
}

void DateNavigator::selectDates( int count )
{
  selectDates( mSelectedDates.first(), count );
}

void DateNavigator::selectDates( const QDate &d, int count )
{
  DateList dates;

  int i;
  for ( i = 0; i < count; ++i ) {
    dates.append( d.addDays( i ) );
  }

  mSelectedDates = dates;
  emitSelected();
}

void DateNavigator::selectWeekByDay( int weekDay, const QDate &d )
{
  int dateCount = mSelectedDates.count();
  bool weekStart = ( weekDay == KGlobal::locale()->weekStartDay() );
  if ( weekStart && dateCount == 7 ) {
    selectWeek( d );
  } else {
    selectDates( d, dateCount );
  }
}

void DateNavigator::selectWeek()
{
  selectWeek( mSelectedDates.first() );
}

void DateNavigator::selectWeek( const QDate &d )
{
  int dayOfWeek = KOGlobals::self()->calendarSystem()->dayOfWeek( d );

  int weekStart = KGlobal::locale()->weekStartDay();

  QDate firstDate = d.addDays( weekStart - dayOfWeek );

  if ( weekStart != 1 && dayOfWeek < weekStart ) {
    firstDate = firstDate.addDays( -7 );
  }

  selectDates( firstDate, 7 );
}

void DateNavigator::selectWorkWeek()
{
  selectWorkWeek( mSelectedDates.first() );
}

void DateNavigator::selectWorkWeek( const QDate &d )
{
  int weekStart = KGlobal::locale()->weekStartDay();
  int dayOfWeek = KOGlobals::self()->calendarSystem()->dayOfWeek( d );
  QDate currentDate = d.addDays( weekStart - dayOfWeek );

  if ( weekStart != 1 && dayOfWeek < weekStart ) {
    currentDate = currentDate.addDays( -7 );
  }

  mSelectedDates.clear();
  int mask = KOGlobals::self()->getWorkWeekMask();

  for ( int i = 0; i < 7; ++i ) {
    if ( ( 1 << ( ( i + weekStart + 6 ) % 7 ) ) & (mask) ) {
      mSelectedDates.append( currentDate.addDays( i ) );
    }
  }

  emitSelected();
}

void DateNavigator::selectToday()
{
  QDate d = QDate::currentDate();

  int dateCount = mSelectedDates.count();

  if ( dateCount == 7 ) {
    selectWeek( d );
  } else {
    selectDates( d, dateCount );
  }
}

void DateNavigator::selectPreviousYear()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();
  firstSelected = KOGlobals::self()->calendarSystem()->addYears( firstSelected, -1 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectPreviousMonth()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();
  firstSelected = KOGlobals::self()->calendarSystem()->addMonths( firstSelected, -1 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectPreviousWeek()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();
  firstSelected = KOGlobals::self()->calendarSystem()->addDays( firstSelected, -7 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectNextWeek()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();

  firstSelected = KOGlobals::self()->calendarSystem()->addDays( firstSelected, 7 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectNextMonth()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();

  firstSelected = KOGlobals::self()->calendarSystem()->addMonths( firstSelected, 1 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectNextYear()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();
  firstSelected = KOGlobals::self()->calendarSystem()->addYears( firstSelected, 1 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectPrevious()
{
  int offset = -7;
  if ( datesCount() == 1 ) {
    offset = -1;
  }

  selectDates( mSelectedDates.first().addDays( offset ), datesCount() );
}

void DateNavigator::selectNext()
{
  int offset = 7;
  if ( datesCount() == 1 ) {
    offset = 1;
  }

  selectDates( mSelectedDates.first().addDays( offset ), datesCount() );
}

void DateNavigator::selectMonth( int month )
{
  // always display starting at the first week of the specified month

  QDate firstSelected = QDate( mSelectedDates.first().year(), month, 1 );

  const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
  int day = calSys->day( firstSelected );
  calSys->setYMD( firstSelected, calSys->year( firstSelected ), month, 1 );
  int days = calSys->daysInMonth( firstSelected );
  // As day we use either the selected date, or if the month has less days
  // than that, we use the max day of that month
  if ( day > days ) {
    day = days;
  }
  calSys->setYMD( firstSelected, calSys->year( firstSelected ), month, day );

  selectWeekByDay( 1, firstSelected );
}

void DateNavigator::selectYear( int year )
{
  QDate firstSelected = mSelectedDates.first();
  int deltaYear = year - KOGlobals::self()->calendarSystem()->year( firstSelected );
  firstSelected = KOGlobals::self()->calendarSystem()->addYears( firstSelected, deltaYear );

  int weekDay = firstSelected.dayOfWeek();
  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::emitSelected()
{
  emit datesSelected( mSelectedDates );
}

#include "datenavigator.moc"
<commit_msg>SVN_MERGE Merged revisions 1015955 via svnmerge from  svn+ssh://tmcguire@svn.kde.org/home/kde/branches/kdepim/enterprise4/kdepim<commit_after>/*
  This file is part of KOrganizer.
  Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
  Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>

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

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "datenavigator.h"
#include "koglobals.h"

#include <kcalendarsystem.h>
#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>

using namespace KCal;

DateNavigator::DateNavigator( QObject *parent ) : QObject( parent )
{
  mSelectedDates.append( QDate::currentDate() );
}

DateNavigator::~DateNavigator()
{
}

DateList DateNavigator::selectedDates()
{
  return mSelectedDates;
}

int DateNavigator::datesCount() const
{
  return mSelectedDates.count();
}

void DateNavigator::selectDates( const DateList &dateList )
{
  if ( dateList.count() > 0 ) {
    mSelectedDates = dateList;
    emitSelected();
  }
}

void DateNavigator::selectDate( const QDate &date )
{
  QDate d = date;

  if ( !d.isValid() ) {
    kDebug() << "an invalid date was passed as a parameter!";
    d = QDate::currentDate();
  }

  mSelectedDates.clear();
  mSelectedDates.append( d );

  emitSelected();
}

void DateNavigator::selectDates( int count )
{
  selectDates( mSelectedDates.first(), count );
}

void DateNavigator::selectDates( const QDate &d, int count )
{
  DateList dates;

  int i;
  for ( i = 0; i < count; ++i ) {
    dates.append( d.addDays( i ) );
  }

  mSelectedDates = dates;
  emitSelected();
}

void DateNavigator::selectWeekByDay( int weekDay, const QDate &d )
{
  int dateCount = mSelectedDates.count();
  bool weekStart = ( weekDay == KGlobal::locale()->weekStartDay() );
  if ( weekStart && dateCount == 7 ) {
    selectWeek( d );
  } else {
    selectDates( d, dateCount );
  }
}

void DateNavigator::selectWeek()
{
  selectWeek( mSelectedDates.first() );
}

void DateNavigator::selectWeek( const QDate &d )
{
  int dayOfWeek = KOGlobals::self()->calendarSystem()->dayOfWeek( d );

  int weekStart = KGlobal::locale()->weekStartDay();

  QDate firstDate = d.addDays( weekStart - dayOfWeek );

  if ( weekStart != 1 && dayOfWeek < weekStart ) {
    firstDate = firstDate.addDays( -7 );
  }

  selectDates( firstDate, 7 );
}

void DateNavigator::selectWorkWeek()
{
  selectWorkWeek( mSelectedDates.first() );
}

void DateNavigator::selectWorkWeek( const QDate &d )
{
  int weekStart = KGlobal::locale()->weekStartDay();
  int dayOfWeek = KOGlobals::self()->calendarSystem()->dayOfWeek( d );
  QDate currentDate = d.addDays( weekStart - dayOfWeek );

  if ( weekStart != 1 && dayOfWeek < weekStart ) {
    currentDate = currentDate.addDays( -7 );
  }

  mSelectedDates.clear();
  int mask = KOGlobals::self()->getWorkWeekMask();

  for ( int i = 0; i < 7; ++i ) {
    if ( ( 1 << ( ( i + weekStart + 6 ) % 7 ) ) & (mask) ) {
      mSelectedDates.append( currentDate.addDays( i ) );
    }
  }

  emitSelected();
}

void DateNavigator::selectToday()
{
  QDate d = QDate::currentDate();

  int dateCount = mSelectedDates.count();

  if ( dateCount == 7 ) {
    selectWeek( d );
  } else if ( dateCount == 5 ) {
    selectWorkWeek( d );
  } else {
    selectDates( d, dateCount );
  }
}

void DateNavigator::selectPreviousYear()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();
  firstSelected = KOGlobals::self()->calendarSystem()->addYears( firstSelected, -1 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectPreviousMonth()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();
  firstSelected = KOGlobals::self()->calendarSystem()->addMonths( firstSelected, -1 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectPreviousWeek()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();
  firstSelected = KOGlobals::self()->calendarSystem()->addDays( firstSelected, -7 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectNextWeek()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();

  firstSelected = KOGlobals::self()->calendarSystem()->addDays( firstSelected, 7 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectNextMonth()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();

  firstSelected = KOGlobals::self()->calendarSystem()->addMonths( firstSelected, 1 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectNextYear()
{
  QDate firstSelected = mSelectedDates.first();
  int weekDay = firstSelected.dayOfWeek();
  firstSelected = KOGlobals::self()->calendarSystem()->addYears( firstSelected, 1 );

  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::selectPrevious()
{
  int offset = -7;
  if ( datesCount() == 1 ) {
    offset = -1;
  }

  selectDates( mSelectedDates.first().addDays( offset ), datesCount() );
}

void DateNavigator::selectNext()
{
  int offset = 7;
  if ( datesCount() == 1 ) {
    offset = 1;
  }

  selectDates( mSelectedDates.first().addDays( offset ), datesCount() );
}

void DateNavigator::selectMonth( int month )
{
  // always display starting at the first week of the specified month

  QDate firstSelected = QDate( mSelectedDates.first().year(), month, 1 );

  const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
  int day = calSys->day( firstSelected );
  calSys->setYMD( firstSelected, calSys->year( firstSelected ), month, 1 );
  int days = calSys->daysInMonth( firstSelected );
  // As day we use either the selected date, or if the month has less days
  // than that, we use the max day of that month
  if ( day > days ) {
    day = days;
  }
  calSys->setYMD( firstSelected, calSys->year( firstSelected ), month, day );

  selectWeekByDay( 1, firstSelected );
}

void DateNavigator::selectYear( int year )
{
  QDate firstSelected = mSelectedDates.first();
  int deltaYear = year - KOGlobals::self()->calendarSystem()->year( firstSelected );
  firstSelected = KOGlobals::self()->calendarSystem()->addYears( firstSelected, deltaYear );

  int weekDay = firstSelected.dayOfWeek();
  selectWeekByDay( weekDay, firstSelected );
}

void DateNavigator::emitSelected()
{
  emit datesSelected( mSelectedDates );
}

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