<commit_before>#ifdef USE_UPNP
#include <string>
#include <thread>

#include <boost/thread/thread.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include "Log.h"

#include "RouterContext.h"
#include "UPnP.h"
#include "NetDb.hpp"
#include "util.h"
#include "RouterInfo.h"
#include "Config.h"

#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>

namespace i2p
{
namespace transport
{
	UPnP::UPnP () : m_IsRunning(false), m_Thread (nullptr), m_Timer (m_Service)
	{
	}

	void UPnP::Stop ()
	{
		if (m_IsRunning)
		{
			LogPrint(eLogInfo, "UPnP: stopping");
			m_IsRunning = false;
			m_Timer.cancel ();
			m_Service.stop ();
			if (m_Thread)
			{
				m_Thread->join ();
				m_Thread.reset (nullptr);
			}
			CloseMapping ();
			Close ();
		}
	}

	void UPnP::Start()
	{
		m_IsRunning = true;
		LogPrint(eLogInfo, "UPnP: starting");
		m_Service.post (std::bind (&UPnP::Discover, this));
		std::unique_lock<std::mutex> l(m_StartedMutex);
		m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this)));
		m_Started.wait_for (l, std::chrono::seconds (5)); // 5 seconds maximum
	}

	UPnP::~UPnP ()
	{
		Stop ();
	}

	void UPnP::Run ()
	{
		while (m_IsRunning)
		{
			try
			{
				m_Service.run ();
				// Discover failed
				break; // terminate the thread
			}
			catch (std::exception& ex)
			{
				LogPrint (eLogError, "UPnP: runtime exception: ", ex.what ());
				PortMapping ();
			}
		}
	}

	void UPnP::Discover ()
	{
#if MINIUPNPC_API_VERSION >= 14
		int nerror = 0;
		m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror);
#elif ( MINIUPNPC_API_VERSION >= 8 || defined(UPNPDISCOVER_SUCCESS) )
		int nerror = 0;
		m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror);
#else
		m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0);
#endif
		{
			// notify satrting thread
			std::unique_lock<std::mutex> l(m_StartedMutex);
			m_Started.notify_all ();
		}

		int r;
		r = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
		if (r == 1)
		{
			r = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
			if(r != UPNPCOMMAND_SUCCESS)
			{
				LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress() returned ", r);
				return;
			}
			else
			{
				if (!m_externalIPAddress[0])
				{
					LogPrint (eLogError, "UPnP: GetExternalIPAddress() failed.");
					return;
				}
			}
		}
		else
		{
			LogPrint (eLogError, "UPnP: GetValidIGD() failed.");
			return;
		}

		// UPnP discovered
		LogPrint (eLogDebug, "UPnP: ExternalIPAddress is ", m_externalIPAddress);
		i2p::context.UpdateAddress (boost::asio::ip::address::from_string (m_externalIPAddress));
		// port mapping
		PortMapping ();
	}

	void UPnP::PortMapping ()
	{
		const auto& a = context.GetRouterInfo().GetAddresses();
		for (const auto& address : a)
		{
			if (!address->host.is_v6 ())
			TryPortMapping (address);
		}
		m_Timer.expires_from_now (boost::posix_time::minutes(20));	// every 20 minutes
		m_Timer.async_wait ([this](const boost::system::error_code& ecode)
		{
			if (ecode != boost::asio::error::operation_aborted)
			PortMapping ();
		});

	}

	void UPnP::CloseMapping ()
	{
		const auto& a = context.GetRouterInfo().GetAddresses();
		for (const auto& address : a)
		{
			if (!address->host.is_v6 ())
			CloseMapping (address);
		}
	}

	void UPnP::TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
	{
		std::string strType (GetProto (address)), strPort (std::to_string (address->port));
		int r;
		std::string strDesc; i2p::config::GetOption("upnp.name", strDesc);
#ifdef UPNPDISCOVER_SUCCESS
		r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0");
#else
		r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0);
#endif
		if (r!=UPNPCOMMAND_SUCCESS)
		{
			LogPrint (eLogError, "UPnP: AddPortMapping (", m_NetworkAddr, ":", strPort, ") failed with code ", r);
			return;
		}
		else
		{
			LogPrint (eLogDebug, "UPnP: Port Mapping successful. (", m_NetworkAddr ,":", strPort, " type ", strType, " -> ", m_externalIPAddress ,":", strPort ,")");
			return;
		}
	}

	void UPnP::CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
	{
		std::string strType (GetProto (address)), strPort (std::to_string (address->port));
		int r = 0;
		r = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
		LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r);
	}

	void UPnP::Close ()
	{
		freeUPNPDevlist (m_Devlist);
		m_Devlist = 0;
		FreeUPNPUrls (&m_upnpUrls);
	}

	std::string UPnP::GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address)
	{
		switch (address->transportStyle)
		{
			case i2p::data::RouterInfo::eTransportNTCP:
			return "TCP";
			break;
			case i2p::data::RouterInfo::eTransportSSU:
			default:
			return "UDP";
		}
	}
}
}
#else /* USE_UPNP */
namespace i2p {
namespace transport {
}
}
#endif /* USE_UPNP */
<commit_msg>ignore unpublished addresses<commit_after>#ifdef USE_UPNP
#include <string>
#include <thread>

#include <boost/thread/thread.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include "Log.h"

#include "RouterContext.h"
#include "UPnP.h"
#include "NetDb.hpp"
#include "util.h"
#include "RouterInfo.h"
#include "Config.h"

#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>

namespace i2p
{
namespace transport
{
	UPnP::UPnP () : m_IsRunning(false), m_Thread (nullptr), m_Timer (m_Service)
	{
	}

	void UPnP::Stop ()
	{
		if (m_IsRunning)
		{
			LogPrint(eLogInfo, "UPnP: stopping");
			m_IsRunning = false;
			m_Timer.cancel ();
			m_Service.stop ();
			if (m_Thread)
			{
				m_Thread->join ();
				m_Thread.reset (nullptr);
			}
			CloseMapping ();
			Close ();
		}
	}

	void UPnP::Start()
	{
		m_IsRunning = true;
		LogPrint(eLogInfo, "UPnP: starting");
		m_Service.post (std::bind (&UPnP::Discover, this));
		std::unique_lock<std::mutex> l(m_StartedMutex);
		m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this)));
		m_Started.wait_for (l, std::chrono::seconds (5)); // 5 seconds maximum
	}

	UPnP::~UPnP ()
	{
		Stop ();
	}

	void UPnP::Run ()
	{
		while (m_IsRunning)
		{
			try
			{
				m_Service.run ();
				// Discover failed
				break; // terminate the thread
			}
			catch (std::exception& ex)
			{
				LogPrint (eLogError, "UPnP: runtime exception: ", ex.what ());
				PortMapping ();
			}
		}
	}

	void UPnP::Discover ()
	{
#if MINIUPNPC_API_VERSION >= 14
		int nerror = 0;
		m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror);
#elif ( MINIUPNPC_API_VERSION >= 8 || defined(UPNPDISCOVER_SUCCESS) )
		int nerror = 0;
		m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror);
#else
		m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0);
#endif
		{
			// notify satrting thread
			std::unique_lock<std::mutex> l(m_StartedMutex);
			m_Started.notify_all ();
		}

		int r;
		r = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
		if (r == 1)
		{
			r = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
			if(r != UPNPCOMMAND_SUCCESS)
			{
				LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress() returned ", r);
				return;
			}
			else
			{
				if (!m_externalIPAddress[0])
				{
					LogPrint (eLogError, "UPnP: GetExternalIPAddress() failed.");
					return;
				}
			}
		}
		else
		{
			LogPrint (eLogError, "UPnP: GetValidIGD() failed.");
			return;
		}

		// UPnP discovered
		LogPrint (eLogDebug, "UPnP: ExternalIPAddress is ", m_externalIPAddress);
		i2p::context.UpdateAddress (boost::asio::ip::address::from_string (m_externalIPAddress));
		// port mapping
		PortMapping ();
	}

	void UPnP::PortMapping ()
	{
		const auto& a = context.GetRouterInfo().GetAddresses();
		for (const auto& address : a)
		{
			if (!address->host.is_v6 () && address->port)
				TryPortMapping (address);
		}
		m_Timer.expires_from_now (boost::posix_time::minutes(20));	// every 20 minutes
		m_Timer.async_wait ([this](const boost::system::error_code& ecode)
		{
			if (ecode != boost::asio::error::operation_aborted)
			PortMapping ();
		});

	}

	void UPnP::CloseMapping ()
	{
		const auto& a = context.GetRouterInfo().GetAddresses();
		for (const auto& address : a)
		{
			if (!address->host.is_v6 () && address->port)
			CloseMapping (address);
		}
	}

	void UPnP::TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
	{
		std::string strType (GetProto (address)), strPort (std::to_string (address->port));
		int r;
		std::string strDesc; i2p::config::GetOption("upnp.name", strDesc);
#ifdef UPNPDISCOVER_SUCCESS
		r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0");
#else
		r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0);
#endif
		if (r!=UPNPCOMMAND_SUCCESS)
		{
			LogPrint (eLogError, "UPnP: AddPortMapping (", m_NetworkAddr, ":", strPort, ") failed with code ", r);
			return;
		}
		else
		{
			LogPrint (eLogDebug, "UPnP: Port Mapping successful. (", m_NetworkAddr ,":", strPort, " type ", strType, " -> ", m_externalIPAddress ,":", strPort ,")");
			return;
		}
	}

	void UPnP::CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
	{
		std::string strType (GetProto (address)), strPort (std::to_string (address->port));
		int r = 0;
		r = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
		LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r);
	}

	void UPnP::Close ()
	{
		freeUPNPDevlist (m_Devlist);
		m_Devlist = 0;
		FreeUPNPUrls (&m_upnpUrls);
	}

	std::string UPnP::GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address)
	{
		switch (address->transportStyle)
		{
			case i2p::data::RouterInfo::eTransportNTCP:
			return "TCP";
			break;
			case i2p::data::RouterInfo::eTransportSSU:
			default:
			return "UDP";
		}
	}
}
}
#else /* USE_UPNP */
namespace i2p {
namespace transport {
}
}
#endif /* USE_UPNP */
<|endoftext|>


<commit_before>#include "QuadKey.hpp"
#include "builders/BuilderContext.hpp"
#include "builders/terrain/TerraBuilder.hpp"
#include "entities/Way.hpp"
#include "entities/Area.hpp"

#include <boost/test/unit_test.hpp>

#include "test_utils/DependencyProvider.hpp"
#include "test_utils/ElementUtils.hpp"

using namespace utymap;
using namespace utymap::builders;
using namespace utymap::entities;
using namespace utymap::math;

namespace {
    const std::string stylesheet =
        "canvas|z1-16 { grid-cell-size: 1%; layer-priority: road; ele-noise-freq: 0.05; color-noise-freq: 0.1; color:gradient(red); max-area: 5%;"
        "road-ele-noise-freq: 0.05; road-color-noise-freq: 0.1; road-color:gradient(red); road-max-area: 5%;}"
        "area|z1[landuse=commercial] { builders:terrain; terrain-layer:road; }"

        "way|z16[highway] { builders:terrain; terrain-layer:road; }"
        "way|z16[layer<0] { level: eval(\"tag('layer')\"); }";

    struct Builders_Terrain_TerraBuilderFixture
    {
        DependencyProvider dependencyProvider;
        std::unique_ptr<BuilderContext> context = nullptr;

        std::unique_ptr<TerraBuilder> create(const QuadKey& quadKey, std::function<void(const utymap::math::Mesh&)> meshCallback)
        {
            context = utymap::utils::make_unique<BuilderContext>(quadKey,
                                                                 *dependencyProvider.getStyleProvider(stylesheet),
                                                                 *dependencyProvider.getStringTable(),
                                                                 *dependencyProvider.getElevationProvider(),
                                                                 meshCallback, nullptr);
            return utymap::utils::make_unique<TerraBuilder>(*context);
        }
    };
}

BOOST_FIXTURE_TEST_SUITE(Builders_Terrain_TerraBuilder, Builders_Terrain_TerraBuilderFixture)

BOOST_AUTO_TEST_CASE(GivenArea_WhenComplete_ThenSurfaceMeshIsNotEmpty)
{
    bool isCalled = false;
    auto terraBuilder = create(QuadKey(1, 0, 0), [&](const Mesh& mesh) {
        if (mesh.name != "terrain_surface") return;
        BOOST_CHECK_GT(mesh.vertices.size(), 0);
        BOOST_CHECK_GT(mesh.triangles.size(), 0);
        isCalled = true;
    });
    ElementUtils::createElement<Area>(*dependencyProvider.getStringTable(), 0,
            { { "landuse", "commercial" } },
            { { 0, 0 }, { 20, 0 }, { 20, 20 }, { 0, 20 } })
        .accept(*terraBuilder);

    terraBuilder->complete();

    BOOST_CHECK(isCalled);
}

BOOST_AUTO_TEST_CASE(GivenOneTunnelConnectedWithTwoSteps_WhenComplete_ThenExteriorMeshHasExpectedGeometry)
{
    bool isCalled = false;
    auto terraBuilder = create(QuadKey(16, 35202, 21492), [&](const Mesh& mesh) {
        if (mesh.name != "terrain_exterior") return;
        // TODO
        isCalled = true;
    });
    ElementUtils::createElement<Way>(*dependencyProvider.getStringTable(), 48840561,
             { { "highway", "footway" }, {"layer", "-1"} },
             { { 52.5196429, 13.3737519 }, { 52.519642, 13.3731909}, { 52.5196415, 13.372909 } })
         .accept(*terraBuilder);
    ElementUtils::createElement<Way>(*dependencyProvider.getStringTable(), 421618241,
             { { "highway", "steps" }, { "incline", "up"} },
             { { 52.5196415, 13.372909 }, { 52.5196413, 13.372696 } })
          .accept(*terraBuilder);
    ElementUtils::createElement<Way>(*dependencyProvider.getStringTable(), 421618243,
             { { "highway", "steps" }, { "incline", "up"} },
             { { 52.5196429, 13.3737519 }, { 52.5196438, 13.3739644 } })
          .accept(*terraBuilder);

    terraBuilder->complete();

    BOOST_CHECK(isCalled);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>core: disable unit test for missing functionality<commit_after>#include "QuadKey.hpp"
#include "builders/BuilderContext.hpp"
#include "builders/terrain/TerraBuilder.hpp"
#include "entities/Way.hpp"
#include "entities/Area.hpp"

#include <boost/test/unit_test.hpp>

#include "test_utils/DependencyProvider.hpp"
#include "test_utils/ElementUtils.hpp"

using namespace utymap;
using namespace utymap::builders;
using namespace utymap::entities;
using namespace utymap::math;

const bool TerrainLevelImplemented = false;

namespace {
    const std::string stylesheet =
        "canvas|z1-16 { grid-cell-size: 1%; layer-priority: road; ele-noise-freq: 0.05; color-noise-freq: 0.1; color:gradient(red); max-area: 5%;"
        "road-ele-noise-freq: 0.05; road-color-noise-freq: 0.1; road-color:gradient(red); road-max-area: 5%;}"
        "area|z1[landuse=commercial] { builders:terrain; terrain-layer:road; }"

        "way|z16[highway] { builders:terrain; terrain-layer:road; }"
        "way|z16[layer<0] { level: eval(\"tag('layer')\"); }";

    struct Builders_Terrain_TerraBuilderFixture
    {
        DependencyProvider dependencyProvider;
        std::unique_ptr<BuilderContext> context = nullptr;

        std::unique_ptr<TerraBuilder> create(const QuadKey& quadKey, std::function<void(const utymap::math::Mesh&)> meshCallback)
        {
            context = utymap::utils::make_unique<BuilderContext>(quadKey,
                                                                 *dependencyProvider.getStyleProvider(stylesheet),
                                                                 *dependencyProvider.getStringTable(),
                                                                 *dependencyProvider.getElevationProvider(),
                                                                 meshCallback, nullptr);
            return utymap::utils::make_unique<TerraBuilder>(*context);
        }
    };
}

BOOST_FIXTURE_TEST_SUITE(Builders_Terrain_TerraBuilder, Builders_Terrain_TerraBuilderFixture)

BOOST_AUTO_TEST_CASE(GivenArea_WhenComplete_ThenSurfaceMeshIsNotEmpty)
{
    bool isCalled = false;
    auto terraBuilder = create(QuadKey(1, 0, 0), [&](const Mesh& mesh) {
        if (mesh.name != "terrain_surface") return;
        BOOST_CHECK_GT(mesh.vertices.size(), 0);
        BOOST_CHECK_GT(mesh.triangles.size(), 0);
        isCalled = true;
    });
    ElementUtils::createElement<Area>(*dependencyProvider.getStringTable(), 0,
            { { "landuse", "commercial" } },
            { { 0, 0 }, { 20, 0 }, { 20, 20 }, { 0, 20 } })
        .accept(*terraBuilder);

    terraBuilder->complete();

    BOOST_CHECK(isCalled);
}

BOOST_AUTO_TEST_CASE(GivenOneTunnelConnectedWithTwoSteps_WhenComplete_ThenExteriorMeshHasExpectedGeometry,
   * boost::unit_test::enable_if<TerrainLevelImplemented>())
{
    bool isCalled = false;
    auto terraBuilder = create(QuadKey(16, 35202, 21492), [&](const Mesh& mesh) {
        if (mesh.name != "terrain_exterior") return;
        // TODO
        isCalled = true;
    });
    ElementUtils::createElement<Way>(*dependencyProvider.getStringTable(), 48840561,
             { { "highway", "footway" }, {"layer", "-1"} },
             { { 52.5196429, 13.3737519 }, { 52.519642, 13.3731909}, { 52.5196415, 13.372909 } })
         .accept(*terraBuilder);
    ElementUtils::createElement<Way>(*dependencyProvider.getStringTable(), 421618241,
             { { "highway", "steps" }, { "incline", "up"} },
             { { 52.5196415, 13.372909 }, { 52.5196413, 13.372696 } })
          .accept(*terraBuilder);
    ElementUtils::createElement<Way>(*dependencyProvider.getStringTable(), 421618243,
             { { "highway", "steps" }, { "incline", "up"} },
             { { 52.5196429, 13.3737519 }, { 52.5196438, 13.3739644 } })
          .accept(*terraBuilder);

    terraBuilder->complete();

    BOOST_CHECK(isCalled);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2013 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */

#include "joynr/AbstractJoynrProvider.h"
#include "joynr/IAttributeListener.h"
#include "joynr/IBroadcastListener.h"

namespace joynr
{

AbstractJoynrProvider::AbstractJoynrProvider()
        : providerQos(), lock(), attributeListeners(), broadcastListeners(), broadcastFilters()
{
}

AbstractJoynrProvider::~AbstractJoynrProvider()
{
    // Delete all attribute listeners
    for (auto& mapEntry : attributeListeners) {
        const std::vector<IAttributeListener*>& listeners(mapEntry.second);
        for (IAttributeListener* listener : listeners) {
            delete listener;
        }
    }
}

types::ProviderQos AbstractJoynrProvider::getProviderQos() const
{
    return providerQos;
}

void AbstractJoynrProvider::registerAttributeListener(const std::string& attributeName,
                                                      IAttributeListener* attributeListener)
{
    WriteLocker locker(lock);
    attributeListeners[attributeName].push_back(attributeListener);
}

void AbstractJoynrProvider::unregisterAttributeListener(const std::string& attributeName,
                                                        IAttributeListener* attributeListener)
{
    WriteLocker locker(lock);
    std::vector<IAttributeListener*>& listeners = attributeListeners[attributeName];

    // Find and delete the attribute listener
    auto it = listeners.begin();
    while (it != listeners.end()) {
        if (*it == attributeListener) {
            IAttributeListener* listener = *it;
            it = listeners.erase(it);
            delete listener;
        } else {
            ++it;
        }
    }
}

void AbstractJoynrProvider::onAttributeValueChanged(const std::string& attributeName,
                                                    const Variant& value)
{
    ReadLocker locker(lock);

    const std::vector<IAttributeListener*>& listeners = attributeListeners[attributeName];

    // Inform all the attribute listeners for this attribute
    for (IAttributeListener* listener : listeners) {
        listener->attributeValueChanged(value);
    }
}

void AbstractJoynrProvider::registerBroadcastListener(const std::string& broadcastName,
                                                      IBroadcastListener* broadcastListener)
{
    WriteLocker locker(lock);
    broadcastListeners[broadcastName].push_back(broadcastListener);
}

void AbstractJoynrProvider::unregisterBroadcastListener(const std::string& broadcastName,
                                                        IBroadcastListener* broadcastListener)
{
    WriteLocker locker(lock);
    std::vector<IBroadcastListener*>& listeners = broadcastListeners[broadcastName];

    auto listenerIt = std::find(listeners.cbegin(), listeners.cend(), broadcastListener);
    assert(listenerIt != listeners.cend());
    delete *listenerIt;
    listeners.erase(listenerIt);
}

void AbstractJoynrProvider::fireBroadcast(const std::string& broadcastName,
                                          const std::vector<Variant>& values)
{
    ReadLocker locker(lock);

    const std::vector<IBroadcastListener*>& listeners = broadcastListeners[broadcastName];

    // Inform all the broadcast listeners for this broadcast
    for (IBroadcastListener* listener : listeners) {
        auto broadcastFiletersIterator = broadcastFilters.find(broadcastName);
        if (broadcastFiletersIterator != broadcastFilters.end()) {
            listener->broadcastOccurred(values, broadcastFiletersIterator->second);
        } else {
            listener->broadcastOccurred(values, std::vector<std::shared_ptr<IBroadcastFilter>>());
        }
    }
}

void AbstractJoynrProvider::addBroadcastFilter(std::shared_ptr<IBroadcastFilter> filter)
{
    std::map<std::string, std::vector<std::shared_ptr<IBroadcastFilter>>>::iterator it =
            broadcastFilters.find(filter->getName());

    if (it != broadcastFilters.end()) {
        it->second.push_back(filter);
    } else {
        broadcastFilters.insert(std::make_pair(
                filter->getName(), std::vector<std::shared_ptr<IBroadcastFilter>>({filter})));
    }
}

} // namespace joynr
<commit_msg>[C++] Cleanup handling of subscriptionListeners in AbstractJoynrProvider<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2013 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */

#include "joynr/AbstractJoynrProvider.h"
#include "joynr/IAttributeListener.h"
#include "joynr/IBroadcastListener.h"

namespace joynr
{

AbstractJoynrProvider::AbstractJoynrProvider()
        : providerQos(), lock(), attributeListeners(), broadcastListeners(), broadcastFilters()
{
}

AbstractJoynrProvider::~AbstractJoynrProvider()
{
    // Delete all attribute listeners
    for (auto& mapEntry : attributeListeners) {
        const std::vector<IAttributeListener*>& listeners(mapEntry.second);
        for (IAttributeListener* listener : listeners) {
            delete listener;
        }
    }
}

types::ProviderQos AbstractJoynrProvider::getProviderQos() const
{
    return providerQos;
}

void AbstractJoynrProvider::registerAttributeListener(const std::string& attributeName,
                                                      IAttributeListener* attributeListener)
{
    WriteLocker locker(lock);
    attributeListeners[attributeName].push_back(attributeListener);
}

void AbstractJoynrProvider::unregisterAttributeListener(const std::string& attributeName,
                                                        IAttributeListener* attributeListener)
{
    WriteLocker locker(lock);
    std::vector<IAttributeListener*>& listeners = attributeListeners[attributeName];

    auto listenerIt = std::find(listeners.cbegin(), listeners.cend(), attributeListener);
    assert(listenerIt != listeners.cend());
    delete *listenerIt;
    listeners.erase(listenerIt);

    if (listeners.empty()) {
        attributeListeners.erase(attributeName);
    }
}

void AbstractJoynrProvider::onAttributeValueChanged(const std::string& attributeName,
                                                    const Variant& value)
{
    ReadLocker locker(lock);

    if (attributeListeners.find(attributeName) != attributeListeners.cend()) {
        const std::vector<IAttributeListener*>& listeners = attributeListeners[attributeName];

        // Inform all the attribute listeners for this attribute
        for (IAttributeListener* listener : listeners) {
            listener->attributeValueChanged(value);
        }
    }
}

void AbstractJoynrProvider::registerBroadcastListener(const std::string& broadcastName,
                                                      IBroadcastListener* broadcastListener)
{
    WriteLocker locker(lock);
    broadcastListeners[broadcastName].push_back(broadcastListener);
}

void AbstractJoynrProvider::unregisterBroadcastListener(const std::string& broadcastName,
                                                        IBroadcastListener* broadcastListener)
{
    WriteLocker locker(lock);
    std::vector<IBroadcastListener*>& listeners = broadcastListeners[broadcastName];

    auto listenerIt = std::find(listeners.cbegin(), listeners.cend(), broadcastListener);
    assert(listenerIt != listeners.cend());
    delete *listenerIt;
    listeners.erase(listenerIt);

    if (listeners.empty()) {
        broadcastListeners.erase(broadcastName);
    }
}

void AbstractJoynrProvider::fireBroadcast(const std::string& broadcastName,
                                          const std::vector<Variant>& values)
{
    ReadLocker locker(lock);

    const std::vector<IBroadcastListener*>& listeners = broadcastListeners[broadcastName];

    // Inform all the broadcast listeners for this broadcast
    for (IBroadcastListener* listener : listeners) {
        auto broadcastFiletersIterator = broadcastFilters.find(broadcastName);
        if (broadcastFiletersIterator != broadcastFilters.end()) {
            listener->broadcastOccurred(values, broadcastFiletersIterator->second);
        } else {
            listener->broadcastOccurred(values, std::vector<std::shared_ptr<IBroadcastFilter>>());
        }
    }
}

void AbstractJoynrProvider::addBroadcastFilter(std::shared_ptr<IBroadcastFilter> filter)
{
    std::map<std::string, std::vector<std::shared_ptr<IBroadcastFilter>>>::iterator it =
            broadcastFilters.find(filter->getName());

    if (it != broadcastFilters.end()) {
        it->second.push_back(filter);
    } else {
        broadcastFilters.insert(std::make_pair(
                filter->getName(), std::vector<std::shared_ptr<IBroadcastFilter>>({filter})));
    }
}

} // namespace joynr
<|endoftext|>


<commit_before>/*
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

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

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "propertywidgetcontainer.h"
#include "propertywidgetitem.h"
#include "propertywidgetitemnewcustomproperty.h"
#include "core/gluonobject.h"

#include <selectionmanager.h>
#include <objectmanager.h>
#include <engine/gameobject.h>
#include <models/models.h>
#include <models/scenemodel.h>

#include <KIcon>
#include <KLocalizedString>
#include <KMessageBox>
#include <ksqueezedtextlabel.h>

#include <QtGui/QGridLayout>
#include <QtGui/QBoxLayout>
#include <QtGui/QToolButton>
#include <QtGui/QCheckBox>
#include <QtGui/QMenu>
#include <QtCore/QHash>
#include <QtCore/QMetaProperty>
#include <QtCore/QStringBuilder>
#include <QtCore/QTimer>
#include <QtCore/QDebug>

namespace GluonCreator
{
    class PropertyWidgetContainer::PropertyWidgetContainerPrivate
    {
        public:
            PropertyWidgetContainerPrivate( PropertyWidgetContainer* parent )
                : expanded( true )
                , enabled( true )
                , containerWidget( 0 )
                , containerLayout( 0 )
                , expander( 0 )
                , enabler( 0 )
                , menuButton( 0 )
                , newCustomProp( 0 )
            {
                this->parent = parent;
                menu = new QMenu( parent );

                // The widget used for the heading
                QFrame* titleWidget = new QFrame( parent );
                titleWidget->setFrameShape( QFrame::StyledPanel );
                titleWidget->setFrameShadow( QFrame::Raised );
                parent->layout()->addWidget( titleWidget );

                QHBoxLayout* titleLayout = new QHBoxLayout();
                titleLayout->setSpacing( 0 );
                titleLayout->setContentsMargins( 0, 0, 0, 0 );
                titleWidget->setLayout( titleLayout );

                expander = new QToolButton( titleWidget );
                expander->setAutoRaise( true );
                expander->setArrowType( Qt::DownArrow );
                connect( expander, SIGNAL( clicked( bool ) ), parent, SLOT( toggleExpanded() ) );
                titleLayout->addWidget( expander );

                enabler = new QCheckBox( titleWidget );
                enabler->setText( title );
                enabler->setChecked( enabled );
                connect( enabler, SIGNAL( toggled( bool ) ), parent, SLOT( setEnabled( bool ) ) );
                titleLayout->addWidget( enabler );

                menuButton = new QToolButton( titleWidget );
                menuButton->setIcon( KIcon( "preferences-other" ) );
                menuButton->setAutoRaise( true );
                menuButton->setPopupMode( QToolButton::InstantPopup );
                menuButton->setMenu( menu );
                titleLayout->addWidget( menuButton );

                // The widget used for containing the children
                containerWidget = new QWidget( parent );
                containerLayout = new QGridLayout();
                containerLayout->setSpacing( 0 );
                containerLayout->setContentsMargins( 2, 0, 0, 0 );
                containerWidget->setLayout( containerLayout );
                containerLayout->setColumnStretch( 0, 1 );
                containerLayout->setColumnStretch( 1, 3 );
                parent->layout()->addWidget( containerWidget );
            }
            ~PropertyWidgetContainerPrivate()
            {
            }

            /**
             * Sanitize the name according to the camelCasing
             * - Make first letter upper case
             * - Split at upper-case letters
             * - Add space between those indicated words
             * @par fixThis A string which needs fixing
             * @return The fixified string
             */
            QString humanifyString( QString fixThis );

            PropertyWidgetContainer* parent;
            GluonCore::GluonObject* object;
            void appendMetaObject( QObject* object );
            void addPropertyItem( QString name, PropertyWidgetItem* item );

            bool expanded;
            bool enabled;
            QString title;

            QWidget* containerWidget;
            QGridLayout* containerLayout;
            QHash<QString, QWidget*> items;

            QToolButton* expander;
            QCheckBox* enabler;
            QToolButton* menuButton;

            QMenu* menu;

            GluonCreator::PropertyWidgetItemNewCustomProperty* newCustomProp;
    };
}

using namespace GluonCreator;

PropertyWidgetContainer::PropertyWidgetContainer( GluonCore::GluonObject* theObject, QWidget* parent, Qt::WindowFlags f )
    : QWidget( parent, f )
{
    // Create a base layout to add our two children to...
    QVBoxLayout* layout = new QVBoxLayout( this );
    layout->setSpacing( 0 );
    layout->setContentsMargins( 0, 0, 0, 0 );
    setLayout( layout );

    d = new PropertyWidgetContainerPrivate( this );
    setObject( theObject );
}

PropertyWidgetContainer::~PropertyWidgetContainer()
{
    delete d;
}

void PropertyWidgetContainer::setObject( GluonCore::GluonObject* theObject )
{
    d->object = theObject;

    QString classname( theObject->metaObject()->className() );
    classname = classname.right( classname.length() - classname.lastIndexOf( ':' ) - 1 );
    setTitle( d->humanifyString( classname ) );

    if( !theObject->property( "enabled" ).isNull() )
        setEnabled( theObject->property( "enabled" ).value<bool>() );
    if( !theObject->property( "expanded" ).isNull() )
        setExpanded( theObject->property( "expanded" ).value<bool>() );
    connect( this, SIGNAL( propertyChanged( QObject*, QString, QVariant, QVariant ) ), parentWidget(), SIGNAL( propertyChanged( QObject*, QString, QVariant, QVariant ) ) );

    // Manually add the name and description widgets, as we wish to handle those a little differently
    PropertyWidgetItem* nameWidget = PropertyWidgetItemFactory::instance()->create( theObject, "QString", parentWidget() );
    nameWidget->setEditObject( theObject );
    nameWidget->setEditProperty( "name" );
    d->addPropertyItem( "name", nameWidget );

    PropertyWidgetItem* descriptionWidget = PropertyWidgetItemFactory::instance()->create( theObject, "QString", parentWidget() );
    descriptionWidget->setEditObject( theObject );
    descriptionWidget->setEditProperty( "description" );
    d->addPropertyItem( "description", descriptionWidget );

    QFrame* separator = new QFrame( this );
    separator->setFrameShape( QFrame::HLine );
    d->containerLayout->addWidget( separator, d->containerLayout->rowCount(), 0, 1, 2 );

    // Set up us the menu...
    QAction* customPropAction = new QAction( this );
    customPropAction->setText( i18n( "Add Custom Property..." ) );
    connect( customPropAction, SIGNAL( triggered( bool ) ), this, SLOT( addPropertyTriggered() ) );
    d->menu->addAction( customPropAction );
    d->menu->addSeparator();
    if( classname != QString( "GameObject" ) )
    {
        // Don't show moving up and down stuff for the GameObject
        QAction* upAction = new QAction( this );
        upAction->setText( i18n( "Move Up" ) );
        connect( upAction, SIGNAL( triggered( bool ) ), this, SLOT( upTriggered() ) );
        d->menu->addAction( upAction );
        QAction* downAction = new QAction( this );
        downAction->setText( i18n( "Move Down" ) );
        connect( downAction, SIGNAL( triggered( bool ) ), this, SLOT( downTriggered() ) );
        d->menu->addAction( downAction );
        d->menu->addSeparator();
    }
    if( classname != QString( "GameProject" ) )
    {
        QAction* delAction = new QAction( this );
        delAction->setText( i18n( "Delete" ) );
        connect( delAction, SIGNAL( triggered( bool ) ), this, SLOT( delTriggered() ) );
        d->menu->addAction( delAction );
    }

    d->appendMetaObject( theObject );
}

void
PropertyWidgetContainer::upTriggered()
{

}

void
PropertyWidgetContainer::downTriggered()
{

}

void
PropertyWidgetContainer::delTriggered()
{
    if( KMessageBox::questionYesNo( this, i18n( "Are you sure you wish to delete the item %1?" ).arg( d->object->fullyQualifiedName() ), i18n( "Delete Item?" ) ) == KMessageBox::Yes )
    {
        GluonCore::GluonObject* theParent = qobject_cast<GluonCore::GluonObject*>( d->object->parent() );
        if( theParent )
            theParent->removeChild( d->object );

        SelectionManager::instance()->clearSelection();
        GluonEngine::GameObject* gobj = qobject_cast<GluonEngine::GameObject*>(d->object);
        if(gobj && gobj->parentGameObject())
        {
            Models::instance()->sceneModel()->deleteGameObject(gobj);
        }
        else
        {
            d->object->deleteLater();
            // Cause the property dock to update its view
            SelectionManager::SelectionList list;
            list.append( theParent );
            SelectionManager::instance()->setSelection( list );
        }
    }
}

void PropertyWidgetContainer::addPropertyTriggered()
{
    d->newCustomProp = new PropertyWidgetItemNewCustomProperty( this );
    connect( d->newCustomProp, SIGNAL( propertyCreated(GluonCore::GluonObject*,QString) ), this, SLOT( propertyCreated(GluonCore::GluonObject*,QString) ) );
    d->newCustomProp->createProperty( d->object );
}

void PropertyWidgetContainer::propertyCreated(GluonCore::GluonObject* propertyCreatedOn, QString createdPropertyName)
{
    QVariant propVal = propertyCreatedOn->property(createdPropertyName.toUtf8());
    PropertyWidgetItem* pwi = PropertyWidgetItemFactory::instance()->create( propertyCreatedOn, propVal.typeName(), parentWidget() );
    pwi->setEditObject( propertyCreatedOn );
    pwi->setEditProperty( createdPropertyName );
    d->addPropertyItem( createdPropertyName, pwi );
    d->newCustomProp->deleteLater();
    emit propertyChanged( propertyCreatedOn, createdPropertyName, propVal, propVal );
}

bool
PropertyWidgetContainer::expanded() const
{
    return d->expanded;
}

void
PropertyWidgetContainer::setExpanded( const bool& newExpanded )
{
    bool oldExpanded = d->expanded;
    d->expanded = newExpanded;

    // This is done to avoid polluting the GDL with unneeded data - the invalid QVariant removes the expanded property, because true is the default value
    if( !newExpanded )
        d->object->setProperty( "expanded", false );
    else
        d->object->setProperty( "expanded", QVariant() );

    if( newExpanded )
    {
        d->expander->setArrowType( Qt::DownArrow );
    }
    else
    {
        d->expander->setArrowType( Qt::RightArrow );
    }
    // This should be animated - need to experiment with the animation framework for that to be pretty ;)
    d->containerWidget->setVisible( newExpanded );

    emit propertyChanged( d->object, "expanded", oldExpanded, newExpanded );
}

void
PropertyWidgetContainer::toggleExpanded()
{
    setExpanded( !expanded() );
}

bool
PropertyWidgetContainer::enabled() const
{
    return d->enabled;
}

void
PropertyWidgetContainer::setEnabled( const bool& newEnabled )
{
    bool oldEnabled = d->enabled;
    d->enabled = newEnabled;
    if( d->enabled != d->object->property( "enabled" ).value<bool>() )
        d->object->setProperty( "enabled", newEnabled );
    if( d->enabler->isChecked() != newEnabled )
        d->enabler->setChecked( newEnabled );
    emit propertyChanged( d->object, "expanded", oldEnabled, newEnabled );
}

QString
PropertyWidgetContainer::title() const
{
    return d->title;
}

void
PropertyWidgetContainer::setTitle( const QString& newTitle )
{
    d->title = newTitle;
    d->enabler->setText( newTitle );
}

void
PropertyWidgetContainer::addDefaultMenuItems()
{
}

void
PropertyWidgetContainer::addMenuItem( QAction* menuItem )
{
    d->menu->addAction( menuItem );
}

void
PropertyWidgetContainer::removeMenuItem( QAction* menuItem )
{
    if( d->menu->actions().contains( menuItem ) )
        d->menu->removeAction( menuItem );
}

void
PropertyWidgetContainer::PropertyWidgetContainerPrivate::appendMetaObject( QObject* object )
{
    QString propertyName, propertyDescription;
    QVariant propertyValue;

    const QMetaObject* metaObject = object->metaObject();
    QMetaProperty metaProperty;

    int count = metaObject->propertyCount();
    for( int i = 0; i < count; ++i )
    {
        metaProperty = metaObject->property( i );

        // Guard against adding these, as we manually add them above, to ensure that they
        // are right at the top and have a little line under them and such... all pretty ;)
        // Also disregard enabled, as that is done by the checkbox above...
        propertyName = QString( metaProperty.name() );
        if( propertyName == QString( "objectName" ) || propertyName == QString( "name" ) || propertyName == QString( "description" ) || propertyName == QString( "expanded" ) || propertyName == QString( "enabled" ) )
            continue;

        PropertyWidgetItem* editWidget;
        if(!metaProperty.isEnumType())
        {
            editWidget = PropertyWidgetItemFactory::instance()->create( object, metaProperty.typeName(), parent->parentWidget() );
        }
        else
        {
            QMetaEnum enumerator = metaProperty.enumerator();
            if( enumerator.scope() != "Qt" )
                editWidget = PropertyWidgetItemFactory::instance()->create( object, enumerator.name(), parent->parentWidget() );
            else
                editWidget = PropertyWidgetItemFactory::instance()->create( object, metaProperty.typeName(), parent->parentWidget() );
        }

        editWidget->setEditObject( object );
        editWidget->setEditProperty( metaProperty.name() );

        addPropertyItem( metaProperty.name(), editWidget );
    }

    foreach( const QByteArray & propName, object->dynamicPropertyNames() )
    {
        QString thePropName( propName );
        // Don't show the expanded dynamic property - we make this one dynamic because
        // we don't want to pollute the API with this arguably very meta information
        if( thePropName == QString( "description" ) || thePropName == QString( "expanded" ) || thePropName == QString( "enabled" ) )
            continue;

        PropertyWidgetItem* editWidget = PropertyWidgetItemFactory::instance()->create( object, object->property( propName ).typeName(), parent->parentWidget() );
        editWidget->setEditObject( object );
        editWidget->setEditProperty( thePropName );

        addPropertyItem( thePropName, editWidget );
    }
}

void
PropertyWidgetContainer::PropertyWidgetContainerPrivate::addPropertyItem( QString name, PropertyWidgetItem* item )
{

    KSqueezedTextLabel* nameLabel = new KSqueezedTextLabel( parent );
    nameLabel->setAlignment( Qt::AlignLeft | Qt::AlignTop );
    nameLabel->setTextElideMode( Qt::ElideRight );
    nameLabel->setText( humanifyString( name ) );
    nameLabel->setToolTip( nameLabel->fullText() );

    item->setMinimumWidth( 150 );
    item->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
    // Yeah, looks a bit funny, but this makes it possible to connect to either the pwi container... or the pwi view ;)
    connect( item, SIGNAL( propertyChanged( QObject*, QString, QVariant, QVariant ) ), parent, SIGNAL( propertyChanged( QObject*, QString, QVariant, QVariant ) ) );

    int row = containerLayout->rowCount();
    containerLayout->addWidget( nameLabel, row, 0 );
    containerLayout->addWidget( item, row, 1 );

    items.insert( name, item );
}

QString
PropertyWidgetContainer::PropertyWidgetContainerPrivate::humanifyString( QString fixThis )
{
    QString fixedString;
    const int length = fixThis.size();
    for( int i = 0; i < length; ++i )
    {
        const QChar current = fixThis.at( i );
        if( i == 0 )
        {
            // Always upper-case the first word, whether it is or not...
            fixedString = current.toUpper();
        }
        else
        {
            if( current.isUpper() )
            {
                fixedString = fixedString % ' ' % current;
            }
            else
            {
                fixedString = fixedString % current;
            }
        }
    }
    return fixedString;
}
<commit_msg>Creator: Change the <..> lines for "..." in case project headers.<commit_after>/*
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

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

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "propertywidgetcontainer.h"
#include "propertywidgetitem.h"
#include "propertywidgetitemnewcustomproperty.h"
#include "core/gluonobject.h"

#include "selectionmanager.h"
#include "objectmanager.h"
#include "engine/gameobject.h"
#include "models/models.h"
#include "models/scenemodel.h"

#include <KIcon>
#include <KLocalizedString>
#include <KMessageBox>
#include <ksqueezedtextlabel.h>

#include <QtGui/QGridLayout>
#include <QtGui/QBoxLayout>
#include <QtGui/QToolButton>
#include <QtGui/QCheckBox>
#include <QtGui/QMenu>
#include <QtCore/QHash>
#include <QtCore/QMetaProperty>
#include <QtCore/QStringBuilder>
#include <QtCore/QTimer>
#include <QtCore/QDebug>

namespace GluonCreator
{
    class PropertyWidgetContainer::PropertyWidgetContainerPrivate
    {
        public:
            PropertyWidgetContainerPrivate( PropertyWidgetContainer* parent )
                : expanded( true )
                , enabled( true )
                , containerWidget( 0 )
                , containerLayout( 0 )
                , expander( 0 )
                , enabler( 0 )
                , menuButton( 0 )
                , newCustomProp( 0 )
            {
                this->parent = parent;
                menu = new QMenu( parent );

                // The widget used for the heading
                QFrame* titleWidget = new QFrame( parent );
                titleWidget->setFrameShape( QFrame::StyledPanel );
                titleWidget->setFrameShadow( QFrame::Raised );
                parent->layout()->addWidget( titleWidget );

                QHBoxLayout* titleLayout = new QHBoxLayout();
                titleLayout->setSpacing( 0 );
                titleLayout->setContentsMargins( 0, 0, 0, 0 );
                titleWidget->setLayout( titleLayout );

                expander = new QToolButton( titleWidget );
                expander->setAutoRaise( true );
                expander->setArrowType( Qt::DownArrow );
                connect( expander, SIGNAL( clicked( bool ) ), parent, SLOT( toggleExpanded() ) );
                titleLayout->addWidget( expander );

                enabler = new QCheckBox( titleWidget );
                enabler->setText( title );
                enabler->setChecked( enabled );
                connect( enabler, SIGNAL( toggled( bool ) ), parent, SLOT( setEnabled( bool ) ) );
                titleLayout->addWidget( enabler );

                menuButton = new QToolButton( titleWidget );
                menuButton->setIcon( KIcon( "preferences-other" ) );
                menuButton->setAutoRaise( true );
                menuButton->setPopupMode( QToolButton::InstantPopup );
                menuButton->setMenu( menu );
                titleLayout->addWidget( menuButton );

                // The widget used for containing the children
                containerWidget = new QWidget( parent );
                containerLayout = new QGridLayout();
                containerLayout->setSpacing( 0 );
                containerLayout->setContentsMargins( 2, 0, 0, 0 );
                containerWidget->setLayout( containerLayout );
                containerLayout->setColumnStretch( 0, 1 );
                containerLayout->setColumnStretch( 1, 3 );
                parent->layout()->addWidget( containerWidget );
            }
            ~PropertyWidgetContainerPrivate()
            {
            }

            /**
             * Sanitize the name according to the camelCasing
             * - Make first letter upper case
             * - Split at upper-case letters
             * - Add space between those indicated words
             * @par fixThis A string which needs fixing
             * @return The fixified string
             */
            QString humanifyString( QString fixThis );

            PropertyWidgetContainer* parent;
            GluonCore::GluonObject* object;
            void appendMetaObject( QObject* object );
            void addPropertyItem( QString name, PropertyWidgetItem* item );

            bool expanded;
            bool enabled;
            QString title;

            QWidget* containerWidget;
            QGridLayout* containerLayout;
            QHash<QString, QWidget*> items;

            QToolButton* expander;
            QCheckBox* enabler;
            QToolButton* menuButton;

            QMenu* menu;

            GluonCreator::PropertyWidgetItemNewCustomProperty* newCustomProp;
    };
}

using namespace GluonCreator;

PropertyWidgetContainer::PropertyWidgetContainer( GluonCore::GluonObject* theObject, QWidget* parent, Qt::WindowFlags f )
    : QWidget( parent, f )
{
    // Create a base layout to add our two children to...
    QVBoxLayout* layout = new QVBoxLayout( this );
    layout->setSpacing( 0 );
    layout->setContentsMargins( 0, 0, 0, 0 );
    setLayout( layout );

    d = new PropertyWidgetContainerPrivate( this );
    setObject( theObject );
}

PropertyWidgetContainer::~PropertyWidgetContainer()
{
    delete d;
}

void PropertyWidgetContainer::setObject( GluonCore::GluonObject* theObject )
{
    d->object = theObject;

    QString classname( theObject->metaObject()->className() );
    classname = classname.right( classname.length() - classname.lastIndexOf( ':' ) - 1 );
    setTitle( d->humanifyString( classname ) );

    if( !theObject->property( "enabled" ).isNull() )
        setEnabled( theObject->property( "enabled" ).value<bool>() );
    if( !theObject->property( "expanded" ).isNull() )
        setExpanded( theObject->property( "expanded" ).value<bool>() );
    connect( this, SIGNAL( propertyChanged( QObject*, QString, QVariant, QVariant ) ), parentWidget(), SIGNAL( propertyChanged( QObject*, QString, QVariant, QVariant ) ) );

    // Manually add the name and description widgets, as we wish to handle those a little differently
    PropertyWidgetItem* nameWidget = PropertyWidgetItemFactory::instance()->create( theObject, "QString", parentWidget() );
    nameWidget->setEditObject( theObject );
    nameWidget->setEditProperty( "name" );
    d->addPropertyItem( "name", nameWidget );

    PropertyWidgetItem* descriptionWidget = PropertyWidgetItemFactory::instance()->create( theObject, "QString", parentWidget() );
    descriptionWidget->setEditObject( theObject );
    descriptionWidget->setEditProperty( "description" );
    d->addPropertyItem( "description", descriptionWidget );

    QFrame* separator = new QFrame( this );
    separator->setFrameShape( QFrame::HLine );
    d->containerLayout->addWidget( separator, d->containerLayout->rowCount(), 0, 1, 2 );

    // Set up us the menu...
    QAction* customPropAction = new QAction( this );
    customPropAction->setText( i18n( "Add Custom Property..." ) );
    connect( customPropAction, SIGNAL( triggered( bool ) ), this, SLOT( addPropertyTriggered() ) );
    d->menu->addAction( customPropAction );
    d->menu->addSeparator();
    if( classname != QString( "GameObject" ) )
    {
        // Don't show moving up and down stuff for the GameObject
        QAction* upAction = new QAction( this );
        upAction->setText( i18n( "Move Up" ) );
        connect( upAction, SIGNAL( triggered( bool ) ), this, SLOT( upTriggered() ) );
        d->menu->addAction( upAction );
        QAction* downAction = new QAction( this );
        downAction->setText( i18n( "Move Down" ) );
        connect( downAction, SIGNAL( triggered( bool ) ), this, SLOT( downTriggered() ) );
        d->menu->addAction( downAction );
        d->menu->addSeparator();
    }
    if( classname != QString( "GameProject" ) )
    {
        QAction* delAction = new QAction( this );
        delAction->setText( i18n( "Delete" ) );
        connect( delAction, SIGNAL( triggered( bool ) ), this, SLOT( delTriggered() ) );
        d->menu->addAction( delAction );
    }

    d->appendMetaObject( theObject );
}

void
PropertyWidgetContainer::upTriggered()
{

}

void
PropertyWidgetContainer::downTriggered()
{

}

void
PropertyWidgetContainer::delTriggered()
{
    if( KMessageBox::questionYesNo( this, i18n( "Are you sure you wish to delete the item %1?" ).arg( d->object->fullyQualifiedName() ), i18n( "Delete Item?" ) ) == KMessageBox::Yes )
    {
        GluonCore::GluonObject* theParent = qobject_cast<GluonCore::GluonObject*>( d->object->parent() );
        if( theParent )
            theParent->removeChild( d->object );

        SelectionManager::instance()->clearSelection();
        GluonEngine::GameObject* gobj = qobject_cast<GluonEngine::GameObject*>(d->object);
        if(gobj && gobj->parentGameObject())
        {
            Models::instance()->sceneModel()->deleteGameObject(gobj);
        }
        else
        {
            d->object->deleteLater();
            // Cause the property dock to update its view
            SelectionManager::SelectionList list;
            list.append( theParent );
            SelectionManager::instance()->setSelection( list );
        }
    }
}

void PropertyWidgetContainer::addPropertyTriggered()
{
    d->newCustomProp = new PropertyWidgetItemNewCustomProperty( this );
    connect( d->newCustomProp, SIGNAL( propertyCreated(GluonCore::GluonObject*,QString) ), this, SLOT( propertyCreated(GluonCore::GluonObject*,QString) ) );
    d->newCustomProp->createProperty( d->object );
}

void PropertyWidgetContainer::propertyCreated(GluonCore::GluonObject* propertyCreatedOn, QString createdPropertyName)
{
    QVariant propVal = propertyCreatedOn->property(createdPropertyName.toUtf8());
    PropertyWidgetItem* pwi = PropertyWidgetItemFactory::instance()->create( propertyCreatedOn, propVal.typeName(), parentWidget() );
    pwi->setEditObject( propertyCreatedOn );
    pwi->setEditProperty( createdPropertyName );
    d->addPropertyItem( createdPropertyName, pwi );
    d->newCustomProp->deleteLater();
    emit propertyChanged( propertyCreatedOn, createdPropertyName, propVal, propVal );
}

bool
PropertyWidgetContainer::expanded() const
{
    return d->expanded;
}

void
PropertyWidgetContainer::setExpanded( const bool& newExpanded )
{
    bool oldExpanded = d->expanded;
    d->expanded = newExpanded;

    // This is done to avoid polluting the GDL with unneeded data - the invalid QVariant removes the expanded property, because true is the default value
    if( !newExpanded )
        d->object->setProperty( "expanded", false );
    else
        d->object->setProperty( "expanded", QVariant() );

    if( newExpanded )
    {
        d->expander->setArrowType( Qt::DownArrow );
    }
    else
    {
        d->expander->setArrowType( Qt::RightArrow );
    }
    // This should be animated - need to experiment with the animation framework for that to be pretty ;)
    d->containerWidget->setVisible( newExpanded );

    emit propertyChanged( d->object, "expanded", oldExpanded, newExpanded );
}

void
PropertyWidgetContainer::toggleExpanded()
{
    setExpanded( !expanded() );
}

bool
PropertyWidgetContainer::enabled() const
{
    return d->enabled;
}

void
PropertyWidgetContainer::setEnabled( const bool& newEnabled )
{
    bool oldEnabled = d->enabled;
    d->enabled = newEnabled;
    if( d->enabled != d->object->property( "enabled" ).value<bool>() )
        d->object->setProperty( "enabled", newEnabled );
    if( d->enabler->isChecked() != newEnabled )
        d->enabler->setChecked( newEnabled );
    emit propertyChanged( d->object, "expanded", oldEnabled, newEnabled );
}

QString
PropertyWidgetContainer::title() const
{
    return d->title;
}

void
PropertyWidgetContainer::setTitle( const QString& newTitle )
{
    d->title = newTitle;
    d->enabler->setText( newTitle );
}

void
PropertyWidgetContainer::addDefaultMenuItems()
{
}

void
PropertyWidgetContainer::addMenuItem( QAction* menuItem )
{
    d->menu->addAction( menuItem );
}

void
PropertyWidgetContainer::removeMenuItem( QAction* menuItem )
{
    if( d->menu->actions().contains( menuItem ) )
        d->menu->removeAction( menuItem );
}

void
PropertyWidgetContainer::PropertyWidgetContainerPrivate::appendMetaObject( QObject* object )
{
    QString propertyName, propertyDescription;
    QVariant propertyValue;

    const QMetaObject* metaObject = object->metaObject();
    QMetaProperty metaProperty;

    int count = metaObject->propertyCount();
    for( int i = 0; i < count; ++i )
    {
        metaProperty = metaObject->property( i );

        // Guard against adding these, as we manually add them above, to ensure that they
        // are right at the top and have a little line under them and such... all pretty ;)
        // Also disregard enabled, as that is done by the checkbox above...
        propertyName = QString( metaProperty.name() );
        if( propertyName == QString( "objectName" ) || propertyName == QString( "name" ) || propertyName == QString( "description" ) || propertyName == QString( "expanded" ) || propertyName == QString( "enabled" ) )
            continue;

        PropertyWidgetItem* editWidget;
        if(!metaProperty.isEnumType())
        {
            editWidget = PropertyWidgetItemFactory::instance()->create( object, metaProperty.typeName(), parent->parentWidget() );
        }
        else
        {
            QMetaEnum enumerator = metaProperty.enumerator();
            if( enumerator.scope() != "Qt" )
                editWidget = PropertyWidgetItemFactory::instance()->create( object, enumerator.name(), parent->parentWidget() );
            else
                editWidget = PropertyWidgetItemFactory::instance()->create( object, metaProperty.typeName(), parent->parentWidget() );
        }

        editWidget->setEditObject( object );
        editWidget->setEditProperty( metaProperty.name() );

        addPropertyItem( metaProperty.name(), editWidget );
    }

    foreach( const QByteArray & propName, object->dynamicPropertyNames() )
    {
        QString thePropName( propName );
        // Don't show the expanded dynamic property - we make this one dynamic because
        // we don't want to pollute the API with this arguably very meta information
        if( thePropName == QString( "description" ) || thePropName == QString( "expanded" ) || thePropName == QString( "enabled" ) )
            continue;

        PropertyWidgetItem* editWidget = PropertyWidgetItemFactory::instance()->create( object, object->property( propName ).typeName(), parent->parentWidget() );
        editWidget->setEditObject( object );
        editWidget->setEditProperty( thePropName );

        addPropertyItem( thePropName, editWidget );
    }
}

void
PropertyWidgetContainer::PropertyWidgetContainerPrivate::addPropertyItem( QString name, PropertyWidgetItem* item )
{

    KSqueezedTextLabel* nameLabel = new KSqueezedTextLabel( parent );
    nameLabel->setAlignment( Qt::AlignLeft | Qt::AlignTop );
    nameLabel->setTextElideMode( Qt::ElideRight );
    nameLabel->setText( humanifyString( name ) );
    nameLabel->setToolTip( nameLabel->fullText() );

    item->setMinimumWidth( 150 );
    item->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
    // Yeah, looks a bit funny, but this makes it possible to connect to either the pwi container... or the pwi view ;)
    connect( item, SIGNAL( propertyChanged( QObject*, QString, QVariant, QVariant ) ), parent, SIGNAL( propertyChanged( QObject*, QString, QVariant, QVariant ) ) );

    int row = containerLayout->rowCount();
    containerLayout->addWidget( nameLabel, row, 0 );
    containerLayout->addWidget( item, row, 1 );

    items.insert( name, item );
}

QString
PropertyWidgetContainer::PropertyWidgetContainerPrivate::humanifyString( QString fixThis )
{
    QString fixedString;
    const int length = fixThis.size();
    for( int i = 0; i < length; ++i )
    {
        const QChar current = fixThis.at( i );
        if( i == 0 )
        {
            // Always upper-case the first word, whether it is or not...
            fixedString = current.toUpper();
        }
        else
        {
            if( current.isUpper() )
            {
                fixedString = fixedString % ' ' % current;
            }
            else
            {
                fixedString = fixedString % current;
            }
        }
    }
    return fixedString;
}
<|endoftext|>


<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

/* End of file. */
<commit_msg>test svn access<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

/* End of file. */
<|endoftext|>


<commit_before>/***********************************************************************
    filename:   CEGUINode.cpp
    created:    18/8/2011
    author:     Paul D Turner

    purpose:    Implements the Node class
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
 *
 *   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 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.
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#   include "config.h"
#endif

#include "CEGUINode.h"

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
Node::Node():
    d_unclippedOuterRect(this, &Node::getUnclippedOuterRect_impl),
    d_unclippedInnerRect(this, &Node::getUnclippedInnerRect_impl)
{}

Node::~Node()
{}

Node::Node(const Node&):
    d_unclippedOuterRect(this, &Node::getUnclippedOuterRect_impl),
    d_unclippedInnerRect(this, &Node::getUnclippedInnerRect_impl)
{}

} // End of  CEGUI namespace section
<commit_msg>MOD: My file, mine!<commit_after>/***********************************************************************
    filename:   CEGUINode.cpp
    created:    18/8/2011
    author:     Martin Preisler

    purpose:    Implements the Node class
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
 *
 *   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 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.
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#   include "config.h"
#endif

#include "CEGUINode.h"

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
Node::Node():
    d_unclippedOuterRect(this, &Node::getUnclippedOuterRect_impl),
    d_unclippedInnerRect(this, &Node::getUnclippedInnerRect_impl)
{}

Node::~Node()
{}

Node::Node(const Node&):
    d_unclippedOuterRect(this, &Node::getUnclippedOuterRect_impl),
    d_unclippedInnerRect(this, &Node::getUnclippedInnerRect_impl)
{}

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>/*
Serial example program playing Conway's Game of Life.

Copyright 2013, 2014 Ilja Honkonen
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution.

* Neither the name of copyright holders nor the names of their contributors
  may be used to endorse or promote products derived from this software
  without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "array"
#include "cstdlib"
#include "iostream"

#include "gensimcell.hpp"

using namespace std;

/*
Variable that records whether
the cell is alive or not
*/
struct is_alive
{
	using data_type = bool;
};

/*
Variable that records the
number of cell's live neighbors
*/
struct live_neighbors
{
	using data_type = int;
};

/*
The cell type stored in the game grid
defined by the variables it holds
*/
using cell_t = gensimcell::Cell<
	is_alive,
	live_neighbors
>;

/*
Prints given game of life to standard output,
using 0 for live cells and . for dead cells.
*/
template<class Game_Grid> void print_game(const Game_Grid& grid)
{
	for (const auto& row: grid) {
		for (const auto& cell: row) {
			if (cell[is_alive()]) {
				cout << "0";
			} else {
				cout << ".";
			}
		}
		cout << endl;
	}
	cout << endl;
}

int main(int, char**)
{
	// the game grid
	constexpr size_t
		width = 6,
		height = 6;

	array<array<cell_t, width>, height> game_grid;

	// initialize the game with a glider at upper left
	for (auto& row: game_grid) {
		for (auto& cell: row) {
			cell[is_alive()] = false;
			cell[live_neighbors()] = 0;
		}
	}
	game_grid[1][2][is_alive()] = true;
	game_grid[2][3][is_alive()] = true;
	game_grid[3][3][is_alive()] = true;
	game_grid[3][2][is_alive()] = true;
	game_grid[3][1][is_alive()] = true;

	constexpr size_t max_turns = 4;
	for (size_t turn = 0; turn < max_turns; turn++) {

		print_game(game_grid);

		// collect live neighbor counts, use periodic boundaries
		for (size_t row_i = 0; row_i < game_grid.size(); row_i++)
		for (size_t cell_i = 0; cell_i < game_grid[row_i].size(); cell_i++) {

			cell_t& current_cell = game_grid[row_i][cell_i];

			for (auto row_offset: {size_t(1), size_t(0), width - 1})
			for (auto cell_offset: {size_t(1), size_t(0), height - 1}) {

				if (row_offset == 0 and cell_offset == 0) {
					continue;
				}

				const cell_t& neighbor
					= game_grid[
						(row_i + row_offset) % height
					][
						(cell_i + cell_offset) % width
					];

				if (neighbor[is_alive()]) {
					current_cell[live_neighbors()]++;
				}
			}
		}

		// set new state
		for (size_t row_i = 0; row_i < game_grid.size(); row_i++)
		for (size_t cell_i = 0; cell_i < game_grid[row_i].size(); cell_i++) {

			cell_t& cell = game_grid[row_i][cell_i];
			if (cell[live_neighbors()] == 3) {
				cell[is_alive()] = true;
			} else if (cell[live_neighbors()] != 2) {
				cell[is_alive()] = false;
			}
			cell[live_neighbors()] = 0;
		}
	}

	print_game(game_grid);

	return EXIT_SUCCESS;
}
<commit_msg>A few cosmetic improvements to serial GoL example.<commit_after>/*
Serial example program playing Conway's Game of Life.

Copyright 2013, 2014 Ilja Honkonen
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution.

* Neither the name of copyright holders nor the names of their contributors
  may be used to endorse or promote products derived from this software
  without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "array"
#include "cstdlib"
#include "iostream"

#include "gensimcell.hpp"

using namespace std;

/*
Variable that records whether
the cell is alive or not
*/
struct is_alive
{
	using data_type = bool;
};

/*
Variable that records the
number of cell's live neighbors
*/
struct live_neighbors
{
	using data_type = int;
};

/*
The cell type stored in the game grid
defined by the variables it holds
*/
using Cell_T = gensimcell::Cell<
	is_alive,
	live_neighbors
>;

/*
Prints given game of life to standard output,
using 0 for live cells and . for dead cells.
*/
template<class Game_Grid> void print_game(const Game_Grid& grid)
{
	for (const auto& row: grid) {
		for (const auto& cell: row) {
			if (cell[is_alive()]) {
				cout << "0";
			} else {
				cout << ".";
			}
		}
		cout << endl;
	}
	cout << endl;
}

int main(int, char**)
{
	// the game grid
	constexpr size_t
		width = 6,
		height = 6;

	array<array<Cell_T, width>, height> grid;

	// initialize the game with a glider at upper left
	for (auto& row: grid) {
		for (auto& cell: row) {
			cell[is_alive()] = false;
			cell[live_neighbors()] = 0;
		}
	}
	grid[1][2][is_alive()] = true;
	grid[2][3][is_alive()] = true;
	grid[3][3][is_alive()] = true;
	grid[3][2][is_alive()] = true;
	grid[3][1][is_alive()] = true;

	constexpr size_t max_turns = 4;
	for (size_t turn = 0; turn < max_turns; turn++) {

		print_game(grid);

		// collect live neighbor counts, use periodic boundaries
		for (size_t row_i = 0; row_i < grid.size(); row_i++)
		for (size_t cell_i = 0; cell_i < grid[row_i].size(); cell_i++) {

			auto& current_cell = grid[row_i][cell_i];

			for (auto row_offset: {size_t(1), size_t(0), width - 1})
			for (auto cell_offset: {size_t(1), size_t(0), height - 1}) {

				if (row_offset == 0 and cell_offset == 0) {
					continue;
				}

				const auto& neighbor
					= grid[
						(row_i + row_offset) % height
					][
						(cell_i + cell_offset) % width
					];

				if (neighbor[is_alive()]) {
					current_cell[live_neighbors()]++;
				}
			}
		}

		// set new state
		for (size_t row_i = 0; row_i < grid.size(); row_i++)
		for (size_t cell_i = 0; cell_i < grid[row_i].size(); cell_i++) {

			auto& cell = grid[row_i][cell_i];
			if (cell[live_neighbors()] == 3) {
				cell[is_alive()] = true;
			} else if (cell[live_neighbors()] != 2) {
				cell[is_alive()] = false;
			}
			cell[live_neighbors()] = 0;
		}
	}

	print_game(grid);

	return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>//===-- GBSMessageParse_Test.cpp --------------------------------*- C++ -*-===//
//
// This file is distributed uner the MIT license. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
///
//===----------------------------------------------------------------------===//
#include "NMEAParser.h"
#include "gtest/gtest.h"

#include <cstring>
#include <cmath>
#include <iostream>

#if 0
| N | Message |
|---+---------|
| 1 | Valid   |
| 2 | Invalid |
| 3 | Empty   |
#endif

namespace NMEA {
TEST(GBSMessageParse, Valid_Message) {
  const std::string RawMessage =
      "$GPGBS,235458.00,1.4,1.3,3.1,03,,-21.4,3.8*5B";

  NMEAHeader Header = {NMEA_TALKER_ID::GPS, NMEA_MESSAGE_TYPE::GBS, 1};

  time_t ExpectedTimestamp = 0;
  struct tm *TimeInfo;

  std::time(&ExpectedTimestamp);
  TimeInfo = gmtime(&ExpectedTimestamp);
  TimeInfo->tm_hour = 23;
  TimeInfo->tm_min = 54;
  TimeInfo->tm_sec = 58;
  ExpectedTimestamp = mktime(TimeInfo);

  GPGBS Message = {ExpectedTimestamp, 1.4f, 1.3f, 3.1f, 3, NAN, -21.4f, 3.8f};

  NMEAMessage Expected = {.Header = &Header, .GBS = &Message};

  auto Parser = NMEAParser{};
  auto Result = Parser.Parse(RawMessage);

  // Compare Header
  EXPECT_EQ(Expected.Header->ID, Result->Header->ID);
  EXPECT_EQ(Expected.Header->Type, Result->Header->Type);
  EXPECT_EQ(Expected.Header->Valid, Result->Header->Valid);

  // Compare Message
  EXPECT_EQ(Expected.GBS->TimeStamp, Result->GBS->TimeStamp);
  EXPECT_FLOAT_EQ(Expected.GBS->errlat, Result->GBS->errlat);
  EXPECT_FLOAT_EQ(Expected.GBS->errlon, Result->GBS->errlon);
  EXPECT_FLOAT_EQ(Expected.GBS->erralt, Result->GBS->erralt);
  EXPECT_EQ(Expected.GBS->svid, Result->GBS->svid);
  EXPECT_EQ(isnan(Expected.GBS->prob), isnan(Result->GBS->prob));
  EXPECT_FLOAT_EQ(Expected.GBS->bias, Result->GBS->bias);
  EXPECT_FLOAT_EQ(Expected.GBS->stddev, Result->GBS->stddev);
}
};
<commit_msg>Update GBSMessageParse<commit_after>//===-- GBSMessageParse_Test.cpp --------------------------------*- C++ -*-===//
//
// This file is distributed uner the MIT license. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
///
//===----------------------------------------------------------------------===//
#include "NMEAParser.h"
#include "gtest/gtest.h"

#include <cstring>
#include <cmath>
#include <iostream>

#if 0
| N | Message |
|---+---------|
| 1 | Valid   |
| 2 | Invalid |
| 3 | Empty   |
#endif

namespace NMEA {
TEST(GBSMessageParse, Valid_Message) {
  const std::string RawMessage =
      "$GPGBS,235458.00,1.4,1.3,3.1,03,,-21.4,3.8*5B";

  time_t ExpectedTimestamp = 0;
  struct tm *TimeInfo;

  std::time(&ExpectedTimestamp);
  TimeInfo = gmtime(&ExpectedTimestamp);
  TimeInfo->tm_hour = 23;
  TimeInfo->tm_min = 54;
  TimeInfo->tm_sec = 58;
  ExpectedTimestamp = mktime(TimeInfo);

  NMEAMessage Expected{NMEA_TALKER_ID::GPS, NMEA_MESSAGE_TYPE::GBS, 1,
                       .GBS = {new GPGBS{ExpectedTimestamp, 1.4f, 1.3f, 3.1f, 3,
                                         NAN, -21.4f, 3.8f}}};

  auto Parser = NMEAParser{};
  auto Result = Parser.Parse(RawMessage);

  // Compare Header
  EXPECT_EQ(Expected.ID, Result->ID);
  EXPECT_EQ(Expected.Type, Result->Type);
  EXPECT_EQ(Expected.Valid, Result->Valid);

  // Compare Message
  EXPECT_EQ(Expected.GBS->TimeStamp, Result->GBS->TimeStamp);
  EXPECT_FLOAT_EQ(Expected.GBS->errlat, Result->GBS->errlat);
  EXPECT_FLOAT_EQ(Expected.GBS->errlon, Result->GBS->errlon);
  EXPECT_FLOAT_EQ(Expected.GBS->erralt, Result->GBS->erralt);
  EXPECT_EQ(Expected.GBS->svid, Result->GBS->svid);
  EXPECT_EQ(isnan(Expected.GBS->prob), isnan(Result->GBS->prob));
  EXPECT_FLOAT_EQ(Expected.GBS->bias, Result->GBS->bias);
  EXPECT_FLOAT_EQ(Expected.GBS->stddev, Result->GBS->stddev);
}
};
<|endoftext|>


<commit_before>/**
 * \file
 * \brief mutexTestCases object definition
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-04
 */

#include "mutexTestCases.hpp"

#include "MutexPriorityTestCase.hpp"
#include "MutexOperationsTestCase.hpp"
#include "MutexErrorCheckingOperationsTestCase.hpp"
#include "MutexRecursiveOperationsTestCase.hpp"
#include "MutexPriorityProtocolTestCase.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local objects
+---------------------------------------------------------------------------------------------------------------------*/

/// MutexPriorityTestCase instance
const MutexPriorityTestCase priorityTestCase;

/// MutexOperationsTestCase instance
const MutexOperationsTestCase operationsTestCase;

/// MutexErrorCheckingOperationsTestCase instance
const MutexErrorCheckingOperationsTestCase errorCheckingOperationsTestCase;

/// MutexRecursiveOperationsTestCase instance
const MutexRecursiveOperationsTestCase recursiveOperationsTestCase;

/// MutexPriorityProtocolTestCase instance
const MutexPriorityProtocolTestCase priorityProtocolTestCase;

/// array with references to TestCase objects related to mutexes
const TestCaseRange::value_type mutexTestCases_[]
{
		priorityTestCase,
		operationsTestCase,
		errorCheckingOperationsTestCase,
		recursiveOperationsTestCase,
		priorityProtocolTestCase,
};

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| global objects
+---------------------------------------------------------------------------------------------------------------------*/

const TestCaseRange mutexTestCases {mutexTestCases_};

}	// namespace test

}	// namespace distortos
<commit_msg>test: add MutexPriorityProtectOperationsTestCase to executed test cases<commit_after>/**
 * \file
 * \brief mutexTestCases object definition
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-09
 */

#include "mutexTestCases.hpp"

#include "MutexPriorityTestCase.hpp"
#include "MutexOperationsTestCase.hpp"
#include "MutexErrorCheckingOperationsTestCase.hpp"
#include "MutexRecursiveOperationsTestCase.hpp"
#include "MutexPriorityProtocolTestCase.hpp"
#include "MutexPriorityProtectOperationsTestCase.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local objects
+---------------------------------------------------------------------------------------------------------------------*/

/// MutexPriorityTestCase instance
const MutexPriorityTestCase priorityTestCase;

/// MutexOperationsTestCase instance
const MutexOperationsTestCase operationsTestCase;

/// MutexErrorCheckingOperationsTestCase instance
const MutexErrorCheckingOperationsTestCase errorCheckingOperationsTestCase;

/// MutexRecursiveOperationsTestCase instance
const MutexRecursiveOperationsTestCase recursiveOperationsTestCase;

/// MutexPriorityProtocolTestCase instance
const MutexPriorityProtocolTestCase priorityProtocolTestCase;

/// MutexPriorityProtectOperationsTestCase instance
const MutexPriorityProtectOperationsTestCase priorityProtectOperationsTestCase;

/// array with references to TestCase objects related to mutexes
const TestCaseRange::value_type mutexTestCases_[]
{
		priorityTestCase,
		operationsTestCase,
		errorCheckingOperationsTestCase,
		recursiveOperationsTestCase,
		priorityProtocolTestCase,
		priorityProtectOperationsTestCase,
};

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| global objects
+---------------------------------------------------------------------------------------------------------------------*/

const TestCaseRange mutexTestCases {mutexTestCases_};

}	// namespace test

}	// namespace distortos
<|endoftext|>