<commit_before>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2012 execjosh, http://execjosh.blogspot.com

  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 the <organization> nor the
      names of its 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 <COPYRIGHT HOLDER> 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 "system.h"

#include <QVariantMap>
#include <QSysInfo>

#include "../env.h"

System::System(QObject *parent) :
    REPLCompletable(parent)
{
    // Populate "env"
    m_env = Env::instance()->asVariantMap();

    // Populate "os"
    // "osarchitecture" word size
    m_os.insert("architecture", QString("%1bit").arg(QSysInfo::WordSize));

    // "os.name" and "os.version"
#if defined(Q_OS_WIN32)
    m_os.insert("name", "windows");
    switch (QSysInfo::WindowsVersion) {
    case QSysInfo::WV_32s:
        m_os.insert("version", "3.1");
        break;
    case QSysInfo::WV_95:
        m_os.insert("version", "95");
        break;
    case QSysInfo::WV_98:
        m_os.insert("version", "98");
        break;
    case QSysInfo::WV_Me:
        m_os.insert("version", "Me");
        break;
    case QSysInfo::WV_NT:
        m_os.insert("version", "NT");
        break;
    case QSysInfo::WV_2000:
        m_os.insert("version", "2000");
        break;
    case QSysInfo::WV_XP:
        m_os.insert("version", "XP");
        break;
    case QSysInfo::WV_2003:
        m_os.insert("version", "2003");
        break;
    case QSysInfo::WV_VISTA:
        m_os.insert("version", "Vista");
        break;
    case QSysInfo::WV_WINDOWS7:
        m_os.insert("version", "7");
        break;
    default:
        m_os.insert("version", "unknown");
        break;
    }
#elif defined(Q_OS_MAC)
    m_os.insert("name", "mac");
    switch (QSysInfo::MacintoshVersion) {
    case QSysInfo::MV_10_3:
        m_os.insert("version", "10.3 (Panther)");
        break;
    case QSysInfo::MV_10_4:
        m_os.insert("version", "10.4 (Tiger)");
        break;
    case QSysInfo::MV_10_5:
        m_os.insert("version", "10.5 (Leopard)");
        break;
    case QSysInfo::MV_10_6:
        m_os.insert("version", "10.6 (Snow Leopard)");
        break;
    case QSysInfo::MV_10_7:
        m_os.insert("version", "10.7 (Lion)");
        break;
    default:
        m_os.insert("version", "unknown");
        break;
    }
#elif defined(Q_OS_LINUX)
    m_os.insert("name", "linux");
    m_os.insert("version", "unknown");
#else
    m_os.insert("name", "unknown");
    m_os.insert("version", "unknown");
#endif
}

void System::setArgs(const QStringList &args)
{
    m_args = args;
}

QStringList System::args() const
{
    return m_args;
}

QVariant System::env() const
{
    return m_env;
}

QVariant System::os() const
{
    return m_os;
}

void System::initCompletions()
{
    addCompletion("args");
    addCompletion("env");
    addCompletion("platform");
    addCompletion("os");
}
<commit_msg>Better support for Windows 8.<commit_after>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2012 execjosh, http://execjosh.blogspot.com

  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 the <organization> nor the
      names of its 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 <COPYRIGHT HOLDER> 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 "system.h"

#include <QVariantMap>
#include <QSysInfo>

#include "../env.h"

System::System(QObject *parent) :
    REPLCompletable(parent)
{
    // Populate "env"
    m_env = Env::instance()->asVariantMap();

    // Populate "os"
    // "osarchitecture" word size
    m_os.insert("architecture", QString("%1bit").arg(QSysInfo::WordSize));

    // "os.name" and "os.version"
#if defined(Q_OS_WIN32)
    m_os.insert("name", "windows");
    switch (QSysInfo::WindowsVersion) {
    case QSysInfo::WV_32s:
        m_os.insert("version", "3.1");
        break;
    case QSysInfo::WV_95:
        m_os.insert("version", "95");
        break;
    case QSysInfo::WV_98:
        m_os.insert("version", "98");
        break;
    case QSysInfo::WV_Me:
        m_os.insert("version", "Me");
        break;
    case QSysInfo::WV_NT:
        m_os.insert("version", "NT");
        break;
    case QSysInfo::WV_2000:
        m_os.insert("version", "2000");
        break;
    case QSysInfo::WV_XP:
        m_os.insert("version", "XP");
        break;
    case QSysInfo::WV_2003:
        m_os.insert("version", "2003");
        break;
    case QSysInfo::WV_VISTA:
        m_os.insert("version", "Vista");
        break;
    case QSysInfo::WV_WINDOWS7:
        m_os.insert("version", "7");
        break;
    case QSysInfo::WV_WINDOWS8:
        m_os.insert("version", "8");
        break;
    default:
        m_os.insert("version", "unknown");
        break;
    }
#elif defined(Q_OS_MAC)
    m_os.insert("name", "mac");
    switch (QSysInfo::MacintoshVersion) {
    case QSysInfo::MV_10_3:
        m_os.insert("version", "10.3 (Panther)");
        break;
    case QSysInfo::MV_10_4:
        m_os.insert("version", "10.4 (Tiger)");
        break;
    case QSysInfo::MV_10_5:
        m_os.insert("version", "10.5 (Leopard)");
        break;
    case QSysInfo::MV_10_6:
        m_os.insert("version", "10.6 (Snow Leopard)");
        break;
    case QSysInfo::MV_10_7:
        m_os.insert("version", "10.7 (Lion)");
        break;
    default:
        m_os.insert("version", "unknown");
        break;
    }
#elif defined(Q_OS_LINUX)
    m_os.insert("name", "linux");
    m_os.insert("version", "unknown");
#else
    m_os.insert("name", "unknown");
    m_os.insert("version", "unknown");
#endif
}

void System::setArgs(const QStringList &args)
{
    m_args = args;
}

QStringList System::args() const
{
    return m_args;
}

QVariant System::env() const
{
    return m_env;
}

QVariant System::os() const
{
    return m_os;
}

void System::initCompletions()
{
    addCompletion("args");
    addCompletion("env");
    addCompletion("platform");
    addCompletion("os");
}
<|endoftext|>


<commit_before>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2012 execjosh, http://execjosh.blogspot.com

  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 the <organization> nor the
      names of its 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 <COPYRIGHT HOLDER> 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 "system.h"

#include <QVariantMap>
#include <QSysInfo>

#include "../env.h"

System::System(QObject *parent) :
    REPLCompletable(parent)
{
    // Populate "env"
    m_env = Env::instance()->asVariantMap();

    // Populate "os"
    // "osarchitecture" word size
    m_os.insert("architecture", QString("%1bit").arg(QSysInfo::WordSize));

    // "os.name" and "os.version"
#if defined(Q_OS_WIN32)
    m_os.insert("name", "windows");
    switch (QSysInfo::WindowsVersion) {
    case QSysInfo::WV_32s:
        m_os.insert("version", "3.1");
        break;
    case QSysInfo::WV_95:
        m_os.insert("version", "95");
        break;
    case QSysInfo::WV_98:
        m_os.insert("version", "98");
        break;
    case QSysInfo::WV_Me:
        m_os.insert("version", "Me");
        break;
    case QSysInfo::WV_NT:
        m_os.insert("version", "NT");
        break;
    case QSysInfo::WV_2000:
        m_os.insert("version", "2000");
        break;
    case QSysInfo::WV_XP:
        m_os.insert("version", "XP");
        break;
    case QSysInfo::WV_2003:
        m_os.insert("version", "2003");
        break;
    case QSysInfo::WV_VISTA:
        m_os.insert("version", "Vista");
        break;
    case QSysInfo::WV_WINDOWS7:
        m_os.insert("version", "7");
        break;
    case QSysInfo::WV_WINDOWS8:
        m_os.insert("version", "8");
        break;
    default:
        m_os.insert("version", "unknown");
        break;
    }
#elif defined(Q_OS_MAC)
    m_os.insert("name", "mac");
    switch (QSysInfo::MacintoshVersion) {
    case QSysInfo::MV_10_3:
        m_os.insert("version", "10.3 (Panther)");
        break;
    case QSysInfo::MV_10_4:
        m_os.insert("version", "10.4 (Tiger)");
        break;
    case QSysInfo::MV_10_5:
        m_os.insert("version", "10.5 (Leopard)");
        break;
    case QSysInfo::MV_10_6:
        m_os.insert("version", "10.6 (Snow Leopard)");
        break;
    case QSysInfo::MV_10_7:
        m_os.insert("version", "10.7 (Lion)");
        break;
    default:
        m_os.insert("version", "unknown");
        break;
    }
#elif defined(Q_OS_LINUX)
    m_os.insert("name", "linux");
    m_os.insert("version", "unknown");
#else
    m_os.insert("name", "unknown");
    m_os.insert("version", "unknown");
#endif
}

void System::setArgs(const QStringList &args)
{
    m_args = args;
}

QStringList System::args() const
{
    return m_args;
}

QVariant System::env() const
{
    return m_env;
}

QVariant System::os() const
{
    return m_os;
}

void System::initCompletions()
{
    addCompletion("args");
    addCompletion("env");
    addCompletion("platform");
    addCompletion("os");
}
<commit_msg>Better support for OS X Mountain Lion.<commit_after>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2012 execjosh, http://execjosh.blogspot.com

  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 the <organization> nor the
      names of its 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 <COPYRIGHT HOLDER> 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 "system.h"

#include <QVariantMap>
#include <QSysInfo>

#include "../env.h"

System::System(QObject *parent) :
    REPLCompletable(parent)
{
    // Populate "env"
    m_env = Env::instance()->asVariantMap();

    // Populate "os"
    // "osarchitecture" word size
    m_os.insert("architecture", QString("%1bit").arg(QSysInfo::WordSize));

    // "os.name" and "os.version"
#if defined(Q_OS_WIN32)
    m_os.insert("name", "windows");
    switch (QSysInfo::WindowsVersion) {
    case QSysInfo::WV_32s:
        m_os.insert("version", "3.1");
        break;
    case QSysInfo::WV_95:
        m_os.insert("version", "95");
        break;
    case QSysInfo::WV_98:
        m_os.insert("version", "98");
        break;
    case QSysInfo::WV_Me:
        m_os.insert("version", "Me");
        break;
    case QSysInfo::WV_NT:
        m_os.insert("version", "NT");
        break;
    case QSysInfo::WV_2000:
        m_os.insert("version", "2000");
        break;
    case QSysInfo::WV_XP:
        m_os.insert("version", "XP");
        break;
    case QSysInfo::WV_2003:
        m_os.insert("version", "2003");
        break;
    case QSysInfo::WV_VISTA:
        m_os.insert("version", "Vista");
        break;
    case QSysInfo::WV_WINDOWS7:
        m_os.insert("version", "7");
        break;
    case QSysInfo::WV_WINDOWS8:
        m_os.insert("version", "8");
        break;
    default:
        m_os.insert("version", "unknown");
        break;
    }
#elif defined(Q_OS_MAC)
    m_os.insert("name", "mac");
    switch (QSysInfo::MacintoshVersion) {
    case QSysInfo::MV_10_3:
        m_os.insert("version", "10.3 (Panther)");
        break;
    case QSysInfo::MV_10_4:
        m_os.insert("version", "10.4 (Tiger)");
        break;
    case QSysInfo::MV_10_5:
        m_os.insert("version", "10.5 (Leopard)");
        break;
    case QSysInfo::MV_10_6:
        m_os.insert("version", "10.6 (Snow Leopard)");
        break;
    case QSysInfo::MV_10_7:
        m_os.insert("version", "10.7 (Lion)");
        break;
    case QSysInfo::MV_10_8:
        m_os.insert("version", "10.8 (Mountain Lion)");
        break;
    default:
        m_os.insert("version", "unknown");
        break;
    }
#elif defined(Q_OS_LINUX)
    m_os.insert("name", "linux");
    m_os.insert("version", "unknown");
#else
    m_os.insert("name", "unknown");
    m_os.insert("version", "unknown");
#endif
}

void System::setArgs(const QStringList &args)
{
    m_args = args;
}

QStringList System::args() const
{
    return m_args;
}

QVariant System::env() const
{
    return m_env;
}

QVariant System::os() const
{
    return m_os;
}

void System::initCompletions()
{
    addCompletion("args");
    addCompletion("env");
    addCompletion("platform");
    addCompletion("os");
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2021 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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.
 */

#pragma once

#include "util/StringView.hxx"

#include <nghttp2/nghttp2.h>

namespace NgHttp2 {

/**
 * Construct a #nghttp2_nv from two string views.
 */
constexpr auto
MakeNv(StringView name, StringView value,
       uint8_t flags=NGHTTP2_NV_FLAG_NONE) noexcept
{
	nghttp2_nv nv{};
	nv.name = const_cast<uint8_t *>((const uint8_t *)(const void *)name.data);
	nv.value = const_cast<uint8_t *>((const uint8_t *)(const void *)value.data);
	nv.namelen = name.size;
	nv.valuelen = value.size;
	nv.flags = flags;
	return nv;
}

} // namespace NgHttp2
<commit_msg>nghttp2/Util: switch to std::string_view<commit_after>/*
 * Copyright 2007-2021 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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.
 */

#pragma once

#include <nghttp2/nghttp2.h>

#include <string_view>

namespace NgHttp2 {

/**
 * Construct a #nghttp2_nv from two string views.
 */
constexpr auto
MakeNv(std::string_view name, std::string_view value,
       uint8_t flags=NGHTTP2_NV_FLAG_NONE) noexcept
{
	nghttp2_nv nv{};
	nv.name = const_cast<uint8_t *>((const uint8_t *)(const void *)name.data());
	nv.value = const_cast<uint8_t *>((const uint8_t *)(const void *)value.data());
	nv.namelen = name.size();
	nv.valuelen = value.size();
	nv.flags = flags;
	return nv;
}

} // namespace NgHttp2
<|endoftext|>


<commit_before>#ifndef SRC_NODES_BUFFER_HPP_
#define SRC_NODES_BUFFER_HPP_

#include <core/traits.hpp>

#include <ports/states/state_source_call_function.hpp>
#include <ports/events/event_sinks.hpp>

#include <boost/range.hpp>
#include <vector>

namespace fc
{

template<class data_t>
class base_event_to_state
{
public:
	typedef boost::iterator_range<typename std::vector<data_t>::const_iterator> out_range_t;

	auto in() noexcept { return collector{buffer_collect}; }

	auto out() noexcept { return out_port; }

protected:
	explicit base_event_to_state(const state_source_call_function<out_range_t>& out_port) :
		buffer_collect(std::make_shared<std::vector<data_t>>()),
		out_port(out_port)
	{
	}

	std::shared_ptr<std::vector<data_t>> buffer_collect;
	std::vector<data_t> buffer_state;

	state_source_call_function<out_range_t> out_port;

	struct collector
	{
		typedef void result_t;

		void operator() (const auto& range)
		{
			using std::begin;
			using std::end;
			//check if the node owning the buffer has been deleted. which is a bug.
			assert(!buffer.expired());
			buffer.lock()->insert(
					end(*buffer.lock()), begin(range), end(range));
		};

		void operator()(const data_t& single_input)
		{
			//check if the node owning the buffer has been deleted. which is a bug.
			assert(!buffer.expired());
			buffer.lock()->insert(
					end(*buffer.lock()), single_input);
		}

		std::weak_ptr<std::vector<data_t>> buffer;
	};
};

template<class data_t>
class event_to_state : public base_event_to_state<data_t>
{
public:
	typedef boost::iterator_range<typename std::vector<data_t>::const_iterator> out_range_t;
	event_to_state()
		: base_event_to_state<data_t>( state_source_call_function<out_range_t>([&]()
				{
					data_read = true;
					return boost::make_iterator_range(
							this->buffer_state.begin(),
							this->buffer_state.end());
				} ))
	{}

	auto swap_buffers() noexcept
	{
		return [this]()
		{
			if (data_read) //move data from collect buffer to output, and clear collect buffer
			{
				this->buffer_state.clear();
				this->buffer_state.swap(*this->buffer_collect);
				data_read = false;
			}
			else //just move data from collect buffer to output buffer
			{
				this->buffer_state.insert(end(*this->buffer_collect),
						begin(*this->buffer_collect), end(*this->buffer_collect));
				this->buffer_collect->clear();
			}
		};
	}

private:
	bool data_read = false;
};

/**
 * Collects list contents and store them into a buffer.
 * Sends the buffer as state when pulled.
 */
template<class data_t>
class list_collector : public base_event_to_state<data_t>
{
public:
	typedef boost::iterator_range<typename std::vector<data_t>::const_iterator> out_range_t;

	list_collector()
		: base_event_to_state<data_t>( state_source_call_function<out_range_t>([&]()
				{
					return this->get_state();
				} ))
	{}

private:
	out_range_t get_state()
	{
		this->buffer_state.clear();
		this->buffer_state.swap(*this->buffer_collect);
		return boost::make_iterator_range(
				this->buffer_state.begin(),
				this->buffer_state.end());
	}
};

/**
 * \brief buffer which receives events and stores the last event received as state.
 *
 * \tparam data_t is type of token received as event and then stored.
 */
template<class data_t>
class hold_last
{
public:
	static_assert(!std::is_void<data_t>(),
			"data stored in hold_last cannot be void");

	/// Constructs hold_last with initial state.
	explicit hold_last(const data_t& initial_value = data_t())
		: storage(initial_value)
	{
	}

	/// Event in Port expecting data_t.
	auto in() noexcept { return [this](data_t in){ storage = in; }; }
	/// State out port supplying data_t.
	auto out() const noexcept { return [this](){ return storage;}; }
private:
	data_t storage;
};

}  // namespace fc

#endif /* SRC_NODES_BUFFER_HPP_ */
<commit_msg>fixed include in buffer<commit_after>#ifndef SRC_NODES_BUFFER_HPP_
#define SRC_NODES_BUFFER_HPP_

#include <core/traits.hpp>

#include <ports/states/state_sources.hpp>
#include <ports/events/event_sinks.hpp>

#include <boost/range.hpp>
#include <vector>

namespace fc
{

template<class data_t>
class base_event_to_state
{
public:
	typedef boost::iterator_range<typename std::vector<data_t>::const_iterator> out_range_t;

	auto in() noexcept { return collector{buffer_collect}; }

	auto out() noexcept { return out_port; }

protected:
	explicit base_event_to_state(const state_source_call_function<out_range_t>& out_port) :
		buffer_collect(std::make_shared<std::vector<data_t>>()),
		out_port(out_port)
	{
	}

	std::shared_ptr<std::vector<data_t>> buffer_collect;
	std::vector<data_t> buffer_state;

	state_source_call_function<out_range_t> out_port;

	struct collector
	{
		typedef void result_t;

		void operator() (const auto& range)
		{
			using std::begin;
			using std::end;
			//check if the node owning the buffer has been deleted. which is a bug.
			assert(!buffer.expired());
			buffer.lock()->insert(
					end(*buffer.lock()), begin(range), end(range));
		};

		void operator()(const data_t& single_input)
		{
			//check if the node owning the buffer has been deleted. which is a bug.
			assert(!buffer.expired());
			buffer.lock()->insert(
					end(*buffer.lock()), single_input);
		}

		std::weak_ptr<std::vector<data_t>> buffer;
	};
};

template<class data_t>
class event_to_state : public base_event_to_state<data_t>
{
public:
	typedef boost::iterator_range<typename std::vector<data_t>::const_iterator> out_range_t;
	event_to_state()
		: base_event_to_state<data_t>( state_source_call_function<out_range_t>([&]()
				{
					data_read = true;
					return boost::make_iterator_range(
							this->buffer_state.begin(),
							this->buffer_state.end());
				} ))
	{}

	auto swap_buffers() noexcept
	{
		return [this]()
		{
			if (data_read) //move data from collect buffer to output, and clear collect buffer
			{
				this->buffer_state.clear();
				this->buffer_state.swap(*this->buffer_collect);
				data_read = false;
			}
			else //just move data from collect buffer to output buffer
			{
				this->buffer_state.insert(end(*this->buffer_collect),
						begin(*this->buffer_collect), end(*this->buffer_collect));
				this->buffer_collect->clear();
			}
		};
	}

private:
	bool data_read = false;
};

/**
 * Collects list contents and store them into a buffer.
 * Sends the buffer as state when pulled.
 */
template<class data_t>
class list_collector : public base_event_to_state<data_t>
{
public:
	typedef boost::iterator_range<typename std::vector<data_t>::const_iterator> out_range_t;

	list_collector()
		: base_event_to_state<data_t>( state_source_call_function<out_range_t>([&]()
				{
					return this->get_state();
				} ))
	{}

private:
	out_range_t get_state()
	{
		this->buffer_state.clear();
		this->buffer_state.swap(*this->buffer_collect);
		return boost::make_iterator_range(
				this->buffer_state.begin(),
				this->buffer_state.end());
	}
};

/**
 * \brief buffer which receives events and stores the last event received as state.
 *
 * \tparam data_t is type of token received as event and then stored.
 */
template<class data_t>
class hold_last
{
public:
	static_assert(!std::is_void<data_t>(),
			"data stored in hold_last cannot be void");

	/// Constructs hold_last with initial state.
	explicit hold_last(const data_t& initial_value = data_t())
		: storage(initial_value)
	{
	}

	/// Event in Port expecting data_t.
	auto in() noexcept { return [this](data_t in){ storage = in; }; }
	/// State out port supplying data_t.
	auto out() const noexcept { return [this](){ return storage;}; }
private:
	data_t storage;
};

}  // namespace fc

#endif /* SRC_NODES_BUFFER_HPP_ */
<|endoftext|>


<commit_before>#include "nodetreeview.h"
#include "nodetreemodel.h"
#include <QMenu>
#include <QAction>
#include <QMouseEvent>
#include <QDebug>
#include <QMimeData>

NodeTreeView::NodeTreeView(QWidget *parent) :
    QTreeView(parent),
    m_isContextMenuOpened{false},
    m_isEditing{false}
{
    setHeaderHidden(true);
    setStyleSheet(
                R"(QTreeView {)"
                R"(    border-style: none;)"
                R"(    background-color: rgb(255, 255, 255);)"
                R"(    selection-background-color: white;)"
                R"(    selection-color: white;)"
                R"(})"
                R"()"
                R"(QTreeView::branch{)"
                R"(    border-image: url(none.png);)"
                R"(})"
                R"(QScrollBar::handle:vertical:hover { background: rgb(170, 170, 171); } )"
                R"(QScrollBar::handle:vertical:pressed { background: rgb(149, 149, 149); } )"
                R"(QScrollBar::handle:vertical { border-radius: 4px; background: rgb(188, 188, 188); min-height: 20px; }  )"
                R"(QScrollBar::vertical {border-radius: 4px; width: 8px; color: rgba(255, 255, 255,0);} )"
                R"(QScrollBar {margin: 0; background: transparent;} )"
                R"(QScrollBar:hover { background-color: rgb(217, 217, 217);})"
                R"(QScrollBar::add-line:vertical { width:0px; height: 0px; subcontrol-position: bottom; subcontrol-origin: margin; }  )"
                R"(QScrollBar::sub-line:vertical { width:0px; height: 0px; subcontrol-position: top; subcontrol-origin: margin; })"
                );
    setRootIsDecorated(false);
    setMouseTracking(true);
    setAcceptDrops(true);
    connect(this, &QAbstractItemView::clicked, this, &NodeTreeView::onClicked);
    setSelectionMode(QAbstractItemView::MultiSelection);
    setContextMenuPolicy(Qt::CustomContextMenu);
    connect(this, &QWidget::customContextMenuRequested,
            this, &NodeTreeView::onCustomContextMenu);
    contextMenu = new QMenu(this);
    renameFolderAction = new QAction(tr("Rename Folder"), this);
    connect(renameFolderAction, &QAction::triggered, this, [this] {
        setIsEditing(true);
        emit renameFolderRequested();
    });
    deleteFolderAction = new QAction(tr("Delete Folder"), this);
    connect(deleteFolderAction, &QAction::triggered, this, &NodeTreeView::onDeleteNodeAction);
    addSubfolderAction = new QAction(tr("Add Subfolder"), this);
    connect(addSubfolderAction, &QAction::triggered, this, &NodeTreeView::addFolderRequested);

    renameTagAction = new QAction(tr("Rename Tag"), this);
    connect(renameTagAction, &QAction::triggered, this, [this] {
        setIsEditing(true);
        emit renameTagRequested();
    });
    changeTagColorAction = new QAction(tr("Change Tag Color"), this);
    connect(changeTagColorAction, &QAction::triggered, this, &NodeTreeView::onChangeTagColorAction);
    deleteTagAction = new QAction(tr("Delete Tag"), this);
    connect(deleteTagAction, &QAction::triggered, this, &NodeTreeView::onDeleteNodeAction);
    clearSelectionAction = new QAction(tr("Clear Selection"), this);
    connect(clearSelectionAction, &QAction::triggered,
            this, [this] {
        closeCurrentEditor();
        clearSelection();
        setCurrentIndex(QModelIndex());
    });

    contextMenuTimer.setInterval(100);
    contextMenuTimer.setSingleShot(true);
    connect(&contextMenuTimer, &QTimer::timeout, this, [this] {
        if (!m_isEditing) {
            closeCurrentEditor();
        }
    });

    connect(contextMenu, &QMenu::aboutToHide, this, [this] {
        m_isContextMenuOpened = false;
        // this signal is emmited before QAction::triggered
        contextMenuTimer.start();
    });
}

void NodeTreeView::onClicked(const QModelIndex &index)
{
    auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
    switch (itemType) {
    case NodeItem::Type::FolderItem: {
        expand(index);
        break;
    }
    default: {
        break;
    }
    }
}

void NodeTreeView::onDeleteNodeAction()
{
    auto itemType = static_cast<NodeItem::Type>(m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
    auto id = m_currentEditingIndex.data(NodeItem::Roles::NodeId).toInt();
    if (itemType == NodeItem::Type::FolderItem || itemType == NodeItem::Type::NoteItem) {
        if (id > SpecialNodeID::DefaultNotesFolder) {
            auto index = m_currentEditingIndex;
            emit deleteNodeRequested(index);
        }
    } else if (itemType == NodeItem::Type::TagItem) {
        auto index = m_currentEditingIndex;
        emit deleteTagRequested(index);
    }
}

void NodeTreeView::onChangeTagColorAction()
{
    auto itemType = static_cast<NodeItem::Type>(m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
    if (itemType == NodeItem::Type::TagItem) {
        auto index = m_currentEditingIndex;
        emit changeTagColorRequested(index);
    }
}

void NodeTreeView::updateEditingIndex(QMouseEvent *event)
{
    auto index = indexAt(event->pos());
    if(indexAt(event->pos()) != m_currentEditingIndex && !m_isContextMenuOpened && !m_isEditing) {
        auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
        auto id = index.data(NodeItem::Roles::NodeId).toInt();
        if ((itemType == NodeItem::Type::FolderItem
             && id != SpecialNodeID::DefaultNotesFolder)
                || itemType == NodeItem::Type::TagItem) {
            closePersistentEditor(m_currentEditingIndex);
            openPersistentEditor(index);
            m_currentEditingIndex = index;
        } else {
            closeCurrentEditor();
        }
    }
}

void NodeTreeView::closeCurrentEditor()
{
    closePersistentEditor(m_currentEditingIndex);
    m_currentEditingIndex = QModelIndex();
}

void NodeTreeView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
    QTreeView::selectionChanged(selected, deselected);
    auto indexes = selectedIndexes();
    QSet<int> tagIds;
    for (const auto index : indexes) {
        auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
        switch (itemType) {
        case NodeItem::Type::RootItem:
        case NodeItem::Type::FolderSeparator:
        case NodeItem::Type::TagSeparator:
        case NodeItem::Type::NoteItem: {
            return;
        }
        case NodeItem::Type::AllNoteButton: {
            emit loadNotesInFolderRequested(SpecialNodeID::RootFolder, true);
            return;
        }
        case NodeItem::Type::TrashButton: {
            emit loadNotesInFolderRequested(SpecialNodeID::TrashFolder, true);
            return;
        }
        case NodeItem::Type::FolderItem: {
            auto folderId = index.data(NodeItem::Roles::NodeId).toInt();
            emit loadNotesInFolderRequested(folderId, false);
            return;
        }
        case NodeItem::Type::TagItem: {
            auto tagId = index.data(NodeItem::Roles::NodeId).toInt();
            tagIds.insert(tagId);
            break;
        }
        }
    }
    emit loadNotesInTagsRequested(tagIds);
}

void NodeTreeView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
    QTreeView::currentChanged(current, previous);
    auto itemType = static_cast<NodeItem::Type>(current.data(NodeItem::Roles::ItemType).toInt());
    if (itemType == NodeItem::Type::TagItem) {
        setSelectionMode(QAbstractItemView::MultiSelection);
    } else {
        clearSelection();
        setSelectionMode(QAbstractItemView::SingleSelection);
        selectionModel()->setCurrentIndex(current, QItemSelectionModel::Current);
    }
}

void NodeTreeView::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasFormat("text/noteId")) {
        event->acceptProposedAction();
    }
}

void NodeTreeView::dragMoveEvent(QDragMoveEvent *event)
{
    if (event->mimeData()->hasFormat("text/noteId")) {
        event->acceptProposedAction();
    }
}

void NodeTreeView::dropEvent(QDropEvent *event)
{
    if (event->mimeData()->hasFormat("text/noteId")) {
        auto dropIndex = indexAt(event->pos());
        if (dropIndex.isValid()) {
            auto itemType = static_cast<NodeItem::Type>(dropIndex.data(NodeItem::Roles::ItemType).toInt());
            bool ok = false;
            auto nodeId = QString::fromUtf8(
                        event->mimeData()->data("text/noteId")).toInt(&ok);
            if (ok) {
                if (itemType == NodeItem::Type::FolderItem) {
                    emit moveNodeRequested(nodeId, dropIndex.data(NodeItem::NodeId).toInt());
                    setCurrentIndex(dropIndex);
                    clearSelection();
                    setSelectionMode(QAbstractItemView::SingleSelection);
                    selectionModel()->setCurrentIndex(dropIndex, QItemSelectionModel::SelectCurrent);
                    event->acceptProposedAction();
                } else if (itemType == NodeItem::Type::TagItem) {
                    emit addNoteToTag(nodeId, dropIndex.data(NodeItem::NodeId).toInt());
                } else if (itemType == NodeItem::Type::TrashButton) {
                    emit moveNodeRequested(nodeId, SpecialNodeID::TrashFolder);
                    setCurrentIndex(dropIndex);
                    clearSelection();
                    setSelectionMode(QAbstractItemView::SingleSelection);
                    selectionModel()->setCurrentIndex(dropIndex, QItemSelectionModel::SelectCurrent);
                    event->acceptProposedAction();
                }
            }
        }
    }
}

void NodeTreeView::setIsEditing(bool newIsEditing)
{
    m_isEditing = newIsEditing;
}

void NodeTreeView::onRenameFolderFinished(const QString &newName)
{
    if (m_currentEditingIndex.isValid()) {
        auto itemType = static_cast<NodeItem::Type>(m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
        if (itemType == NodeItem::Type::FolderItem) {
            QModelIndex index = m_currentEditingIndex;
            closeCurrentEditor();
            emit renameFolderInDatabase(index, newName);
        } else {
            qDebug() << __FUNCTION__ << "wrong type";
        }
    } /*else {
        qDebug() << __FUNCTION__ << "m_currentEditingIndex is not valid";
    }*/
}

void NodeTreeView::onRenameTagFinished(const QString &newName)
{
    if (m_currentEditingIndex.isValid()) {
        auto itemType = static_cast<NodeItem::Type>(m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
        if (itemType == NodeItem::Type::TagItem) {
            QModelIndex index = m_currentEditingIndex;
            closeCurrentEditor();
            emit renameTagInDatabase(index, newName);
        } else {
            qDebug() << __FUNCTION__ << "wrong type";
        }
    } /*else {
        qDebug() << __FUNCTION__ << "m_currentEditingIndex is not valid";
    }*/
}

void NodeTreeView::setCurrentIndexC(const QModelIndex &index)
{
    setCurrentIndex(index);
    clearSelection();
    setSelectionMode(QAbstractItemView::SingleSelection);
    selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent);
}

void NodeTreeView::onCustomContextMenu(const QPoint &point)
{
    QModelIndex index = indexAt(point);
    if (index.isValid()) {
        auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
        contextMenu->clear();
        if (itemType == NodeItem::Type::FolderItem) {
            auto id = index.data(NodeItem::Roles::NodeId).toInt();
            if (id != SpecialNodeID::DefaultNotesFolder) {
                m_isContextMenuOpened = true;
                contextMenu->addAction(renameFolderAction);
                contextMenu->addAction(deleteFolderAction);
                contextMenu->addSeparator();
                contextMenu->addAction(addSubfolderAction);
                contextMenu->exec(viewport()->mapToGlobal(point));
            }
        } else if (itemType == NodeItem::Type::TagItem) {
            m_isContextMenuOpened = true;
            contextMenu->addAction(renameTagAction);
            contextMenu->addAction(changeTagColorAction);
            contextMenu->addAction(clearSelectionAction);
            contextMenu->addSeparator();
            contextMenu->addAction(deleteTagAction);
            contextMenu->exec(viewport()->mapToGlobal(point));
        }
    }
}

void NodeTreeView::setTreeSeparator(const QVector<QModelIndex> &newTreeSeparator)
{
    for (const auto& sep : m_treeSeparator) {
        closePersistentEditor(sep);
    }
    m_treeSeparator = newTreeSeparator;
    for (const auto& sep : m_treeSeparator) {
        openPersistentEditor(sep);
    }
}

void NodeTreeView::mouseMoveEvent(QMouseEvent *event)
{
    updateEditingIndex(event);
    QTreeView::mouseMoveEvent(event);
}

void NodeTreeView::mousePressEvent(QMouseEvent *event)
{
    updateEditingIndex(event);
    QTreeView::mousePressEvent(event);
}

void NodeTreeView::leaveEvent(QEvent *event)
{
    if (!m_isContextMenuOpened && !m_isEditing) {
        closeCurrentEditor();
        QTreeView::leaveEvent(event);
    }
}
<commit_msg>fix folder arrow button<commit_after>#include "nodetreeview.h"
#include "nodetreemodel.h"
#include <QMenu>
#include <QAction>
#include <QMouseEvent>
#include <QDebug>
#include <QMimeData>

NodeTreeView::NodeTreeView(QWidget *parent) :
    QTreeView(parent),
    m_isContextMenuOpened{false},
    m_isEditing{false}
{
    setHeaderHidden(true);
    setStyleSheet(
                R"(QTreeView {)"
                R"(    border-style: none;)"
                R"(    background-color: rgb(255, 255, 255);)"
                R"(    selection-background-color: white;)"
                R"(    selection-color: white;)"
                R"(})"
                R"()"
                R"(QTreeView::branch{)"
                R"(    border-image: url(none.png);)"
                R"(})"
                R"(QScrollBar::handle:vertical:hover { background: rgb(170, 170, 171); } )"
                R"(QScrollBar::handle:vertical:pressed { background: rgb(149, 149, 149); } )"
                R"(QScrollBar::handle:vertical { border-radius: 4px; background: rgb(188, 188, 188); min-height: 20px; }  )"
                R"(QScrollBar::vertical {border-radius: 4px; width: 8px; color: rgba(255, 255, 255,0);} )"
                R"(QScrollBar {margin: 0; background: transparent;} )"
                R"(QScrollBar:hover { background-color: rgb(217, 217, 217);})"
                R"(QScrollBar::add-line:vertical { width:0px; height: 0px; subcontrol-position: bottom; subcontrol-origin: margin; }  )"
                R"(QScrollBar::sub-line:vertical { width:0px; height: 0px; subcontrol-position: top; subcontrol-origin: margin; })"
                );
    setRootIsDecorated(false);
    setMouseTracking(true);
    setAcceptDrops(true);
    connect(this, &QAbstractItemView::clicked, this, &NodeTreeView::onClicked);
    setSelectionMode(QAbstractItemView::MultiSelection);
    setContextMenuPolicy(Qt::CustomContextMenu);
    connect(this, &QWidget::customContextMenuRequested,
            this, &NodeTreeView::onCustomContextMenu);
    contextMenu = new QMenu(this);
    renameFolderAction = new QAction(tr("Rename Folder"), this);
    connect(renameFolderAction, &QAction::triggered, this, [this] {
        setIsEditing(true);
        emit renameFolderRequested();
    });
    deleteFolderAction = new QAction(tr("Delete Folder"), this);
    connect(deleteFolderAction, &QAction::triggered, this, &NodeTreeView::onDeleteNodeAction);
    addSubfolderAction = new QAction(tr("Add Subfolder"), this);
    connect(addSubfolderAction, &QAction::triggered, this, &NodeTreeView::addFolderRequested);

    renameTagAction = new QAction(tr("Rename Tag"), this);
    connect(renameTagAction, &QAction::triggered, this, [this] {
        setIsEditing(true);
        emit renameTagRequested();
    });
    changeTagColorAction = new QAction(tr("Change Tag Color"), this);
    connect(changeTagColorAction, &QAction::triggered, this, &NodeTreeView::onChangeTagColorAction);
    deleteTagAction = new QAction(tr("Delete Tag"), this);
    connect(deleteTagAction, &QAction::triggered, this, &NodeTreeView::onDeleteNodeAction);
    clearSelectionAction = new QAction(tr("Clear Selection"), this);
    connect(clearSelectionAction, &QAction::triggered,
            this, [this] {
        closeCurrentEditor();
        clearSelection();
        setCurrentIndex(QModelIndex());
    });

    contextMenuTimer.setInterval(100);
    contextMenuTimer.setSingleShot(true);
    connect(&contextMenuTimer, &QTimer::timeout, this, [this] {
        if (!m_isEditing) {
            closeCurrentEditor();
        }
    });

    connect(contextMenu, &QMenu::aboutToHide, this, [this] {
        m_isContextMenuOpened = false;
        // this signal is emmited before QAction::triggered
        contextMenuTimer.start();
    });
}

void NodeTreeView::onClicked(const QModelIndex &index)
{
    auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
    switch (itemType) {
    case NodeItem::Type::FolderItem: {
        if (isExpanded(index)) {
            collapse(index);
        } else {
            expand(index);
        }
        break;
    }
    default: {
        break;
    }
    }
}

void NodeTreeView::onDeleteNodeAction()
{
    auto itemType = static_cast<NodeItem::Type>(m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
    auto id = m_currentEditingIndex.data(NodeItem::Roles::NodeId).toInt();
    if (itemType == NodeItem::Type::FolderItem || itemType == NodeItem::Type::NoteItem) {
        if (id > SpecialNodeID::DefaultNotesFolder) {
            auto index = m_currentEditingIndex;
            emit deleteNodeRequested(index);
        }
    } else if (itemType == NodeItem::Type::TagItem) {
        auto index = m_currentEditingIndex;
        emit deleteTagRequested(index);
    }
}

void NodeTreeView::onChangeTagColorAction()
{
    auto itemType = static_cast<NodeItem::Type>(m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
    if (itemType == NodeItem::Type::TagItem) {
        auto index = m_currentEditingIndex;
        emit changeTagColorRequested(index);
    }
}

void NodeTreeView::updateEditingIndex(QMouseEvent *event)
{
    auto index = indexAt(event->pos());
    if(indexAt(event->pos()) != m_currentEditingIndex && !m_isContextMenuOpened && !m_isEditing) {
        auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
        auto id = index.data(NodeItem::Roles::NodeId).toInt();
        if ((itemType == NodeItem::Type::FolderItem
             && id != SpecialNodeID::DefaultNotesFolder)
                || itemType == NodeItem::Type::TagItem) {
            closePersistentEditor(m_currentEditingIndex);
            openPersistentEditor(index);
            m_currentEditingIndex = index;
        } else {
            closeCurrentEditor();
        }
    }
}

void NodeTreeView::closeCurrentEditor()
{
    closePersistentEditor(m_currentEditingIndex);
    m_currentEditingIndex = QModelIndex();
}

void NodeTreeView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
    QTreeView::selectionChanged(selected, deselected);
    auto indexes = selectedIndexes();
    QSet<int> tagIds;
    for (const auto index : indexes) {
        auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
        switch (itemType) {
        case NodeItem::Type::RootItem:
        case NodeItem::Type::FolderSeparator:
        case NodeItem::Type::TagSeparator:
        case NodeItem::Type::NoteItem: {
            return;
        }
        case NodeItem::Type::AllNoteButton: {
            emit loadNotesInFolderRequested(SpecialNodeID::RootFolder, true);
            return;
        }
        case NodeItem::Type::TrashButton: {
            emit loadNotesInFolderRequested(SpecialNodeID::TrashFolder, true);
            return;
        }
        case NodeItem::Type::FolderItem: {
            auto folderId = index.data(NodeItem::Roles::NodeId).toInt();
            emit loadNotesInFolderRequested(folderId, false);
            return;
        }
        case NodeItem::Type::TagItem: {
            auto tagId = index.data(NodeItem::Roles::NodeId).toInt();
            tagIds.insert(tagId);
            break;
        }
        }
    }
    emit loadNotesInTagsRequested(tagIds);
}

void NodeTreeView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
    QTreeView::currentChanged(current, previous);
    auto itemType = static_cast<NodeItem::Type>(current.data(NodeItem::Roles::ItemType).toInt());
    if (itemType == NodeItem::Type::TagItem) {
        setSelectionMode(QAbstractItemView::MultiSelection);
    } else {
        clearSelection();
        setSelectionMode(QAbstractItemView::SingleSelection);
        selectionModel()->setCurrentIndex(current, QItemSelectionModel::Current);
    }
}

void NodeTreeView::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasFormat("text/noteId")) {
        event->acceptProposedAction();
    }
}

void NodeTreeView::dragMoveEvent(QDragMoveEvent *event)
{
    if (event->mimeData()->hasFormat("text/noteId")) {
        event->acceptProposedAction();
    }
}

void NodeTreeView::dropEvent(QDropEvent *event)
{
    if (event->mimeData()->hasFormat("text/noteId")) {
        auto dropIndex = indexAt(event->pos());
        if (dropIndex.isValid()) {
            auto itemType = static_cast<NodeItem::Type>(dropIndex.data(NodeItem::Roles::ItemType).toInt());
            bool ok = false;
            auto nodeId = QString::fromUtf8(
                        event->mimeData()->data("text/noteId")).toInt(&ok);
            if (ok) {
                if (itemType == NodeItem::Type::FolderItem) {
                    emit moveNodeRequested(nodeId, dropIndex.data(NodeItem::NodeId).toInt());
                    setCurrentIndex(dropIndex);
                    clearSelection();
                    setSelectionMode(QAbstractItemView::SingleSelection);
                    selectionModel()->setCurrentIndex(dropIndex, QItemSelectionModel::SelectCurrent);
                    event->acceptProposedAction();
                } else if (itemType == NodeItem::Type::TagItem) {
                    emit addNoteToTag(nodeId, dropIndex.data(NodeItem::NodeId).toInt());
                } else if (itemType == NodeItem::Type::TrashButton) {
                    emit moveNodeRequested(nodeId, SpecialNodeID::TrashFolder);
                    setCurrentIndex(dropIndex);
                    clearSelection();
                    setSelectionMode(QAbstractItemView::SingleSelection);
                    selectionModel()->setCurrentIndex(dropIndex, QItemSelectionModel::SelectCurrent);
                    event->acceptProposedAction();
                }
            }
        }
    }
}

void NodeTreeView::setIsEditing(bool newIsEditing)
{
    m_isEditing = newIsEditing;
}

void NodeTreeView::onRenameFolderFinished(const QString &newName)
{
    if (m_currentEditingIndex.isValid()) {
        auto itemType = static_cast<NodeItem::Type>(m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
        if (itemType == NodeItem::Type::FolderItem) {
            QModelIndex index = m_currentEditingIndex;
            closeCurrentEditor();
            emit renameFolderInDatabase(index, newName);
        } else {
            qDebug() << __FUNCTION__ << "wrong type";
        }
    } /*else {
        qDebug() << __FUNCTION__ << "m_currentEditingIndex is not valid";
    }*/
}

void NodeTreeView::onRenameTagFinished(const QString &newName)
{
    if (m_currentEditingIndex.isValid()) {
        auto itemType = static_cast<NodeItem::Type>(m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
        if (itemType == NodeItem::Type::TagItem) {
            QModelIndex index = m_currentEditingIndex;
            closeCurrentEditor();
            emit renameTagInDatabase(index, newName);
        } else {
            qDebug() << __FUNCTION__ << "wrong type";
        }
    } /*else {
        qDebug() << __FUNCTION__ << "m_currentEditingIndex is not valid";
    }*/
}

void NodeTreeView::setCurrentIndexC(const QModelIndex &index)
{
    setCurrentIndex(index);
    clearSelection();
    setSelectionMode(QAbstractItemView::SingleSelection);
    selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent);
}

void NodeTreeView::onCustomContextMenu(const QPoint &point)
{
    QModelIndex index = indexAt(point);
    if (index.isValid()) {
        auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
        contextMenu->clear();
        if (itemType == NodeItem::Type::FolderItem) {
            auto id = index.data(NodeItem::Roles::NodeId).toInt();
            if (id != SpecialNodeID::DefaultNotesFolder) {
                m_isContextMenuOpened = true;
                contextMenu->addAction(renameFolderAction);
                contextMenu->addAction(deleteFolderAction);
                contextMenu->addSeparator();
                contextMenu->addAction(addSubfolderAction);
                contextMenu->exec(viewport()->mapToGlobal(point));
            }
        } else if (itemType == NodeItem::Type::TagItem) {
            m_isContextMenuOpened = true;
            contextMenu->addAction(renameTagAction);
            contextMenu->addAction(changeTagColorAction);
            contextMenu->addAction(clearSelectionAction);
            contextMenu->addSeparator();
            contextMenu->addAction(deleteTagAction);
            contextMenu->exec(viewport()->mapToGlobal(point));
        }
    }
}

void NodeTreeView::setTreeSeparator(const QVector<QModelIndex> &newTreeSeparator)
{
    for (const auto& sep : m_treeSeparator) {
        closePersistentEditor(sep);
    }
    m_treeSeparator = newTreeSeparator;
    for (const auto& sep : m_treeSeparator) {
        openPersistentEditor(sep);
    }
}

void NodeTreeView::mouseMoveEvent(QMouseEvent *event)
{
    updateEditingIndex(event);
    QTreeView::mouseMoveEvent(event);
}

void NodeTreeView::mousePressEvent(QMouseEvent *event)
{
    updateEditingIndex(event);
    QTreeView::mousePressEvent(event);
}

void NodeTreeView::leaveEvent(QEvent *event)
{
    if (!m_isContextMenuOpened && !m_isEditing) {
        closeCurrentEditor();
        QTreeView::leaveEvent(event);
    }
}
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include <QPainter>
#include <QUrl>
#include <QFile>
#include <QDateTime>
#include <QtDBus/QDBusArgument>
#include <QDebug>
#include <XdgIcon>
#include <KWindowSystem/KWindowSystem>

#include "notification.h"
#include "notificationwidgets.h"

#define ICONSIZE QSize(32, 32)

Notification::Notification(const QString &application,
                           const QString &summary, const QString &body,
                           const QString &icon, int timeout,
                           const QStringList& actions, const QVariantMap& hints,
                           QWidget *parent)
    : QWidget(parent),
      m_timer(0),
      m_actionWidget(0)
{
    setupUi(this);
    setObjectName("Notification");
    setMouseTracking(true);

    setMaximumWidth(parent->width());
    setMinimumWidth(parent->width());

    setValues(application, summary, body, icon, timeout, actions, hints);

    connect(closeButton, SIGNAL(clicked()), this, SLOT(closeButton_clicked()));
}

void Notification::setValues(const QString &application,
                             const QString &summary, const QString &body,
                             const QString &icon, int timeout,
                             const QStringList& actions, const QVariantMap& hints)
{
    // Basic properties *********************

    // Notifications spec set real order here:
    // An implementation which only displays one image or icon must
    // choose which one to display using the following order:
    //  - "image-data"
    //  - "image-path"
    //  - app_icon parameter
    //  - for compatibility reason, "icon_data"
    if (!hints["image_data"].isNull())
    {
        m_pixmap = getPixmapFromHint(hints["image_data"]);
//        qDebug() << application << "from image_data" << m_pixmap.isNull();
    }
    else if (!hints["image_path"].isNull())
    {
        m_pixmap = getPixmapFromString(hints["image_path"].toString());
//        qDebug() << application << "from image_path" << m_pixmap.isNull();
    }
    else if (!icon.isEmpty())
    {
        m_pixmap = getPixmapFromString(icon);
//        qDebug() << application << "from icon" << icon << m_pixmap.isNull();
    }
    else if (!hints["icon_data"].isNull())
    {
       m_pixmap = getPixmapFromHint(hints["icon_data"]);
//       qDebug() << application << "from icon_data" << m_pixmap.isNull();
    }
    // issue #325: Do not display icon if it's not found...
    if (m_pixmap.isNull())
    {
        iconLabel->hide();
    }
    else
    {
        if (m_pixmap.size().width() > ICONSIZE.width()
            || m_pixmap.size().height() > ICONSIZE.height())
        {
            m_pixmap = m_pixmap.scaled(ICONSIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        }
        iconLabel->setPixmap(m_pixmap);
        iconLabel->show();
    }

    // application
	appLabel->setVisible(!application.isEmpty());
    appLabel->setText(application);

    // summary
    summaryLabel->setVisible(!summary.isEmpty());
    summaryLabel->setText(summary);

    if (application == summary)
        summaryLabel->setVisible(false);

    // body
    bodyLabel->setVisible(!body.isEmpty());
    bodyLabel->setText(body);

    // Timeout
    // Special values:
    //  < 0: server decides timeout
    //    0: infifite
    if (m_timer)
    {
        m_timer->stop();
        m_timer->deleteLater();
    }

    // -1 for server decides is handled in notifyd to save QSettings instance
    if (timeout > 0)
    {
        m_timer = new NotificationTimer(this);
        connect(m_timer, SIGNAL(timeout()), this, SIGNAL(timeout()));
        m_timer->start(timeout);
    }

    // Categories *********************
    // TODO/FIXME: Categories - how to handle it?
    if (!hints["category"].isNull())
    {
        qDebug() << "Notification" << application << "category" << hints["category"];
    }

    // Urgency Levels *********************
    // Type    Description
    // 0   Low
    // 1   Normal
    // 2   Critical
    // TODO/FIXME: Urgencies - how to handle it?
    if (!hints["urgency"].isNull())
    {
        qDebug() << "Notification" << application << "urgency" << hints["urgency"];
    }

    // Actions
    if (actions.count() && m_actionWidget == 0)
    {
        if (actions.count()/2 < 4)
            m_actionWidget = new NotificationActionsButtonsWidget(actions, this);
        else
            m_actionWidget = new NotificationActionsComboWidget(actions, this);
        connect(m_actionWidget, SIGNAL(actionTriggered(const QString &)),
                this, SIGNAL(actionTriggered(const QString &)));
        actionsLayout->addWidget(m_actionWidget);
        m_actionWidget->show();
    }

    adjustSize();
    // ensure layout expansion
    setMinimumHeight(qMax(rect().height(), childrenRect().height()));
}

QString Notification::application() const
{
    return appLabel->text();
}

QString Notification::summary() const
{
    return summaryLabel->text();
}

QString Notification::body() const
{
    return bodyLabel->text();
}

void Notification::closeButton_clicked()
{
    if (m_timer)
        m_timer->stop();
    emit userCanceled();
}

void Notification::paintEvent(QPaintEvent *)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

QPixmap Notification::getPixmapFromHint(const QVariant &argument) const
{
    int width, height, rowstride, bitsPerSample, channels;
    bool hasAlpha;
    QByteArray data;

    const QDBusArgument arg = argument.value<QDBusArgument>();
    arg.beginStructure();
    arg >> width;
    arg >> height;
    arg >> rowstride;
    arg >> hasAlpha;
    arg >> bitsPerSample;
    arg >> channels;
    arg >> data;
    arg.endStructure();
    QImage img = QImage((uchar*)data.constData(), width, height, QImage::Format_ARGB32).rgbSwapped();

    return QPixmap::fromImage(img);
}

QPixmap Notification::getPixmapFromString(const QString &str) const
{
    QUrl url(str);
    if (url.isValid() && QFile::exists(url.toLocalFile()))
    {
//        qDebug() << "    getPixmapFromString by URL" << url;
        return QPixmap(url.toLocalFile());
    }
    else
    {
//        qDebug() << "    getPixmapFromString by XdgIcon theme" << str << ICONSIZE << XdgIcon::themeName();
//        qDebug() << "       " << XdgIcon::fromTheme(str) << "isnull:" << XdgIcon::fromTheme(str).isNull();
        // They say: do not display an icon if it;s not found - see #325
        return XdgIcon::fromTheme(str/*, XdgIcon::defaultApplicationIcon()*/).pixmap(ICONSIZE);
    }
}

void Notification::enterEvent(QEvent * event)
{
    if (m_timer)
        m_timer->pause();
}

void Notification::leaveEvent(QEvent * event)
{
    if (m_timer)
        m_timer->resume();
}

void Notification::mouseReleaseEvent(QMouseEvent * event)
{
//    qDebug() << "CLICKED" << event;
    QString appName;
    QString windowTitle;

    if (m_actionWidget && m_actionWidget->hasDefaultAction())
    {
        emit actionTriggered(m_actionWidget->defaultAction());
        return;
    }

    foreach (WId i, KWindowSystem::stackingOrder())
    {
        KWindowInfo info = KWindowInfo(i, NET::WMName | NET::WMVisibleName);
        appName = info.name();
        windowTitle = info.visibleName();
        // qDebug() << "    " << i << "APPNAME" << appName << "TITLE" << windowTitle;
        if (appName.isEmpty())
        {
            QWidget::mouseReleaseEvent(event);
            return;
        }
        if (appName == appLabel->text() || windowTitle == appLabel->text())
        {
            KWindowSystem::raiseWindow(i);
            closeButton_clicked();
            return;
        }
    }
}

NotificationTimer::NotificationTimer(QObject *parent)
    : QTimer(parent),
      m_intervalMsec(-1)
{
}

void NotificationTimer::start(int msec)
{
    m_startTime = QDateTime::currentDateTime();
    m_intervalMsec = msec;
    QTimer::start(msec);
}

void NotificationTimer::pause()
{
    if (!isActive())
        return;

    stop();
    m_intervalMsec = m_startTime.msecsTo(QDateTime());
}

void NotificationTimer::resume()
{
    if (isActive())
        return;

    start(m_intervalMsec);
}
<commit_msg>notification: multilined plain text formatting<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include <QPainter>
#include <QUrl>
#include <QFile>
#include <QDateTime>
#include <QtDBus/QDBusArgument>
#include <QDebug>
#include <XdgIcon>
#include <KWindowSystem/KWindowSystem>

#include "notification.h"
#include "notificationwidgets.h"

#define ICONSIZE QSize(32, 32)

Notification::Notification(const QString &application,
                           const QString &summary, const QString &body,
                           const QString &icon, int timeout,
                           const QStringList& actions, const QVariantMap& hints,
                           QWidget *parent)
    : QWidget(parent),
      m_timer(0),
      m_actionWidget(0)
{
    setupUi(this);
    setObjectName("Notification");
    setMouseTracking(true);

    setMaximumWidth(parent->width());
    setMinimumWidth(parent->width());

    setValues(application, summary, body, icon, timeout, actions, hints);

    connect(closeButton, SIGNAL(clicked()), this, SLOT(closeButton_clicked()));
}

void Notification::setValues(const QString &application,
                             const QString &summary, const QString &body,
                             const QString &icon, int timeout,
                             const QStringList& actions, const QVariantMap& hints)
{
    // Basic properties *********************

    // Notifications spec set real order here:
    // An implementation which only displays one image or icon must
    // choose which one to display using the following order:
    //  - "image-data"
    //  - "image-path"
    //  - app_icon parameter
    //  - for compatibility reason, "icon_data"
    if (!hints["image_data"].isNull())
    {
        m_pixmap = getPixmapFromHint(hints["image_data"]);
//        qDebug() << application << "from image_data" << m_pixmap.isNull();
    }
    else if (!hints["image_path"].isNull())
    {
        m_pixmap = getPixmapFromString(hints["image_path"].toString());
//        qDebug() << application << "from image_path" << m_pixmap.isNull();
    }
    else if (!icon.isEmpty())
    {
        m_pixmap = getPixmapFromString(icon);
//        qDebug() << application << "from icon" << icon << m_pixmap.isNull();
    }
    else if (!hints["icon_data"].isNull())
    {
       m_pixmap = getPixmapFromHint(hints["icon_data"]);
//       qDebug() << application << "from icon_data" << m_pixmap.isNull();
    }
    // issue #325: Do not display icon if it's not found...
    if (m_pixmap.isNull())
    {
        iconLabel->hide();
    }
    else
    {
        if (m_pixmap.size().width() > ICONSIZE.width()
            || m_pixmap.size().height() > ICONSIZE.height())
        {
            m_pixmap = m_pixmap.scaled(ICONSIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        }
        iconLabel->setPixmap(m_pixmap);
        iconLabel->show();
    }

    // application
	appLabel->setVisible(!application.isEmpty());
    appLabel->setText(application);

    // summary
    summaryLabel->setVisible(!summary.isEmpty());
    summaryLabel->setText(summary);

    if (application == summary)
        summaryLabel->setVisible(false);

    // body
    bodyLabel->setVisible(!body.isEmpty());
    //https://developer.gnome.org/notification-spec
    //Body - This is a multi-line body of text. Each line is a paragraph, server implementations are free to word wrap them as they see fit.
    //XXX: remove all unsupported tags?!? (supported <b>, <i>, <u>, <a>, <img>)
    QString formatted(body);
    bodyLabel->setText(formatted.replace('\n', QStringLiteral("<br/>")));

    // Timeout
    // Special values:
    //  < 0: server decides timeout
    //    0: infifite
    if (m_timer)
    {
        m_timer->stop();
        m_timer->deleteLater();
    }

    // -1 for server decides is handled in notifyd to save QSettings instance
    if (timeout > 0)
    {
        m_timer = new NotificationTimer(this);
        connect(m_timer, SIGNAL(timeout()), this, SIGNAL(timeout()));
        m_timer->start(timeout);
    }

    // Categories *********************
    // TODO/FIXME: Categories - how to handle it?
    if (!hints["category"].isNull())
    {
        qDebug() << "Notification" << application << "category" << hints["category"];
    }

    // Urgency Levels *********************
    // Type    Description
    // 0   Low
    // 1   Normal
    // 2   Critical
    // TODO/FIXME: Urgencies - how to handle it?
    if (!hints["urgency"].isNull())
    {
        qDebug() << "Notification" << application << "urgency" << hints["urgency"];
    }

    // Actions
    if (actions.count() && m_actionWidget == 0)
    {
        if (actions.count()/2 < 4)
            m_actionWidget = new NotificationActionsButtonsWidget(actions, this);
        else
            m_actionWidget = new NotificationActionsComboWidget(actions, this);
        connect(m_actionWidget, SIGNAL(actionTriggered(const QString &)),
                this, SIGNAL(actionTriggered(const QString &)));
        actionsLayout->addWidget(m_actionWidget);
        m_actionWidget->show();
    }

    adjustSize();
    // ensure layout expansion
    setMinimumHeight(qMax(rect().height(), childrenRect().height()));
}

QString Notification::application() const
{
    return appLabel->text();
}

QString Notification::summary() const
{
    return summaryLabel->text();
}

QString Notification::body() const
{
    return bodyLabel->text();
}

void Notification::closeButton_clicked()
{
    if (m_timer)
        m_timer->stop();
    emit userCanceled();
}

void Notification::paintEvent(QPaintEvent *)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

QPixmap Notification::getPixmapFromHint(const QVariant &argument) const
{
    int width, height, rowstride, bitsPerSample, channels;
    bool hasAlpha;
    QByteArray data;

    const QDBusArgument arg = argument.value<QDBusArgument>();
    arg.beginStructure();
    arg >> width;
    arg >> height;
    arg >> rowstride;
    arg >> hasAlpha;
    arg >> bitsPerSample;
    arg >> channels;
    arg >> data;
    arg.endStructure();
    QImage img = QImage((uchar*)data.constData(), width, height, QImage::Format_ARGB32).rgbSwapped();

    return QPixmap::fromImage(img);
}

QPixmap Notification::getPixmapFromString(const QString &str) const
{
    QUrl url(str);
    if (url.isValid() && QFile::exists(url.toLocalFile()))
    {
//        qDebug() << "    getPixmapFromString by URL" << url;
        return QPixmap(url.toLocalFile());
    }
    else
    {
//        qDebug() << "    getPixmapFromString by XdgIcon theme" << str << ICONSIZE << XdgIcon::themeName();
//        qDebug() << "       " << XdgIcon::fromTheme(str) << "isnull:" << XdgIcon::fromTheme(str).isNull();
        // They say: do not display an icon if it;s not found - see #325
        return XdgIcon::fromTheme(str/*, XdgIcon::defaultApplicationIcon()*/).pixmap(ICONSIZE);
    }
}

void Notification::enterEvent(QEvent * event)
{
    if (m_timer)
        m_timer->pause();
}

void Notification::leaveEvent(QEvent * event)
{
    if (m_timer)
        m_timer->resume();
}

void Notification::mouseReleaseEvent(QMouseEvent * event)
{
//    qDebug() << "CLICKED" << event;
    QString appName;
    QString windowTitle;

    if (m_actionWidget && m_actionWidget->hasDefaultAction())
    {
        emit actionTriggered(m_actionWidget->defaultAction());
        return;
    }

    foreach (WId i, KWindowSystem::stackingOrder())
    {
        KWindowInfo info = KWindowInfo(i, NET::WMName | NET::WMVisibleName);
        appName = info.name();
        windowTitle = info.visibleName();
        // qDebug() << "    " << i << "APPNAME" << appName << "TITLE" << windowTitle;
        if (appName.isEmpty())
        {
            QWidget::mouseReleaseEvent(event);
            return;
        }
        if (appName == appLabel->text() || windowTitle == appLabel->text())
        {
            KWindowSystem::raiseWindow(i);
            closeButton_clicked();
            return;
        }
    }
}

NotificationTimer::NotificationTimer(QObject *parent)
    : QTimer(parent),
      m_intervalMsec(-1)
{
}

void NotificationTimer::start(int msec)
{
    m_startTime = QDateTime::currentDateTime();
    m_intervalMsec = msec;
    QTimer::start(msec);
}

void NotificationTimer::pause()
{
    if (!isActive())
        return;

    stop();
    m_intervalMsec = m_startTime.msecsTo(QDateTime());
}

void NotificationTimer::resume()
{
    if (isActive())
        return;

    start(m_intervalMsec);
}
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2012, Willow Garage, Inc.
 *
 *  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 Willow Garage, Inc. nor the names of its
 *     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 OWNER 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 <pcl/pcl_config.h>
#include <pcl/io/pcd_grabber.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/tar.h>

#ifdef _WIN32
# include <io.h>
# include <windows.h>
# define pcl_open                    _open
# define pcl_close(fd)               _close(fd)
# define pcl_lseek(fd,offset,origin) _lseek(fd,offset,origin)
#else
# include <sys/mman.h>
# define pcl_open                    open
# define pcl_close(fd)               close(fd)
# define pcl_lseek(fd,offset,origin) lseek(fd,offset,origin)
#endif

///////////////////////////////////////////////////////////////////////////////////////////
//////////////////////// GrabberImplementation //////////////////////
struct pcl::PCDGrabberBase::PCDGrabberImpl
{
  PCDGrabberImpl (pcl::PCDGrabberBase& grabber, const std::string& pcd_path, float frames_per_second, bool repeat);
  PCDGrabberImpl (pcl::PCDGrabberBase& grabber, const std::vector<std::string>& pcd_files, float frames_per_second, bool repeat);
  void trigger ();
  void readAhead ();

  // TAR reading I/O
  int openTARFile (const std::string &file_name);
  void closeTARFile ();
  bool readTARHeader ();

  pcl::PCDGrabberBase& grabber_;
  float frames_per_second_;
  bool repeat_;
  bool running_;
  std::vector<std::string> pcd_files_;
  std::vector<std::string>::iterator pcd_iterator_;
  TimeTrigger time_trigger_;

  sensor_msgs::PointCloud2 next_cloud_;
  Eigen::Vector4f origin_;
  Eigen::Quaternionf orientation_;
  bool valid_;

  // TAR reading I/O
  int tar_fd_;
  int tar_offset_;
  std::string tar_file_;
  pcl::io::TARHeader tar_header_;

  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

///////////////////////////////////////////////////////////////////////////////////////////
pcl::PCDGrabberBase::PCDGrabberImpl::PCDGrabberImpl (pcl::PCDGrabberBase& grabber, const std::string& pcd_path, float frames_per_second, bool repeat)
  : grabber_ (grabber)
  , frames_per_second_ (frames_per_second)
  , repeat_ (repeat)
  , running_ (false)
  , pcd_files_ ()
  , pcd_iterator_ ()
  , time_trigger_ (1.0 / static_cast<double> (std::max (frames_per_second, 0.001f)), boost::bind (&PCDGrabberImpl::trigger, this))
  , next_cloud_ ()
  , origin_ ()
  , orientation_ ()
  , valid_ (false)
  , tar_fd_ (-1)
  , tar_offset_ (0)
  , tar_file_ ()
  , tar_header_ ()
{
  pcd_files_.push_back (pcd_path);
  pcd_iterator_ = pcd_files_.begin ();
}

///////////////////////////////////////////////////////////////////////////////////////////
pcl::PCDGrabberBase::PCDGrabberImpl::PCDGrabberImpl (pcl::PCDGrabberBase& grabber, const std::vector<std::string>& pcd_files, float frames_per_second, bool repeat)
  : grabber_ (grabber)
  , frames_per_second_ (frames_per_second)
  , repeat_ (repeat)
  , running_ (false)
  , pcd_files_ ()
  , pcd_iterator_ ()
  , time_trigger_ (1.0 / static_cast<double> (std::max (frames_per_second, 0.001f)), boost::bind (&PCDGrabberImpl::trigger, this))
  , next_cloud_ ()
  , origin_ ()
  , orientation_ ()
  , valid_ (false)
  , tar_fd_ (-1)
  , tar_offset_ (0)
  , tar_file_ ()
  , tar_header_ ()
{
  pcd_files_ = pcd_files;
  pcd_iterator_ = pcd_files_.begin ();
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::PCDGrabberImpl::readAhead ()
{
  PCDReader reader;
  int pcd_version;

  // Check if we're still reading files from a TAR file
  if (tar_fd_ != -1)
  {
    readTARHeader ();
    valid_ = (reader.read (tar_file_, next_cloud_, origin_, orientation_, pcd_version, tar_offset_) == 0);
    if (!valid_)
      closeTARFile ();
    else
    {
      tar_offset_ += (tar_header_.getFileSize ()) + (512 - tar_header_.getFileSize () % 512);
      int result = static_cast<int> (pcl_lseek (tar_fd_, tar_offset_, SEEK_SET));
      if (result < 0)
        closeTARFile ();
    }
  }
  // We're not still reading from a TAR file, so check if there are other PCD/TAR files in the list
  else
  {
    if (pcd_iterator_ != pcd_files_.end ())
    {
      // Try to read in the file as a PCD first
      valid_ = (reader.read (*pcd_iterator_, next_cloud_, origin_, orientation_, pcd_version) == 0);

      // Has an error occured? Check if we can interpret the file as a TAR file first before going onto the next
      if (!valid_)
      {
        if (openTARFile (*pcd_iterator_) >= 0)
        {
          readTARHeader ();
          tar_file_ = *pcd_iterator_;
          valid_ = (reader.read (tar_file_, next_cloud_, origin_, orientation_, pcd_version, tar_offset_) == 0);
          if (!valid_)
            closeTARFile ();
          else
          {
            tar_offset_ += (tar_header_.getFileSize ()) + (512 - tar_header_.getFileSize () % 512);
            int result = static_cast<int> (pcl_lseek (tar_fd_, tar_offset_, SEEK_SET));
            if (result < 0)
              closeTARFile ();
          }
        }
      }

      if (++pcd_iterator_ == pcd_files_.end () && repeat_)
        pcd_iterator_ = pcd_files_.begin ();
    }
    else
      valid_ = false;
  }
}

///////////////////////////////////////////////////////////////////////////////////////////
bool
pcl::PCDGrabberBase::PCDGrabberImpl::readTARHeader ()
{
  // Read in the header
  int result = static_cast<int> (::read (tar_fd_, reinterpret_cast<char*> (&tar_header_), 512));
  if (result == -1)
  {
    closeTARFile ();
    return (false);
  }

  // We only support regular files for now.
  // Addional file types in TAR include: hard links, symbolic links, device/special files, block devices,
  // directories, and named pipes.
  if (tar_header_.file_type[0] != '0' && tar_header_.file_type[0] != '\0')
  {
    closeTARFile ();
    return (false);
  }

  // We only support USTAR version 0 files for now
  if (std::string (tar_header_.ustar).substr (0, 5) != "ustar")
  {
    closeTARFile ();
    return (false);
  }

  if (tar_header_.getFileSize () == 0)
  {
    closeTARFile ();
    return (false);
  }

  tar_offset_ += 512;

  return (true);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::PCDGrabberImpl::closeTARFile ()
{
  pcl_close (tar_fd_);
  tar_fd_ = -1;
  tar_offset_ = 0;
  memset (&tar_header_.file_name[0], 0, 512);
}

///////////////////////////////////////////////////////////////////////////////////////////
int
pcl::PCDGrabberBase::PCDGrabberImpl::openTARFile (const std::string &file_name)
{
  tar_fd_ = pcl_open (file_name.c_str (), O_RDONLY);
  if (tar_fd_ == -1)
    return (-1);

  return (0);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::PCDGrabberImpl::trigger ()
{
  if (valid_)
    grabber_.publish (next_cloud_,origin_,orientation_);

  // use remaining time, if there is time left!
  readAhead ();
}

///////////////////////////////////////////////////////////////////////////////////////////
//////////////////////// GrabberBase //////////////////////
pcl::PCDGrabberBase::PCDGrabberBase (const std::string& pcd_path, float frames_per_second, bool repeat)
: impl_ (new PCDGrabberImpl (*this, pcd_path, frames_per_second, repeat))
{
}

///////////////////////////////////////////////////////////////////////////////////////////
pcl::PCDGrabberBase::PCDGrabberBase (const std::vector<std::string>& pcd_files, float frames_per_second, bool repeat)
: impl_ (new PCDGrabberImpl (*this, pcd_files, frames_per_second, repeat))
{
}

///////////////////////////////////////////////////////////////////////////////////////////
pcl::PCDGrabberBase::~PCDGrabberBase () throw ()
{
  stop ();
  delete impl_;
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::start ()
{
  if (impl_->frames_per_second_ > 0)
  {
    impl_->running_ = true;
    impl_->time_trigger_.start ();
  }
  else // manual trigger
    impl_->trigger ();
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::stop ()
{
  if (impl_->frames_per_second_ > 0)
  {
    impl_->time_trigger_.stop ();
    impl_->running_ = false;
  }
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::trigger ()
{
  if (impl_->frames_per_second_ > 0)
    return;
  impl_->trigger ();
}

///////////////////////////////////////////////////////////////////////////////////////////
bool
pcl::PCDGrabberBase::isRunning () const
{
  return (impl_->running_);
}

///////////////////////////////////////////////////////////////////////////////////////////
std::string
pcl::PCDGrabberBase::getName () const
{
  return ("PCDGrabber");
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::rewind ()
{
  impl_->pcd_iterator_ = impl_->pcd_files_.begin ();
}

///////////////////////////////////////////////////////////////////////////////////////////
float
pcl::PCDGrabberBase::getFramesPerSecond () const
{
  return (impl_->frames_per_second_);
}

///////////////////////////////////////////////////////////////////////////////////////////
bool
pcl::PCDGrabberBase::isRepeatOn () const
{
  return (impl_->repeat_);
}

<commit_msg>fixed a mistake introduced in r6944<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2012, Willow Garage, Inc.
 *
 *  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 Willow Garage, Inc. nor the names of its
 *     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 OWNER 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 <pcl/pcl_config.h>
#include <pcl/io/pcd_grabber.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/tar.h>

#ifdef _WIN32
# include <io.h>
# include <windows.h>
# define pcl_open                    _open
# define pcl_close(fd)               _close(fd)
# define pcl_lseek(fd,offset,origin) _lseek(fd,offset,origin)
#else
# include <sys/mman.h>
# define pcl_open                    open
# define pcl_close(fd)               close(fd)
# define pcl_lseek(fd,offset,origin) lseek(fd,offset,origin)
#endif

///////////////////////////////////////////////////////////////////////////////////////////
//////////////////////// GrabberImplementation //////////////////////
struct pcl::PCDGrabberBase::PCDGrabberImpl
{
  PCDGrabberImpl (pcl::PCDGrabberBase& grabber, const std::string& pcd_path, float frames_per_second, bool repeat);
  PCDGrabberImpl (pcl::PCDGrabberBase& grabber, const std::vector<std::string>& pcd_files, float frames_per_second, bool repeat);
  void trigger ();
  void readAhead ();

  // TAR reading I/O
  int openTARFile (const std::string &file_name);
  void closeTARFile ();
  bool readTARHeader ();

  pcl::PCDGrabberBase& grabber_;
  float frames_per_second_;
  bool repeat_;
  bool running_;
  std::vector<std::string> pcd_files_;
  std::vector<std::string>::iterator pcd_iterator_;
  TimeTrigger time_trigger_;

  sensor_msgs::PointCloud2 next_cloud_;
  Eigen::Vector4f origin_;
  Eigen::Quaternionf orientation_;
  bool valid_;

  // TAR reading I/O
  int tar_fd_;
  int tar_offset_;
  std::string tar_file_;
  pcl::io::TARHeader tar_header_;

  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

///////////////////////////////////////////////////////////////////////////////////////////
pcl::PCDGrabberBase::PCDGrabberImpl::PCDGrabberImpl (pcl::PCDGrabberBase& grabber, const std::string& pcd_path, float frames_per_second, bool repeat)
  : grabber_ (grabber)
  , frames_per_second_ (frames_per_second)
  , repeat_ (repeat)
  , running_ (false)
  , pcd_files_ ()
  , pcd_iterator_ ()
  , time_trigger_ (1.0 / static_cast<double> (std::max (frames_per_second, 0.001f)), boost::bind (&PCDGrabberImpl::trigger, this))
  , next_cloud_ ()
  , origin_ ()
  , orientation_ ()
  , valid_ (false)
  , tar_fd_ (-1)
  , tar_offset_ (0)
  , tar_file_ ()
  , tar_header_ ()
{
  pcd_files_.push_back (pcd_path);
  pcd_iterator_ = pcd_files_.begin ();
}

///////////////////////////////////////////////////////////////////////////////////////////
pcl::PCDGrabberBase::PCDGrabberImpl::PCDGrabberImpl (pcl::PCDGrabberBase& grabber, const std::vector<std::string>& pcd_files, float frames_per_second, bool repeat)
  : grabber_ (grabber)
  , frames_per_second_ (frames_per_second)
  , repeat_ (repeat)
  , running_ (false)
  , pcd_files_ ()
  , pcd_iterator_ ()
  , time_trigger_ (1.0 / static_cast<double> (std::max (frames_per_second, 0.001f)), boost::bind (&PCDGrabberImpl::trigger, this))
  , next_cloud_ ()
  , origin_ ()
  , orientation_ ()
  , valid_ (false)
  , tar_fd_ (-1)
  , tar_offset_ (0)
  , tar_file_ ()
  , tar_header_ ()
{
  pcd_files_ = pcd_files;
  pcd_iterator_ = pcd_files_.begin ();
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::PCDGrabberImpl::readAhead ()
{
  PCDReader reader;
  int pcd_version;

  // Check if we're still reading files from a TAR file
  if (tar_fd_ != -1)
  {
    if (!readTARHeader ())
      return;
    valid_ = (reader.read (tar_file_, next_cloud_, origin_, orientation_, pcd_version, tar_offset_) == 0);
    if (!valid_)
      closeTARFile ();
    else
    {
      tar_offset_ += (tar_header_.getFileSize ()) + (512 - tar_header_.getFileSize () % 512);
      int result = static_cast<int> (pcl_lseek (tar_fd_, tar_offset_, SEEK_SET));
      if (result < 0)
        closeTARFile ();
    }
  }
  // We're not still reading from a TAR file, so check if there are other PCD/TAR files in the list
  else
  {
    if (pcd_iterator_ != pcd_files_.end ())
    {
      // Try to read in the file as a PCD first
      valid_ = (reader.read (*pcd_iterator_, next_cloud_, origin_, orientation_, pcd_version) == 0);

      // Has an error occured? Check if we can interpret the file as a TAR file first before going onto the next
      if (!valid_ && openTARFile (*pcd_iterator_) >= 0 && readTARHeader ())
      {
        tar_file_ = *pcd_iterator_;
        valid_ = (reader.read (tar_file_, next_cloud_, origin_, orientation_, pcd_version, tar_offset_) == 0);
        if (!valid_)
          closeTARFile ();
        else
        {
          tar_offset_ += (tar_header_.getFileSize ()) + (512 - tar_header_.getFileSize () % 512);
          int result = static_cast<int> (pcl_lseek (tar_fd_, tar_offset_, SEEK_SET));
          if (result < 0)
            closeTARFile ();
        }
      }

      if (++pcd_iterator_ == pcd_files_.end () && repeat_)
        pcd_iterator_ = pcd_files_.begin ();
    }
    else
      valid_ = false;
  }
}

///////////////////////////////////////////////////////////////////////////////////////////
bool
pcl::PCDGrabberBase::PCDGrabberImpl::readTARHeader ()
{
  // Read in the header
  int result = static_cast<int> (::read (tar_fd_, reinterpret_cast<char*> (&tar_header_), 512));
  if (result == -1)
  {
    closeTARFile ();
    return (false);
  }

  // We only support regular files for now.
  // Addional file types in TAR include: hard links, symbolic links, device/special files, block devices,
  // directories, and named pipes.
  if (tar_header_.file_type[0] != '0' && tar_header_.file_type[0] != '\0')
  {
    closeTARFile ();
    return (false);
  }

  // We only support USTAR version 0 files for now
  if (std::string (tar_header_.ustar).substr (0, 5) != "ustar")
  {
    closeTARFile ();
    return (false);
  }

  if (tar_header_.getFileSize () == 0)
  {
    closeTARFile ();
    return (false);
  }

  tar_offset_ += 512;

  return (true);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::PCDGrabberImpl::closeTARFile ()
{
  pcl_close (tar_fd_);
  tar_fd_ = -1;
  tar_offset_ = 0;
  memset (&tar_header_.file_name[0], 0, 512);
}

///////////////////////////////////////////////////////////////////////////////////////////
int
pcl::PCDGrabberBase::PCDGrabberImpl::openTARFile (const std::string &file_name)
{
  tar_fd_ = pcl_open (file_name.c_str (), O_RDONLY);
  if (tar_fd_ == -1)
    return (-1);

  return (0);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::PCDGrabberImpl::trigger ()
{
  if (valid_)
    grabber_.publish (next_cloud_,origin_,orientation_);

  // use remaining time, if there is time left!
  readAhead ();
}

///////////////////////////////////////////////////////////////////////////////////////////
//////////////////////// GrabberBase //////////////////////
pcl::PCDGrabberBase::PCDGrabberBase (const std::string& pcd_path, float frames_per_second, bool repeat)
: impl_ (new PCDGrabberImpl (*this, pcd_path, frames_per_second, repeat))
{
}

///////////////////////////////////////////////////////////////////////////////////////////
pcl::PCDGrabberBase::PCDGrabberBase (const std::vector<std::string>& pcd_files, float frames_per_second, bool repeat)
: impl_ (new PCDGrabberImpl (*this, pcd_files, frames_per_second, repeat))
{
}

///////////////////////////////////////////////////////////////////////////////////////////
pcl::PCDGrabberBase::~PCDGrabberBase () throw ()
{
  stop ();
  delete impl_;
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::start ()
{
  if (impl_->frames_per_second_ > 0)
  {
    impl_->running_ = true;
    impl_->time_trigger_.start ();
  }
  else // manual trigger
    impl_->trigger ();
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::stop ()
{
  if (impl_->frames_per_second_ > 0)
  {
    impl_->time_trigger_.stop ();
    impl_->running_ = false;
  }
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::trigger ()
{
  if (impl_->frames_per_second_ > 0)
    return;
  impl_->trigger ();
}

///////////////////////////////////////////////////////////////////////////////////////////
bool
pcl::PCDGrabberBase::isRunning () const
{
  return (impl_->running_);
}

///////////////////////////////////////////////////////////////////////////////////////////
std::string
pcl::PCDGrabberBase::getName () const
{
  return ("PCDGrabber");
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::PCDGrabberBase::rewind ()
{
  impl_->pcd_iterator_ = impl_->pcd_files_.begin ();
}

///////////////////////////////////////////////////////////////////////////////////////////
float
pcl::PCDGrabberBase::getFramesPerSecond () const
{
  return (impl_->frames_per_second_);
}

///////////////////////////////////////////////////////////////////////////////////////////
bool
pcl::PCDGrabberBase::isRepeatOn () const
{
  return (impl_->repeat_);
}

<|endoftext|>