<commit_before>#include "latex.hpp"

#include <boost/filesystem.hpp>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <libplatform/libplatform.h>
#include <wkhtmltox/image.h>

std::string Latex::_find_katex_path()
{
	for (std::string dir = "./", end = "../../../"; dir != end; dir += "../")
	{
		for (const auto& file : boost::filesystem::directory_iterator(dir))
		{
			auto path = file.path();

			if (path.stem() == "katex" && boost::filesystem::is_directory(path))
			{
				return path.string();
			}
		}
	}

	// We don't need the CSS necessarily, but do need the JavaScript.
	throw ExistentialException("Could not find KaTeX directory!");
}

std::string Latex::_katex_path;

Latex::V8 Latex::_v8;

Latex::Latex(WarningBehavior behavior)
: Latex("../../katex/katex.min.css", behavior)
{ }

Latex::Latex(const std::string& stylesheet, WarningBehavior behavior)
: _stylesheet(stylesheet)
, _warning_behaviour(behavior)
, _isolate(_new_isolate())
{
	if (_katex_path.empty())
	{
		_katex_path = _find_katex_path();
	}

	v8::HandleScope handle_scope(_isolate);

	v8::Isolate::Scope isolate_scope(_isolate);

	auto context = v8::Context::New(_isolate);

	v8::Context::Scope context_scope(context);

	_load_katex(context);

	_persistent_context = v8::UniquePersistent<v8::Context>(_isolate, context);

	wkhtmltoimage_init(false);
}

Latex::Latex(const Latex& other)
: Latex(other._stylesheet,
		other._warning_behaviour)
{
	_additional_css = other._additional_css;
}

Latex::Latex(Latex&& other) noexcept
: Latex()
{
	swap(other);
}

Latex& Latex::operator=(Latex other)
{
	swap(other);

	return *this;
}

void Latex::swap(Latex &other) noexcept
{
	// Enable ADL
	using std::swap;

	swap(_allocator, other._allocator);

	swap(_isolate, other._isolate);

	swap(_persistent_context, other._persistent_context);

	swap(_stylesheet, other._stylesheet);

	swap(_additional_css, other._additional_css);

	swap(_warning_behaviour, other._warning_behaviour);
}

void swap(Latex& first, Latex& second) noexcept
{
	first.swap(second);
}

Latex::~Latex()
{
	wkhtmltoimage_deinit();
}

std::string Latex::to_html(const std::string& latex) const
{
	static const std::string arguments = "{'displayMode': true}";

	v8::Isolate::Scope isolate_scope(_isolate);

	// Stack-allocated handle-scope (takes care of handles such
	// that object are garbage-collected after the scope ends)
	v8::HandleScope handle_scope(_isolate);

	// Get a local context handle from the persistent handle.
	auto context = v8::Local<v8::Context>::New(_isolate,
											   _persistent_context);

	v8::Context::Scope context_scope(context);

	std::string source = "katex.renderToString('";

	source += _escape(latex) + "', ";
	source += arguments + ");";

	auto value = _run(source, context);

	std::string html = *static_cast<v8::String::Utf8Value>(value);

	return "
\n" + html + "
\n";
}

std::string Latex::to_complete_html(const std::string &latex) const
{
	auto snippet = to_html(latex);

	std::string html = "<!DOCTYPE html>\n\n";

	html += "\n<meta charset='utf-8'/>\n";
	html += "<link rel='stylesheet' type='text/css' ";
 	html += "href='" + _stylesheet + "'>\n";

	if (! _additional_css.empty())
	{
		html += "\n";
	}

	html += "\n\n";
	html += snippet;
	html += "\n";

	return html;
}

void Latex::to_image(const std::string &latex,
				  const std::string &filepath,
				  ImageFormat format) const
{
	std::ofstream temp("temp.html");

	if (! temp) throw FileException("Could not open temporary file!");

	temp << to_complete_html(latex);

	temp.close();

	auto converter = _new_converter(filepath, format);

	if (! wkhtmltoimage_convert(converter))
	{
		throw ConversionException("Could not convert to png!");
	}

	wkhtmltoimage_destroy_converter(converter);

	boost::filesystem::remove("temp.html");
}

void Latex::to_png(const std::string &latex,
				const std::string &filepath) const
{
	to_image(latex, filepath, ImageFormat::PNG);
}

void Latex::to_jpg(const std::string &latex,
				const std::string &filepath) const
{
	to_image(latex, filepath, ImageFormat::JPG);
}

void Latex::to_svg(const std::string &latex,
				const std::string &filepath) const
{
	to_image(latex, filepath, ImageFormat::SVG);
}

void Latex::add_css(const std::string& css)
{
	_additional_css += css;
}

const std::string& Latex::additional_css() const
{
	return _additional_css;
}

void Latex::clear_additional_css()
{
	_additional_css.clear();
}

const std::string& Latex::stylesheet() const
{
	return _stylesheet;
}

void Latex::stylesheet(const std::string& stylesheet)
{
	_stylesheet = stylesheet;
}

const Latex::WarningBehavior& Latex::warning_behavior() const
{
	return _warning_behaviour;
}

void Latex::warning_behavior(WarningBehavior behavior)
{
	_warning_behaviour = behavior;
}

v8::Isolate* Latex::_new_isolate() const
{
	v8::Isolate::CreateParams parameters;

	parameters.array_buffer_allocator = &_allocator;

	// Isolated JavaScript Virtual Environment
	return v8::Isolate::New(parameters);
}

void Latex::_load_katex(const v8::Local<v8::Context>& context) const
{
	std::ifstream file(_katex_path + "/katex.min.js");

	std::string source;
	std::string input;

	while (std::getline(file, input))
	{
		source += input + " ";
	}

	_run(source, context);
}

v8::Local<v8::Value> Latex::_run(const std::string& source,
								 const v8::Local<v8::Context>& context) const
{
	v8::EscapableHandleScope handle_scope(_isolate);

	auto unchecked = v8::String::NewFromUtf8(_isolate,
											 source.c_str(),
											 v8::NewStringType::kNormal);

	auto checked = unchecked.ToLocalChecked();

	// Compile the source code.
	auto script = v8::Script::Compile(context, checked).ToLocalChecked();

	// V8 engine's try-catch mechanism
	v8::TryCatch try_catch(_isolate);

	auto result = script->Run(context);

	if (result.IsEmpty())
	{
		// Grab last exception
		auto exception = try_catch.Exception();

		std::string what = *static_cast<v8::String::Utf8Value>(exception);

		// Remove the 'ParseError' (redundant)
		throw ParseException(what.substr(12));
	}

	// Allows us to return local-scope objects to the outside scope
	return handle_scope.Escape(result.ToLocalChecked());
}

std::string Latex::_escape(std::string source) const
{
	for (auto i = source.begin(); i != source.end(); ++i)
	{
		if (*i == '\\')
		{
			i = source.insert(i, '\\');

			++i;
		}
	}

	return source;
}

void _throw(wkhtmltoimage_converter*, const char* message)
{
	throw Latex::ConversionException(message);
}

void _log(wkhtmltoimage_converter*, const char* message)
{
	std::clog << message << std::endl;
}

wkhtmltoimage_converter*
Latex::_new_converter(const std::string& filepath, ImageFormat format) const
{
	auto settings = _new_converter_settings(filepath, format);

	auto converter = wkhtmltoimage_create_converter(settings, nullptr);

	wkhtmltoimage_set_error_callback(converter, _throw);

	if (_warning_behaviour == WarningBehavior::Strict)
	{
		wkhtmltoimage_set_error_callback(converter, _throw);
	}

	else if (_warning_behaviour == WarningBehavior::Log)
	{
		wkhtmltoimage_set_warning_callback(converter, _log);
	}

	return converter;
}

wkhtmltoimage_global_settings*
Latex::_new_converter_settings(const std::string& filepath,
					 Latex::ImageFormat format) const
{
	auto settings = wkhtmltoimage_create_global_settings();

	wkhtmltoimage_set_global_setting(settings,
									 "transparent",
									 "false");

	wkhtmltoimage_set_global_setting(settings,
									 "in",
									 "temp.html");

	wkhtmltoimage_set_global_setting(settings,
									 "out",
									 filepath.c_str());
	const char* fmt;

	switch (format)
	{
		case ImageFormat::PNG: fmt = "png"; break;

		case ImageFormat::JPG: fmt = "jpg"; break;

		case ImageFormat::SVG: fmt = "svg"; break;
	}

	wkhtmltoimage_set_global_setting(settings,
									 "fmt",
									 fmt);

	wkhtmltoimage_set_global_setting(settings,
									 "screenWidth",
									 "0");

	wkhtmltoimage_set_global_setting(settings,
									 "quality",
									 "100");

	return settings;
}

Latex::V8::V8()
: platform(v8::platform::CreateDefaultPlatform())
{
	v8::V8::InitializeICU();

	v8::V8::InitializePlatform(platform.get());

	v8::V8::Initialize();
}

Latex::V8::~V8()
{
	v8::V8::Dispose();

	v8::V8::ShutdownPlatform();
}

void* Latex::Allocator::Allocate(size_t length)
{
	auto data = AllocateUninitialized(length);

	return data ? std::memset(data, 0, length) : data;
}

void Latex::Allocator::Free(void *data, size_t)
{
	free(data);
}

void* Latex::Allocator::AllocateUninitialized(size_t length)
{
	return malloc(length);
}<commit_msg>Fix a bug in _find_katex_path()<commit_after>#include "latex.hpp"

#include <boost/filesystem.hpp>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <libplatform/libplatform.h>
#include <wkhtmltox/image.h>

std::string Latex::_find_katex_path()
{
	for (std::string dir = "./", end = "./../../"; dir != end; dir += "../")
	{
		for (const auto& file : boost::filesystem::directory_iterator(dir))
		{
			auto path = file.path();

			if (path.stem() == "katex" && boost::filesystem::is_directory(path))
			{
				return path.string();
			}
		}
	}

	// We don't need the CSS necessarily, but do need the JavaScript.
	throw ExistentialException("Could not find KaTeX directory!");
}

std::string Latex::_katex_path;

Latex::V8 Latex::_v8;

Latex::Latex(WarningBehavior behavior)
: Latex("../../katex/katex.min.css", behavior)
{ }

Latex::Latex(const std::string& stylesheet, WarningBehavior behavior)
: _stylesheet(stylesheet)
, _warning_behaviour(behavior)
, _isolate(_new_isolate())
{
	if (_katex_path.empty())
	{
		_katex_path = _find_katex_path();
	}

	v8::HandleScope handle_scope(_isolate);

	v8::Isolate::Scope isolate_scope(_isolate);

	auto context = v8::Context::New(_isolate);

	v8::Context::Scope context_scope(context);

	_load_katex(context);

	_persistent_context = v8::UniquePersistent<v8::Context>(_isolate, context);

	wkhtmltoimage_init(false);
}

Latex::Latex(const Latex& other)
: Latex(other._stylesheet,
		other._warning_behaviour)
{
	_additional_css = other._additional_css;
}

Latex::Latex(Latex&& other) noexcept
: Latex()
{
	swap(other);
}

Latex& Latex::operator=(Latex other)
{
	swap(other);

	return *this;
}

void Latex::swap(Latex &other) noexcept
{
	// Enable ADL
	using std::swap;

	swap(_allocator, other._allocator);

	swap(_isolate, other._isolate);

	swap(_persistent_context, other._persistent_context);

	swap(_stylesheet, other._stylesheet);

	swap(_additional_css, other._additional_css);

	swap(_warning_behaviour, other._warning_behaviour);
}

void swap(Latex& first, Latex& second) noexcept
{
	first.swap(second);
}

Latex::~Latex()
{
	wkhtmltoimage_deinit();
}

std::string Latex::to_html(const std::string& latex) const
{
	static const std::string arguments = "{'displayMode': true}";

	v8::Isolate::Scope isolate_scope(_isolate);

	// Stack-allocated handle-scope (takes care of handles such
	// that object are garbage-collected after the scope ends)
	v8::HandleScope handle_scope(_isolate);

	// Get a local context handle from the persistent handle.
	auto context = v8::Local<v8::Context>::New(_isolate,
											   _persistent_context);

	v8::Context::Scope context_scope(context);

	std::string source = "katex.renderToString('";

	source += _escape(latex) + "', ";
	source += arguments + ");";

	auto value = _run(source, context);

	std::string html = *static_cast<v8::String::Utf8Value>(value);

	return "
\n" + html + "
\n";
}

std::string Latex::to_complete_html(const std::string &latex) const
{
	auto snippet = to_html(latex);

	std::string html = "<!DOCTYPE html>\n\n";

	html += "\n<meta charset='utf-8'/>\n";
	html += "<link rel='stylesheet' type='text/css' ";
 	html += "href='" + _stylesheet + "'>\n";

	if (! _additional_css.empty())
	{
		html += "\n";
	}

	html += "\n\n";
	html += snippet;
	html += "\n";

	return html;
}

void Latex::to_image(const std::string &latex,
				  const std::string &filepath,
				  ImageFormat format) const
{
	std::ofstream temp("temp.html");

	if (! temp) throw FileException("Could not open temporary file!");

	temp << to_complete_html(latex);

	temp.close();

	auto converter = _new_converter(filepath, format);

	if (! wkhtmltoimage_convert(converter))
	{
		throw ConversionException("Could not convert to png!");
	}

	wkhtmltoimage_destroy_converter(converter);

	boost::filesystem::remove("temp.html");
}

void Latex::to_png(const std::string &latex,
				const std::string &filepath) const
{
	to_image(latex, filepath, ImageFormat::PNG);
}

void Latex::to_jpg(const std::string &latex,
				const std::string &filepath) const
{
	to_image(latex, filepath, ImageFormat::JPG);
}

void Latex::to_svg(const std::string &latex,
				const std::string &filepath) const
{
	to_image(latex, filepath, ImageFormat::SVG);
}

void Latex::add_css(const std::string& css)
{
	_additional_css += css;
}

const std::string& Latex::additional_css() const
{
	return _additional_css;
}

void Latex::clear_additional_css()
{
	_additional_css.clear();
}

const std::string& Latex::stylesheet() const
{
	return _stylesheet;
}

void Latex::stylesheet(const std::string& stylesheet)
{
	_stylesheet = stylesheet;
}

const Latex::WarningBehavior& Latex::warning_behavior() const
{
	return _warning_behaviour;
}

void Latex::warning_behavior(WarningBehavior behavior)
{
	_warning_behaviour = behavior;
}

v8::Isolate* Latex::_new_isolate() const
{
	v8::Isolate::CreateParams parameters;

	parameters.array_buffer_allocator = &_allocator;

	// Isolated JavaScript Virtual Environment
	return v8::Isolate::New(parameters);
}

void Latex::_load_katex(const v8::Local<v8::Context>& context) const
{
	std::ifstream file(_katex_path + "/katex.min.js");

	std::string source;
	std::string input;

	while (std::getline(file, input))
	{
		source += input + " ";
	}

	_run(source, context);
}

v8::Local<v8::Value> Latex::_run(const std::string& source,
								 const v8::Local<v8::Context>& context) const
{
	v8::EscapableHandleScope handle_scope(_isolate);

	auto unchecked = v8::String::NewFromUtf8(_isolate,
											 source.c_str(),
											 v8::NewStringType::kNormal);

	auto checked = unchecked.ToLocalChecked();

	// Compile the source code.
	auto script = v8::Script::Compile(context, checked).ToLocalChecked();

	// V8 engine's try-catch mechanism
	v8::TryCatch try_catch(_isolate);

	auto result = script->Run(context);

	if (result.IsEmpty())
	{
		// Grab last exception
		auto exception = try_catch.Exception();

		std::string what = *static_cast<v8::String::Utf8Value>(exception);

		// Remove the 'ParseError' (redundant)
		throw ParseException(what.substr(12));
	}

	// Allows us to return local-scope objects to the outside scope
	return handle_scope.Escape(result.ToLocalChecked());
}

std::string Latex::_escape(std::string source) const
{
	for (auto i = source.begin(); i != source.end(); ++i)
	{
		if (*i == '\\')
		{
			i = source.insert(i, '\\');

			++i;
		}
	}

	return source;
}

void _throw(wkhtmltoimage_converter*, const char* message)
{
	throw Latex::ConversionException(message);
}

void _log(wkhtmltoimage_converter*, const char* message)
{
	std::clog << message << std::endl;
}

wkhtmltoimage_converter*
Latex::_new_converter(const std::string& filepath, ImageFormat format) const
{
	auto settings = _new_converter_settings(filepath, format);

	auto converter = wkhtmltoimage_create_converter(settings, nullptr);

	wkhtmltoimage_set_error_callback(converter, _throw);

	if (_warning_behaviour == WarningBehavior::Strict)
	{
		wkhtmltoimage_set_error_callback(converter, _throw);
	}

	else if (_warning_behaviour == WarningBehavior::Log)
	{
		wkhtmltoimage_set_warning_callback(converter, _log);
	}

	return converter;
}

wkhtmltoimage_global_settings*
Latex::_new_converter_settings(const std::string& filepath,
					 Latex::ImageFormat format) const
{
	auto settings = wkhtmltoimage_create_global_settings();

	wkhtmltoimage_set_global_setting(settings,
									 "transparent",
									 "false");

	wkhtmltoimage_set_global_setting(settings,
									 "in",
									 "temp.html");

	wkhtmltoimage_set_global_setting(settings,
									 "out",
									 filepath.c_str());
	const char* fmt;

	switch (format)
	{
		case ImageFormat::PNG: fmt = "png"; break;

		case ImageFormat::JPG: fmt = "jpg"; break;

		case ImageFormat::SVG: fmt = "svg"; break;
	}

	wkhtmltoimage_set_global_setting(settings,
									 "fmt",
									 fmt);

	wkhtmltoimage_set_global_setting(settings,
									 "screenWidth",
									 "0");

	wkhtmltoimage_set_global_setting(settings,
									 "quality",
									 "100");

	return settings;
}

Latex::V8::V8()
: platform(v8::platform::CreateDefaultPlatform())
{
	v8::V8::InitializeICU();

	v8::V8::InitializePlatform(platform.get());

	v8::V8::Initialize();
}

Latex::V8::~V8()
{
	v8::V8::Dispose();

	v8::V8::ShutdownPlatform();
}

void* Latex::Allocator::Allocate(size_t length)
{
	auto data = AllocateUninitialized(length);

	return data ? std::memset(data, 0, length) : data;
}

void Latex::Allocator::Free(void *data, size_t)
{
	free(data);
}

void* Latex::Allocator::AllocateUninitialized(size_t length)
{
	return malloc(length);
}<|endoftext|>


<commit_before>#ifdef TOY_WINDOWS
#include <windows.h>
#endif

#include <cstdlib>
#include <cstring>
#include "toy/file/io/Zip7.hpp"

using namespace toy;
using namespace file;
using namespace io;

//---------------------------Come from 7zip example---------------------------start

typedef int SRes;

static void *SzAlloc(void *p, size_t size)
{
	(void)p;
	return MyAlloc(size);
}
static void SzFree(void *p, void *address)
{
	(void)p;
	MyFree(address);
}

void *SzAllocTemp(void *p, size_t size)
{
	(void)p;
	if (size == 0)
		return 0;
	#ifdef _SZ_ALLOC_DEBUG
		fprintf(stderr, "\nAlloc_temp %10d bytes;  count = %10d", size, g_allocCountTemp);
		g_allocCountTemp++;
		#ifdef _WIN32
			return HeapAlloc(GetProcessHeap(), 0, size);
		#endif
	#endif
	return malloc(size);
}

void SzFreeTemp(void *p, void *address)
{
	(void)p;
	#ifdef _SZ_ALLOC_DEBUG
		if (address != 0)
		{
			g_allocCountTemp--;
			fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
		}
		#ifdef _WIN32
			HeapFree(GetProcessHeap(), 0, address);
			return;
		#endif
	#endif
	free(address);
}

static ISzAlloc g_Alloc = { SzAlloc, SzFree };

static int Buf_EnsureSize(CBuf *dest, size_t size)
{
	if (dest->size >= size)
		return 1;
	Buf_Free(dest, &g_Alloc);
	return Buf_Create(dest, size, &g_Alloc);
}

#if defined(TOY_LINUX) || defined(TOY_MAC)
static Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };

static Bool Utf16_To_Utf8(Byte *dest, size_t *destLen, const UInt16 *src, size_t srcLen)
{
	size_t destPos = 0, srcPos = 0;
	for (;;)
	{
		unsigned numAdds;
		UInt32 value;
		if (srcPos == srcLen)
		{
			*destLen = destPos;
			return True;
		}
		value = src[srcPos++];
		if (value < 0x80)
		{
			if (dest)
			dest[destPos] = (char)value;
			destPos++;
			continue;
		}
		if (value >= 0xD800 && value < 0xE000)
		{
			UInt32 c2;
			if (value >= 0xDC00 || srcPos == srcLen)
				break;
			c2 = src[srcPos++];
			if (c2 < 0xDC00 || c2 >= 0xE000)
				break;
			value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
		}
		for (numAdds = 1; numAdds < 5; numAdds++)
			if (value < (((UInt32)1) << (numAdds * 5 + 6)))
				break;
		if (dest)
			dest[destPos] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
		destPos++;
		do
		{
			numAdds--;
			if (dest)
				dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
			destPos++;
		}
		while (numAdds != 0);
	}
	*destLen = destPos;
	return False;
}
static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen)
{
	size_t destLen = 0;
	Bool res;
	Utf16_To_Utf8(NULL, &destLen, src, srcLen);
	destLen += 1;
	if (!Buf_EnsureSize(dest, destLen))
		return SZ_ERROR_MEM;
	res = Utf16_To_Utf8(dest->data, &destLen, src, srcLen);
	dest->data[destLen] = 0;
	return res ? SZ_OK : SZ_ERROR_FAIL;
}
#endif
static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s, int fileMode)
{
	int len = 0;
	for (len = 0; s[len] != '\0'; len++){}

	#ifdef _WIN32
		int size = len * 3 + 100;
		if (!Buf_EnsureSize(buf, size))
		{
			return SZ_ERROR_MEM;
		}

		char defaultChar = '_';
		BOOL defUsed;
		UINT codePage;

		#ifdef UNDER_CE
			codePage = fileMode ? CP_ACP : CP_OEMCP;
		#else
			codePage = fileMode ? ( AreFileApisANSI() ? CP_ACP : CP_OEMCP ) : CP_OEMCP;
		#endif

		int numChars = WideCharToMultiByte( codePage,
		                                    0,
		                                    (LPCWSTR)s,
		                                    len,
		                                    (char *)buf->data,
		                                    size,
		                                    &defaultChar,
		                                    &defUsed);

		if (numChars == 0 || numChars >= size)
		{
			return SZ_ERROR_FAIL;
		}

		buf->data[numChars] = 0;
		return SZ_OK;
	#else
		(void)fileMode;
		return Utf16_To_Utf8Buf(buf, s, len);
	#endif
}

static int SzCheckName(const char *name1,UInt16 *name2)
{
	CBuf buf;
	Buf_Init(&buf);
	Utf16_To_Char(&buf, name2, 0);
	int answer=strcmp((const char *)buf.data,name1);
	Buf_Free(&buf, &g_Alloc);

	if(answer==0)
		return 1;
	else
		return 0;
}

//---------------------------Come from 7zip example---------------------------end

Zip7::Zip7()
{
	_allocImp.Alloc = SzAlloc;
	_allocImp.Free = SzFree;
	_allocTempImp.Alloc = SzAllocTemp;
	_allocTempImp.Free = SzFreeTemp;
	_temp = NULL;
	_outBuffer=0;

	SzArEx_Init(&(_db));
}

bool Zip7::openDir(std::string path)
{
	if ( InFile_Open(&(_archiveStream.file),path.c_str()) )
	{
		toy::Oops(TOY_MARK);
		return 0;
	}

	SRes res;

	FileInStream_CreateVTable(&(_archiveStream));
	LookToRead_CreateVTable(&(_lookStream), False);
	_lookStream.realStream = &(_archiveStream.s);
	LookToRead_Init(&(_lookStream));
	CrcGenerateTable();
	SzArEx_Init(&(_db));

	res = SzArEx_Open(&(_db), &(_lookStream.s), &(_allocImp), &(_allocTempImp));

	if (res != SZ_OK)
	{
		Oops(TOY_MARK);
		SzArEx_Free(&(_db), &(_allocImp));
		SzFree(NULL, _temp);
		File_Close(&(_archiveStream.file));
		return 0;
	}

	return 1;
}

bool Zip7::open(std::string filepath)
{
	size_t	len;
	size_t	tempSize = 0;
	SRes	res;
	UInt32	blockIndex = 0xFFFFFFFF;
	size_t	outBufferSize = 0;
	size_t	offset = 0;
	size_t	outSizeProcessed = 0;

	UInt32	i=0;
	UInt32	number_of_files=_db.db.NumFiles;

	for ( ; i<number_of_files ; i++ )
	{
		const CSzFileItem *f = _db.db.Files + i;

		if ( f->IsDir )
		{
			continue;
		}

		len = SzArEx_GetFileNameUtf16(&(_db), i, NULL);

		if ( len > tempSize )
		{
			SzFree(NULL, _temp);
			tempSize = len;
			_temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(_temp[0]));
			if ( _temp == 0 )
			{
				toy::Oops(TOY_MARK);
				return 0;
			}
		}

		SzArEx_GetFileNameUtf16(&(_db), i, _temp);

		if ( SzCheckName(filepath.c_str(),_temp) )
		{
			res = SzArEx_Extract(&(_db), &(_lookStream.s), i,
			&blockIndex, &(_outBuffer), &outBufferSize,
			&offset, &outSizeProcessed,
			&(_allocImp), &(_allocTempImp));
			if(res == SZ_OK)
			{
				_fileSize = outSizeProcessed;
				_filePointer = (void*)((_outBuffer)+offset);
				return 1;
			}
			else
			{
				Oops(TOY_MARK);
				_fileSize = 0;
				_filePointer = nullptr;
				return 0;
			}
		}
	}

	toy::Oops(TOY_MARK);

	_fileSize = 0;
	_filePointer = nullptr;
	return 0;
}

int Zip7::read(void *file, uint32_t size)
{
	if ( _fileSize<size )
	{
		//toy::Oops(TOY_MARK);
		memcpy(file,_filePointer,_fileSize);
		return _fileSize;
	}

	auto   data = static_cast<Byte*>(_filePointer);

	memcpy(file,_filePointer,size);

	data+=size;

	_filePointer = static_cast<decltype(_filePointer)>data;

	return size;
}

bool Zip7::write(void *,uint32_t )
{
	// Not ready yet
	toy::Oops(TOY_MARK);
	return 1;
}

bool Zip7::seek(enum Base::Option ,int32_t )
{
	// Not ready yet
	toy::Oops(TOY_MARK);
	return 1;
}

void Zip7::close()
{
	IAlloc_Free(&(_allocImp), _outBuffer);

	SzArEx_Free(&(_db), &(_allocImp));

	if ( _temp )
	{
		SzFree(NULL, _temp);
		_temp=NULL;
	}
	File_Close(&(_archiveStream.file));
}

bool Zip7::isEmpty()
{
	return 1;
}

void* Zip7::getFilePointer()
{
	// There is no way to do it.
	toy::Oops(TOY_MARK);
	return nullptr;
}
<commit_msg>Syntax error.<commit_after>#ifdef TOY_WINDOWS
#include <windows.h>
#endif

#include <cstdlib>
#include <cstring>
#include "toy/file/io/Zip7.hpp"

using namespace toy;
using namespace file;
using namespace io;

//---------------------------Come from 7zip example---------------------------start

typedef int SRes;

static void *SzAlloc(void *p, size_t size)
{
	(void)p;
	return MyAlloc(size);
}
static void SzFree(void *p, void *address)
{
	(void)p;
	MyFree(address);
}

void *SzAllocTemp(void *p, size_t size)
{
	(void)p;
	if (size == 0)
		return 0;
	#ifdef _SZ_ALLOC_DEBUG
		fprintf(stderr, "\nAlloc_temp %10d bytes;  count = %10d", size, g_allocCountTemp);
		g_allocCountTemp++;
		#ifdef _WIN32
			return HeapAlloc(GetProcessHeap(), 0, size);
		#endif
	#endif
	return malloc(size);
}

void SzFreeTemp(void *p, void *address)
{
	(void)p;
	#ifdef _SZ_ALLOC_DEBUG
		if (address != 0)
		{
			g_allocCountTemp--;
			fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
		}
		#ifdef _WIN32
			HeapFree(GetProcessHeap(), 0, address);
			return;
		#endif
	#endif
	free(address);
}

static ISzAlloc g_Alloc = { SzAlloc, SzFree };

static int Buf_EnsureSize(CBuf *dest, size_t size)
{
	if (dest->size >= size)
		return 1;
	Buf_Free(dest, &g_Alloc);
	return Buf_Create(dest, size, &g_Alloc);
}

#if defined(TOY_LINUX) || defined(TOY_MAC)
static Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };

static Bool Utf16_To_Utf8(Byte *dest, size_t *destLen, const UInt16 *src, size_t srcLen)
{
	size_t destPos = 0, srcPos = 0;
	for (;;)
	{
		unsigned numAdds;
		UInt32 value;
		if (srcPos == srcLen)
		{
			*destLen = destPos;
			return True;
		}
		value = src[srcPos++];
		if (value < 0x80)
		{
			if (dest)
			dest[destPos] = (char)value;
			destPos++;
			continue;
		}
		if (value >= 0xD800 && value < 0xE000)
		{
			UInt32 c2;
			if (value >= 0xDC00 || srcPos == srcLen)
				break;
			c2 = src[srcPos++];
			if (c2 < 0xDC00 || c2 >= 0xE000)
				break;
			value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
		}
		for (numAdds = 1; numAdds < 5; numAdds++)
			if (value < (((UInt32)1) << (numAdds * 5 + 6)))
				break;
		if (dest)
			dest[destPos] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
		destPos++;
		do
		{
			numAdds--;
			if (dest)
				dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
			destPos++;
		}
		while (numAdds != 0);
	}
	*destLen = destPos;
	return False;
}
static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen)
{
	size_t destLen = 0;
	Bool res;
	Utf16_To_Utf8(NULL, &destLen, src, srcLen);
	destLen += 1;
	if (!Buf_EnsureSize(dest, destLen))
		return SZ_ERROR_MEM;
	res = Utf16_To_Utf8(dest->data, &destLen, src, srcLen);
	dest->data[destLen] = 0;
	return res ? SZ_OK : SZ_ERROR_FAIL;
}
#endif
static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s, int fileMode)
{
	int len = 0;
	for (len = 0; s[len] != '\0'; len++){}

	#ifdef _WIN32
		int size = len * 3 + 100;
		if (!Buf_EnsureSize(buf, size))
		{
			return SZ_ERROR_MEM;
		}

		char defaultChar = '_';
		BOOL defUsed;
		UINT codePage;

		#ifdef UNDER_CE
			codePage = fileMode ? CP_ACP : CP_OEMCP;
		#else
			codePage = fileMode ? ( AreFileApisANSI() ? CP_ACP : CP_OEMCP ) : CP_OEMCP;
		#endif

		int numChars = WideCharToMultiByte( codePage,
		                                    0,
		                                    (LPCWSTR)s,
		                                    len,
		                                    (char *)buf->data,
		                                    size,
		                                    &defaultChar,
		                                    &defUsed);

		if (numChars == 0 || numChars >= size)
		{
			return SZ_ERROR_FAIL;
		}

		buf->data[numChars] = 0;
		return SZ_OK;
	#else
		(void)fileMode;
		return Utf16_To_Utf8Buf(buf, s, len);
	#endif
}

static int SzCheckName(const char *name1,UInt16 *name2)
{
	CBuf buf;
	Buf_Init(&buf);
	Utf16_To_Char(&buf, name2, 0);
	int answer=strcmp((const char *)buf.data,name1);
	Buf_Free(&buf, &g_Alloc);

	if(answer==0)
		return 1;
	else
		return 0;
}

//---------------------------Come from 7zip example---------------------------end

Zip7::Zip7()
{
	_allocImp.Alloc = SzAlloc;
	_allocImp.Free = SzFree;
	_allocTempImp.Alloc = SzAllocTemp;
	_allocTempImp.Free = SzFreeTemp;
	_temp = NULL;
	_outBuffer=0;

	SzArEx_Init(&(_db));
}

bool Zip7::openDir(std::string path)
{
	if ( InFile_Open(&(_archiveStream.file),path.c_str()) )
	{
		toy::Oops(TOY_MARK);
		return 0;
	}

	SRes res;

	FileInStream_CreateVTable(&(_archiveStream));
	LookToRead_CreateVTable(&(_lookStream), False);
	_lookStream.realStream = &(_archiveStream.s);
	LookToRead_Init(&(_lookStream));
	CrcGenerateTable();
	SzArEx_Init(&(_db));

	res = SzArEx_Open(&(_db), &(_lookStream.s), &(_allocImp), &(_allocTempImp));

	if (res != SZ_OK)
	{
		Oops(TOY_MARK);
		SzArEx_Free(&(_db), &(_allocImp));
		SzFree(NULL, _temp);
		File_Close(&(_archiveStream.file));
		return 0;
	}

	return 1;
}

bool Zip7::open(std::string filepath)
{
	size_t	len;
	size_t	tempSize = 0;
	SRes	res;
	UInt32	blockIndex = 0xFFFFFFFF;
	size_t	outBufferSize = 0;
	size_t	offset = 0;
	size_t	outSizeProcessed = 0;

	UInt32	i=0;
	UInt32	number_of_files=_db.db.NumFiles;

	for ( ; i<number_of_files ; i++ )
	{
		const CSzFileItem *f = _db.db.Files + i;

		if ( f->IsDir )
		{
			continue;
		}

		len = SzArEx_GetFileNameUtf16(&(_db), i, NULL);

		if ( len > tempSize )
		{
			SzFree(NULL, _temp);
			tempSize = len;
			_temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(_temp[0]));
			if ( _temp == 0 )
			{
				toy::Oops(TOY_MARK);
				return 0;
			}
		}

		SzArEx_GetFileNameUtf16(&(_db), i, _temp);

		if ( SzCheckName(filepath.c_str(),_temp) )
		{
			res = SzArEx_Extract(&(_db), &(_lookStream.s), i,
			&blockIndex, &(_outBuffer), &outBufferSize,
			&offset, &outSizeProcessed,
			&(_allocImp), &(_allocTempImp));
			if(res == SZ_OK)
			{
				_fileSize = outSizeProcessed;
				_filePointer = (void*)((_outBuffer)+offset);
				return 1;
			}
			else
			{
				Oops(TOY_MARK);
				_fileSize = 0;
				_filePointer = nullptr;
				return 0;
			}
		}
	}

	toy::Oops(TOY_MARK);

	_fileSize = 0;
	_filePointer = nullptr;
	return 0;
}

int Zip7::read(void *file, uint32_t size)
{
	if ( _fileSize<size )
	{
		//toy::Oops(TOY_MARK);
		memcpy(file,_filePointer,_fileSize);
		return _fileSize;
	}

	auto   data = static_cast<Byte*>(_filePointer);

	memcpy(file,_filePointer,size);

	data+=size;

	_filePointer = static_cast<decltype(_filePointer)>(data);

	return size;
}

bool Zip7::write(void *,uint32_t )
{
	// Not ready yet
	toy::Oops(TOY_MARK);
	return 1;
}

bool Zip7::seek(enum Base::Option ,int32_t )
{
	// Not ready yet
	toy::Oops(TOY_MARK);
	return 1;
}

void Zip7::close()
{
	IAlloc_Free(&(_allocImp), _outBuffer);

	SzArEx_Free(&(_db), &(_allocImp));

	if ( _temp )
	{
		SzFree(NULL, _temp);
		_temp=NULL;
	}
	File_Close(&(_archiveStream.file));
}

bool Zip7::isEmpty()
{
	return 1;
}

void* Zip7::getFilePointer()
{
	// There is no way to do it.
	toy::Oops(TOY_MARK);
	return nullptr;
}
<|endoftext|>


<commit_before>#include <pybind11/pybind11.h>
#include <iostream>
#include <sstream>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>

#include "boost/format.hpp"

#include "nifty/graph/undirected_grid_graph.hxx"
#include "export_undirected_graph_class_api.hxx"
#include "nifty/python/converter.hxx"

namespace py = pybind11;

namespace nifty{
namespace graph{

    template<size_t DIM>
    void exportUndirectedGridGraphT(py::module & module) {

        typedef UndirectedGridGraph<DIM,true> GraphType;
        const auto clsName = std::string("UndirectedGridGraph") +
                        std::to_string(DIM) + std::string("DSimpleNh");

        auto graphCls = py::class_<GraphType>(module, clsName.c_str(),
            (boost::format("%dDimensional Grid Graph")%DIM).str().c_str()
        );

        graphCls
            .def(py::init<const typename GraphType::ShapeType>(),
               py::arg("shape")
            )
            .def("nodeToCoordinate",[](
                const GraphType & g,
                const uint64_t node
            ){
                return g.nodeToCoordinate(node);
            })
            .def("coordianteToNode",[](
                const GraphType & g,
                const typename GraphType::CoordinateType & coord
            ){
                return g.coordianteToNode(coord);
            })

            .def("imageToEdgeMap",
                [](
                    const GraphType & g,
                    nifty::marray::PyView<float, DIM> image,
                    const std::string & functorType
                ){

                    nifty::marray::PyView<float> out({g.edgeIdUpperBound()+1});

                    if(functorType == std::string("min")){
                        struct {
                            double operator()(const float a, const float b){
                                return std::min(a,b);
                            }
                        } op;
                        g.imageToEdgeMap(image, op, out);
                    }
                    else if(functorType == std::string("max")){
                        struct {
                            double operator()(const float a, const float b){
                                return std::max(a,b);
                            }
                        } op;
                        g.imageToEdgeMap(image, op, out);
                    }
                    else if(functorType == std::string("sum")){
                        struct {
                            double operator()(const float a, const float b){
                                return a + b;
                            }
                        } op;
                        g.imageToEdgeMap(image, op, out);
                    }
                    else if(functorType == std::string("prod")){
                        struct {
                            double operator()(const float a, const float b){
                                return a*b;
                            }
                        } op;
                        g.imageToEdgeMap(image, op, out);
                    }
                    else if(functorType == std::string("interpixel")){
                        g.imageToInterpixelEdgeMap(image, out);
                    }
                    else{
                        const auto s = boost::format("'%s' is an unknown mode. Must be in "
                            "['min', 'max', 'sum', 'prod', 'interpixel']")%functorType;
                        throw std::runtime_error(s.str());
                    }
                    return out;
                },
                py::arg("image"),
                py::arg("mode"),
                "convert an image to an edge map\n\n"
                "Arguments:\n\n"
                "   image (numpy.ndarray): the image\n"
                "    mode str: mode can be:\n"
                "       *   'min':  Minimum of the two image values at edges endpoints of coordinates.\n"
                "       *   'max':  Maximum of the two image values at edges endpoints of coordinates.\n"
                "       *   'sum':      Sum of the two image values at edges endpoints of coordinates.\n"
                "       *   'prod': Product of the two image values at edges endpoints of coordinates.\n"
            )

            .def("affinitiesToEdgeMap",
                [](
                    const GraphType & g,
                    nifty::marray::PyView<float, DIM+1> affinities
                ){
                    nifty::marray::PyView<float> out({g.edgeIdUpperBound()+1});
                    g.affinitiesToEdgeMap(affinities, out);
                },
                py::arg("affinities")
            )

            //.def("uvIds",
            //    [](GraphType & g) {
            //        nifty::marray::PyView<uint64_t> out({uint64_t(g.numberOfEdges()), uint64_t(2)});
            //        for(const auto edge : g.edges()){
            //            const auto uv = g.uv(edge);
            //            out(edge,0) = uv.first;
            //            out(edge,1) = uv.second;
            //        }
            //        return out;
            //    }
            //)
            //.def("serialize",
            //    [](const GraphType & g) {
            //        nifty::marray::PyView<uint64_t> out({g.serializationSize()});
            //        auto ptr = &out(0);
            //        g.serialize(ptr);
            //        return out;
            //    }
            //)
            //.def("deserialize",
            //    [](GraphType & g, nifty::marray::PyView<uint64_t,1> serialization) {
            //        auto  startPtr = &serialization(0);
            //        auto  lastElement = &serialization(serialization.size()-1);
            //        auto d = lastElement - startPtr + 1;
            //        NIFTY_CHECK_OP(d,==,serialization.size(), "serialization must be contiguous");
            //        g.deserialize(startPtr);
            //    }
            //)
            //.def("extractSubgraphFromNodes",
            //    []( GraphType & g, const marray::PyView<int64_t,1> nodeList) {
            //        std::vector<int64_t> innerEdgesVec;
            //        std::vector<int64_t> outerEdgesVec;
            //        GraphType subgraph;
            //        {
            //            py::gil_scoped_release allowThreads;
            //            subgraph = g.extractSubgraphFromNodes(nodeList, innerEdgesVec, outerEdgesVec);
            //        }
            //        return std::make_tuple(innerEdgesVec, outerEdgesVec, subgraph);
            //    }
            //)
        ;

        // export the base graph API (others might derive)
        exportUndirectedGraphClassAPI<GraphType>(module, graphCls,clsName);

    }

    void exportUndirectedGridGraph(py::module & module){
        exportUndirectedGridGraphT<2>(module);
        exportUndirectedGridGraphT<3>(module);
    }
}
}
<commit_msg>Returning results for edge map<commit_after>#include <pybind11/pybind11.h>
#include <iostream>
#include <sstream>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>

#include "boost/format.hpp"

#include "nifty/graph/undirected_grid_graph.hxx"
#include "export_undirected_graph_class_api.hxx"
#include "nifty/python/converter.hxx"

namespace py = pybind11;

namespace nifty{
namespace graph{

    template<size_t DIM>
    void exportUndirectedGridGraphT(py::module & module) {

        typedef UndirectedGridGraph<DIM,true> GraphType;
        const auto clsName = std::string("UndirectedGridGraph") +
                        std::to_string(DIM) + std::string("DSimpleNh");

        auto graphCls = py::class_<GraphType>(module, clsName.c_str(),
            (boost::format("%dDimensional Grid Graph")%DIM).str().c_str()
        );

        graphCls
            .def(py::init<const typename GraphType::ShapeType>(),
               py::arg("shape")
            )
            .def("nodeToCoordinate",[](
                const GraphType & g,
                const uint64_t node
            ){
                return g.nodeToCoordinate(node);
            })
            .def("coordianteToNode",[](
                const GraphType & g,
                const typename GraphType::CoordinateType & coord
            ){
                return g.coordianteToNode(coord);
            })

            .def("imageToEdgeMap",
                [](
                    const GraphType & g,
                    nifty::marray::PyView<float, DIM> image,
                    const std::string & functorType
                ){

                    nifty::marray::PyView<float> out({g.edgeIdUpperBound()+1});

                    if(functorType == std::string("min")){
                        struct {
                            double operator()(const float a, const float b){
                                return std::min(a,b);
                            }
                        } op;
                        g.imageToEdgeMap(image, op, out);
                    }
                    else if(functorType == std::string("max")){
                        struct {
                            double operator()(const float a, const float b){
                                return std::max(a,b);
                            }
                        } op;
                        g.imageToEdgeMap(image, op, out);
                    }
                    else if(functorType == std::string("sum")){
                        struct {
                            double operator()(const float a, const float b){
                                return a + b;
                            }
                        } op;
                        g.imageToEdgeMap(image, op, out);
                    }
                    else if(functorType == std::string("prod")){
                        struct {
                            double operator()(const float a, const float b){
                                return a*b;
                            }
                        } op;
                        g.imageToEdgeMap(image, op, out);
                    }
                    else if(functorType == std::string("interpixel")){
                        g.imageToInterpixelEdgeMap(image, out);
                    }
                    else{
                        const auto s = boost::format("'%s' is an unknown mode. Must be in "
                            "['min', 'max', 'sum', 'prod', 'interpixel']")%functorType;
                        throw std::runtime_error(s.str());
                    }
                    return out;
                },
                py::arg("image"),
                py::arg("mode"),
                "convert an image to an edge map\n\n"
                "Arguments:\n\n"
                "   image (numpy.ndarray): the image\n"
                "    mode str: mode can be:\n"
                "       *   'min':  Minimum of the two image values at edges endpoints of coordinates.\n"
                "       *   'max':  Maximum of the two image values at edges endpoints of coordinates.\n"
                "       *   'sum':      Sum of the two image values at edges endpoints of coordinates.\n"
                "       *   'prod': Product of the two image values at edges endpoints of coordinates.\n"
            )

            .def("affinitiesToEdgeMap",
                [](
                    const GraphType & g,
                    nifty::marray::PyView<float, DIM+1> affinities
                ){
                    nifty::marray::PyView<float> out({g.edgeIdUpperBound()+1});
                    g.affinitiesToEdgeMap(affinities, out);
                    return out;
                },
                py::arg("affinities")
            )

            //.def("uvIds",
            //    [](GraphType & g) {
            //        nifty::marray::PyView<uint64_t> out({uint64_t(g.numberOfEdges()), uint64_t(2)});
            //        for(const auto edge : g.edges()){
            //            const auto uv = g.uv(edge);
            //            out(edge,0) = uv.first;
            //            out(edge,1) = uv.second;
            //        }
            //        return out;
            //    }
            //)
            //.def("serialize",
            //    [](const GraphType & g) {
            //        nifty::marray::PyView<uint64_t> out({g.serializationSize()});
            //        auto ptr = &out(0);
            //        g.serialize(ptr);
            //        return out;
            //    }
            //)
            //.def("deserialize",
            //    [](GraphType & g, nifty::marray::PyView<uint64_t,1> serialization) {
            //        auto  startPtr = &serialization(0);
            //        auto  lastElement = &serialization(serialization.size()-1);
            //        auto d = lastElement - startPtr + 1;
            //        NIFTY_CHECK_OP(d,==,serialization.size(), "serialization must be contiguous");
            //        g.deserialize(startPtr);
            //    }
            //)
            //.def("extractSubgraphFromNodes",
            //    []( GraphType & g, const marray::PyView<int64_t,1> nodeList) {
            //        std::vector<int64_t> innerEdgesVec;
            //        std::vector<int64_t> outerEdgesVec;
            //        GraphType subgraph;
            //        {
            //            py::gil_scoped_release allowThreads;
            //            subgraph = g.extractSubgraphFromNodes(nodeList, innerEdgesVec, outerEdgesVec);
            //        }
            //        return std::make_tuple(innerEdgesVec, outerEdgesVec, subgraph);
            //    }
            //)
        ;

        // export the base graph API (others might derive)
        exportUndirectedGraphClassAPI<GraphType>(module, graphCls,clsName);

    }

    void exportUndirectedGridGraph(py::module & module){
        exportUndirectedGridGraphT<2>(module);
        exportUndirectedGridGraphT<3>(module);
    }
}
}
<|endoftext|>


<commit_before><commit_msg>Whoops<commit_after><|endoftext|>


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

#include "camerabinmetadata.h"

#include <QtMultimedia/qmediametadata.h>

#include <gst/gst.h>
#include <gst/gstversion.h>

#include <QDebug>

QT_BEGIN_NAMESPACE

struct QGstreamerMetaDataKeyLookup
{
    QString key;
    const char *token;
    QVariant::Type type;
};

static QVariant fromGStreamerOrientation(const QVariant &value)
{
    // Note gstreamer tokens either describe the counter clockwise rotation of the
    // image or the clockwise transform to apply to correct the image.  The orientation
    // value returned is the clockwise rotation of the image.
    const QString token = value.toString();
    if (token == QStringLiteral("rotate-90"))
        return 270;
    else if (token == QStringLiteral("rotate-180"))
        return 180;
    else if (token == QStringLiteral("rotate-270"))
        return 90;
    else
        return 0;
}

static QVariant toGStreamerOrientation(const QVariant &value)
{
    switch (value.toInt()) {
    case 90:
        return QStringLiteral("rotate-270");
    case 180:
        return QStringLiteral("rotate-180");
    case 270:
        return QStringLiteral("rotate-90");
    default:
        return QStringLiteral("rotate-0");
    }
}

static const QGstreamerMetaDataKeyLookup qt_gstreamerMetaDataKeys[] =
{
    { QMediaMetaData::Title, GST_TAG_TITLE, QVariant::String },
    //{ QMediaMetaData::SubTitle, 0, QVariant::String },
    //{ QMediaMetaData::Author, 0, QVariant::String },
    { QMediaMetaData::Comment, GST_TAG_COMMENT, QVariant::String },
    { QMediaMetaData::Date, GST_TAG_DATE_TIME, QVariant::DateTime },
    { QMediaMetaData::Description, GST_TAG_DESCRIPTION, QVariant::String },
    //{ QMediaMetaData::Category, 0, QVariant::String },
    { QMediaMetaData::Genre, GST_TAG_GENRE, QVariant::String },
    //{ QMediaMetaData::Year, 0, QVariant::Int },
    //{ QMediaMetaData::UserRating, , QVariant::Int },

    { QMediaMetaData::Language, GST_TAG_LANGUAGE_CODE, QVariant::String },

    { QMediaMetaData::Publisher, GST_TAG_ORGANIZATION, QVariant::String },
    { QMediaMetaData::Copyright, GST_TAG_COPYRIGHT, QVariant::String },
    //{ QMediaMetaData::ParentalRating, 0, QVariant::String },
    //{ QMediaMetaData::RatingOrganisation, 0, QVariant::String },

    // Media
    //{ QMediaMetaData::Size, 0, QVariant::Int },
    //{ QMediaMetaData::MediaType, 0, QVariant::String },
    { QMediaMetaData::Duration, GST_TAG_DURATION, QVariant::Int },

    // Audio
    { QMediaMetaData::AudioBitRate, GST_TAG_BITRATE, QVariant::Int },
    { QMediaMetaData::AudioCodec, GST_TAG_AUDIO_CODEC, QVariant::String },
    //{ QMediaMetaData::ChannelCount, 0, QVariant::Int },
    //{ QMediaMetaData::SampleRate, 0, QVariant::Int },

    // Music
    { QMediaMetaData::AlbumTitle, GST_TAG_ALBUM, QVariant::String },
    { QMediaMetaData::AlbumArtist,  GST_TAG_ARTIST, QVariant::String},
    { QMediaMetaData::ContributingArtist, GST_TAG_PERFORMER, QVariant::String },
#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19)
    { QMediaMetaData::Composer, GST_TAG_COMPOSER, QVariant::String },
#endif
    //{ QMediaMetaData::Conductor, 0, QVariant::String },
    //{ QMediaMetaData::Lyrics, 0, QVariant::String },
    //{ QMediaMetaData::Mood, 0, QVariant::String },
    { QMediaMetaData::TrackNumber, GST_TAG_TRACK_NUMBER, QVariant::Int },

    //{ QMediaMetaData::CoverArtUrlSmall, 0, QVariant::String },
    //{ QMediaMetaData::CoverArtUrlLarge, 0, QVariant::String },

    // Image/Video
    //{ QMediaMetaData::Resolution, 0, QVariant::Size },
    //{ QMediaMetaData::PixelAspectRatio, 0, QVariant::Size },

    // Video
    //{ QMediaMetaData::VideoFrameRate, 0, QVariant::String },
    //{ QMediaMetaData::VideoBitRate, 0, QVariant::Double },
    { QMediaMetaData::VideoCodec, GST_TAG_VIDEO_CODEC, QVariant::String },

    //{ QMediaMetaData::PosterUrl, 0, QVariant::String },

    // Movie
    //{ QMediaMetaData::ChapterNumber, 0, QVariant::Int },
    //{ QMediaMetaData::Director, 0, QVariant::String },
    { QMediaMetaData::LeadPerformer, GST_TAG_PERFORMER, QVariant::String },
    //{ QMediaMetaData::Writer, 0, QVariant::String },

#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 30)
    // Photos
    { QMediaMetaData::CameraManufacturer, 0, QVariant::String },
    { QMediaMetaData::CameraModel, 0, QVariant::String },
    //{ QMediaMetaData::Event, 0, QVariant::String },
    //{ QMediaMetaData::Subject, 0, QVariant::String },

    { QMediaMetaData::Orientation, GST_TAG_IMAGE_ORIENTATION, QVariant::String },

#endif
};

CameraBinMetaData::CameraBinMetaData(QObject *parent)
    :QMetaDataWriterControl(parent)
{
}

QVariant CameraBinMetaData::metaData(const QString &key) const
{
    if (key == QMediaMetaData::Orientation) {
        return fromGStreamerOrientation(m_values.value(QByteArray(GST_TAG_IMAGE_ORIENTATION)));
    } else if (key == QMediaMetaData::GPSSpeed) {
        const double metersPerSec = m_values.value(QByteArray(GST_TAG_GEO_LOCATION_MOVEMENT_SPEED)).toDouble();
        return (metersPerSec * 3600) / 1000;
    }

    static const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup);

    for (int i = 0; i < count; ++i) {
        if (qt_gstreamerMetaDataKeys[i].key == key) {
            const char *name = qt_gstreamerMetaDataKeys[i].token;

            return m_values.value(QByteArray::fromRawData(name, qstrlen(name)));
        }
    }
    return QVariant();
}

void CameraBinMetaData::setMetaData(const QString &key, const QVariant &value)
{
    QVariant correctedValue = value;
    if (key == QMediaMetaData::Orientation) {
        correctedValue = toGStreamerOrientation(value);
    } else if (key == QMediaMetaData::GPSSpeed) {
        // kilometers per hour to meters per second.
        correctedValue = (value.toDouble() * 1000) / 3600;
    }

    static const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup);

    for (int i = 0; i < count; ++i) {
        if (qt_gstreamerMetaDataKeys[i].key == key) {
            const char *name = qt_gstreamerMetaDataKeys[i].token;

            correctedValue.convert(qt_gstreamerMetaDataKeys[i].type);

            m_values.insert(QByteArray::fromRawData(name, qstrlen(name)), correctedValue);

            emit QMetaDataWriterControl::metaDataChanged();
            emit metaDataChanged(m_values);

            return;
        }
    }
}

QStringList CameraBinMetaData::availableMetaData() const
{
    static QMap<QByteArray, QString> keysMap;
    if (keysMap.isEmpty()) {
        const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup);
        for (int i = 0; i < count; ++i) {
            keysMap[QByteArray(qt_gstreamerMetaDataKeys[i].token)] = qt_gstreamerMetaDataKeys[i].key;
        }
    }

    QStringList res;
    foreach (const QByteArray &key, m_values.keys()) {
        QString tag = keysMap.value(key);
        if (!tag.isEmpty())
            res.append(tag);
    }

    return res;
}

QT_END_NAMESPACE
<commit_msg>Add meta-data mappings for GPS and camera make and model to camerabin.<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "camerabinmetadata.h"

#include <QtMultimedia/qmediametadata.h>

#include <gst/gst.h>
#include <gst/gstversion.h>

#include <QDebug>

QT_BEGIN_NAMESPACE

struct QGstreamerMetaDataKeyLookup
{
    QString key;
    const char *token;
    QVariant::Type type;
};

static QVariant fromGStreamerOrientation(const QVariant &value)
{
    // Note gstreamer tokens either describe the counter clockwise rotation of the
    // image or the clockwise transform to apply to correct the image.  The orientation
    // value returned is the clockwise rotation of the image.
    const QString token = value.toString();
    if (token == QStringLiteral("rotate-90"))
        return 270;
    else if (token == QStringLiteral("rotate-180"))
        return 180;
    else if (token == QStringLiteral("rotate-270"))
        return 90;
    else
        return 0;
}

static QVariant toGStreamerOrientation(const QVariant &value)
{
    switch (value.toInt()) {
    case 90:
        return QStringLiteral("rotate-270");
    case 180:
        return QStringLiteral("rotate-180");
    case 270:
        return QStringLiteral("rotate-90");
    default:
        return QStringLiteral("rotate-0");
    }
}

static const QGstreamerMetaDataKeyLookup qt_gstreamerMetaDataKeys[] =
{
    { QMediaMetaData::Title, GST_TAG_TITLE, QVariant::String },
    //{ QMediaMetaData::SubTitle, 0, QVariant::String },
    //{ QMediaMetaData::Author, 0, QVariant::String },
    { QMediaMetaData::Comment, GST_TAG_COMMENT, QVariant::String },
    { QMediaMetaData::Date, GST_TAG_DATE_TIME, QVariant::DateTime },
    { QMediaMetaData::Description, GST_TAG_DESCRIPTION, QVariant::String },
    //{ QMediaMetaData::Category, 0, QVariant::String },
    { QMediaMetaData::Genre, GST_TAG_GENRE, QVariant::String },
    //{ QMediaMetaData::Year, 0, QVariant::Int },
    //{ QMediaMetaData::UserRating, , QVariant::Int },

    { QMediaMetaData::Language, GST_TAG_LANGUAGE_CODE, QVariant::String },

    { QMediaMetaData::Publisher, GST_TAG_ORGANIZATION, QVariant::String },
    { QMediaMetaData::Copyright, GST_TAG_COPYRIGHT, QVariant::String },
    //{ QMediaMetaData::ParentalRating, 0, QVariant::String },
    //{ QMediaMetaData::RatingOrganisation, 0, QVariant::String },

    // Media
    //{ QMediaMetaData::Size, 0, QVariant::Int },
    //{ QMediaMetaData::MediaType, 0, QVariant::String },
    { QMediaMetaData::Duration, GST_TAG_DURATION, QVariant::Int },

    // Audio
    { QMediaMetaData::AudioBitRate, GST_TAG_BITRATE, QVariant::Int },
    { QMediaMetaData::AudioCodec, GST_TAG_AUDIO_CODEC, QVariant::String },
    //{ QMediaMetaData::ChannelCount, 0, QVariant::Int },
    //{ QMediaMetaData::SampleRate, 0, QVariant::Int },

    // Music
    { QMediaMetaData::AlbumTitle, GST_TAG_ALBUM, QVariant::String },
    { QMediaMetaData::AlbumArtist,  GST_TAG_ARTIST, QVariant::String},
    { QMediaMetaData::ContributingArtist, GST_TAG_PERFORMER, QVariant::String },
#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19)
    { QMediaMetaData::Composer, GST_TAG_COMPOSER, QVariant::String },
#endif
    //{ QMediaMetaData::Conductor, 0, QVariant::String },
    //{ QMediaMetaData::Lyrics, 0, QVariant::String },
    //{ QMediaMetaData::Mood, 0, QVariant::String },
    { QMediaMetaData::TrackNumber, GST_TAG_TRACK_NUMBER, QVariant::Int },

    //{ QMediaMetaData::CoverArtUrlSmall, 0, QVariant::String },
    //{ QMediaMetaData::CoverArtUrlLarge, 0, QVariant::String },

    // Image/Video
    //{ QMediaMetaData::Resolution, 0, QVariant::Size },
    //{ QMediaMetaData::PixelAspectRatio, 0, QVariant::Size },

    // Video
    //{ QMediaMetaData::VideoFrameRate, 0, QVariant::String },
    //{ QMediaMetaData::VideoBitRate, 0, QVariant::Double },
    { QMediaMetaData::VideoCodec, GST_TAG_VIDEO_CODEC, QVariant::String },

    //{ QMediaMetaData::PosterUrl, 0, QVariant::String },

    // Movie
    //{ QMediaMetaData::ChapterNumber, 0, QVariant::Int },
    //{ QMediaMetaData::Director, 0, QVariant::String },
    { QMediaMetaData::LeadPerformer, GST_TAG_PERFORMER, QVariant::String },
    //{ QMediaMetaData::Writer, 0, QVariant::String },

#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 30)
    // Photos
    { QMediaMetaData::CameraManufacturer, GST_TAG_DEVICE_MANUFACTURER, QVariant::String },
    { QMediaMetaData::CameraModel, GST_TAG_DEVICE_MODEL, QVariant::String },
    //{ QMediaMetaData::Event, 0, QVariant::String },
    //{ QMediaMetaData::Subject, 0, QVariant::String },

    { QMediaMetaData::Orientation, GST_TAG_IMAGE_ORIENTATION, QVariant::String },

    // GPS
    { QMediaMetaData::GPSLatitude, GST_TAG_GEO_LOCATION_LATITUDE, QVariant::Double },
    { QMediaMetaData::GPSLongitude, GST_TAG_GEO_LOCATION_LONGITUDE, QVariant::Double },
    { QMediaMetaData::GPSAltitude, GST_TAG_GEO_LOCATION_ELEVATION, QVariant::Double },
    { QMediaMetaData::GPSTrack, GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION, QVariant::Double },
    { QMediaMetaData::GPSSpeed, GST_TAG_GEO_LOCATION_MOVEMENT_SPEED, QVariant::Double },
    { QMediaMetaData::GPSImgDirection, GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION, QVariant::Double }
#endif
};

CameraBinMetaData::CameraBinMetaData(QObject *parent)
    :QMetaDataWriterControl(parent)
{
}

QVariant CameraBinMetaData::metaData(const QString &key) const
{
    if (key == QMediaMetaData::Orientation) {
        return fromGStreamerOrientation(m_values.value(QByteArray(GST_TAG_IMAGE_ORIENTATION)));
    } else if (key == QMediaMetaData::GPSSpeed) {
        const double metersPerSec = m_values.value(QByteArray(GST_TAG_GEO_LOCATION_MOVEMENT_SPEED)).toDouble();
        return (metersPerSec * 3600) / 1000;
    }

    static const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup);

    for (int i = 0; i < count; ++i) {
        if (qt_gstreamerMetaDataKeys[i].key == key) {
            const char *name = qt_gstreamerMetaDataKeys[i].token;

            return m_values.value(QByteArray::fromRawData(name, qstrlen(name)));
        }
    }
    return QVariant();
}

void CameraBinMetaData::setMetaData(const QString &key, const QVariant &value)
{
    QVariant correctedValue = value;
    if (key == QMediaMetaData::Orientation) {
        correctedValue = toGStreamerOrientation(value);
    } else if (key == QMediaMetaData::GPSSpeed) {
        // kilometers per hour to meters per second.
        correctedValue = (value.toDouble() * 1000) / 3600;
    }

    static const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup);

    for (int i = 0; i < count; ++i) {
        if (qt_gstreamerMetaDataKeys[i].key == key) {
            const char *name = qt_gstreamerMetaDataKeys[i].token;

            correctedValue.convert(qt_gstreamerMetaDataKeys[i].type);

            m_values.insert(QByteArray::fromRawData(name, qstrlen(name)), correctedValue);

            emit QMetaDataWriterControl::metaDataChanged();
            emit metaDataChanged(m_values);

            return;
        }
    }
}

QStringList CameraBinMetaData::availableMetaData() const
{
    static QMap<QByteArray, QString> keysMap;
    if (keysMap.isEmpty()) {
        const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup);
        for (int i = 0; i < count; ++i) {
            keysMap[QByteArray(qt_gstreamerMetaDataKeys[i].token)] = qt_gstreamerMetaDataKeys[i].key;
        }
    }

    QStringList res;
    foreach (const QByteArray &key, m_values.keys()) {
        QString tag = keysMap.value(key);
        if (!tag.isEmpty())
            res.append(tag);
    }

    return res;
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2008      Dennis Nienhüser <earthwings@gentoo.org>
// Copyright 2010      Bastian Holst <bastianholst@gmx.de>
// Copyright 2013      Mohammed Nafees <nafees.technocool@gmail.com>
//

#include "NavigationFloatItem.h"

#include <QtCore/qmath.h>
#include <QtCore/QRect>
#include <QtGui/QPixmap>
#include <QtGui/QToolButton>
#include <QtGui/QSlider>
#include <QtGui/QWidget>
#include <QtGui/QPainter>

#include "ui_navigation.h"
#include "ViewportParams.h"
#include "MarbleDebug.h"
#include "MarbleWidget.h"
#include "WidgetGraphicsItem.h"
#include "MarbleGraphicsGridLayout.h"

using namespace Marble;
/* TRANSLATOR Marble::NavigationFloatItem */

const int defaultMinZoom = 900;
const int defaultMaxZoom = 2400;

NavigationFloatItem::NavigationFloatItem()
    : AbstractFloatItem( 0 )
{
}

NavigationFloatItem::NavigationFloatItem( const MarbleModel *marbleModel )
    : AbstractFloatItem( marbleModel, QPointF( -10, -30 ) ),
      m_marbleWidget( 0 ),
      m_widgetItem( 0 ),
      m_navigationWidget( 0 ),
      m_oldViewportRadius( 0 )
{
    // Plugin is enabled by default
    setEnabled( true );
    setVisible( false );

    setCacheMode( NoCache );
    setBackground( QBrush( Qt::transparent ) );
    setBorderBrush( QBrush( Qt::transparent ) );
}

NavigationFloatItem::~NavigationFloatItem()
{
    delete m_navigationWidget;
}

QStringList NavigationFloatItem::backendTypes() const
{
    return QStringList("navigation");
}

QString NavigationFloatItem::name() const
{
    return tr("Navigation");
}

QString NavigationFloatItem::guiString() const
{
    return tr("&Navigation");
}

QString NavigationFloatItem::nameId() const
{
    return QString("navigation");
}

QString NavigationFloatItem::version() const
{
    return "1.0";
}

QString NavigationFloatItem::description() const
{
    return tr("A mouse control to zoom and move the map");
}

QString NavigationFloatItem::copyrightYears() const
{
    return "2008, 2010, 2013";
}

QList<PluginAuthor> NavigationFloatItem::pluginAuthors() const
{
    return QList<PluginAuthor>()
            << PluginAuthor( QString::fromUtf8( "Dennis Nienhüser" ), "earthwings@gentoo.org" )
            << PluginAuthor( "Bastian Holst", "bastianholst@gmx.de" )
            << PluginAuthor( "Mohammed Nafees", "nafees.technocool@gmail.com" );
}

QIcon NavigationFloatItem::icon() const
{
    return QIcon(":/icons/navigation.png");
}

void NavigationFloatItem::initialize()
{
    QWidget *navigationParent = new QWidget( 0 );

    m_navigationWidget = new Ui::Navigation;
    m_navigationWidget->setupUi( navigationParent );

    m_widgetItem = new WidgetGraphicsItem( this );
    m_widgetItem->setWidget( navigationParent );

    MarbleGraphicsGridLayout *layout = new MarbleGraphicsGridLayout( 1, 1 );
    layout->addItem( m_widgetItem, 0, 0 );

    setLayout( layout );
}

bool NavigationFloatItem::isInitialized() const
{
    return m_widgetItem;
}

void NavigationFloatItem::changeViewport( ViewportParams *viewport )
{
    if ( viewport->radius() != m_oldViewportRadius ) {
        const qreal zoomValue = (200.0 * qLn( viewport->radius() ) ); // copied from MarbleWidgetPrivate::zoom()
        setZoomSliderValue( zoomValue );

        m_oldViewportRadius = viewport->radius();
        // The slider depends on the map state (zoom factor)
        update();
    }
}

bool NavigationFloatItem::eventFilter( QObject *object, QEvent *e )
{
    if ( !enabled() || !visible() ) {
        return false;
    }

    MarbleWidget *widget = dynamic_cast<MarbleWidget*> (object);
    if ( !widget ) {
        return AbstractFloatItem::eventFilter( object, e );
    }

    if ( m_marbleWidget != widget ) {
        // Delayed initialization
        m_marbleWidget = widget;

        m_navigationWidget->arrowDisc->setMarbleWidget( m_marbleWidget );
        connect( m_navigationWidget->arrowDisc, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()) );

        connect( m_navigationWidget->homeButton, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()) );
        connect( m_navigationWidget->homeButton, SIGNAL(clicked()),
                 m_marbleWidget, SLOT(goHome()) );
     }

    return AbstractFloatItem::eventFilter(object, e);
}

void NavigationFloatItem::setZoomSliderValue( int level )
{
}

void NavigationFloatItem::setMarbleZoomValue( int level )
{
    // There exists a circular signal/slot connection between MarbleWidget and this widget's
    // zoom slider. MarbleWidget prevents recursion, but it still loops one time unless
    // disconnected here.
    // The circular signal/slot connection results into the Marble Globe flickering, when the
    // zoom slider is used.

    if( !m_marbleWidget ) {
        return;
    }

    disconnect( m_marbleWidget, SIGNAL(zoomChanged(int)),
                this, SLOT(setZoomSliderValue(int)) );
    m_marbleWidget->zoomView( level );
    connect( m_marbleWidget, SIGNAL(zoomChanged(int)),
                this, SLOT(setZoomSliderValue(int)) );
}

void NavigationFloatItem::selectTheme( QString theme )
{
    Q_UNUSED(theme);
}

void NavigationFloatItem::adjustForAnimation()
{
    if ( !m_marbleWidget ) {
        return;
    }

    m_marbleWidget->setViewContext( Animation );
}

void NavigationFloatItem::adjustForStill()
{
    if ( !m_marbleWidget ) {
        return;
    }

    m_marbleWidget->setViewContext( Still );
}

void NavigationFloatItem::updateButtons( int zoomValue )
{
}

Q_EXPORT_PLUGIN2( NavigationFloatItem, Marble::NavigationFloatItem )

#include "NavigationFloatItem.moc"
<commit_msg>Transparent background<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2008      Dennis Nienhüser <earthwings@gentoo.org>
// Copyright 2010      Bastian Holst <bastianholst@gmx.de>
// Copyright 2013      Mohammed Nafees <nafees.technocool@gmail.com>
//

#include "NavigationFloatItem.h"

#include <QtCore/qmath.h>
#include <QtCore/QRect>
#include <QtGui/QPixmap>
#include <QtGui/QToolButton>
#include <QtGui/QSlider>
#include <QtGui/QWidget>
#include <QtGui/QPainter>

#include "ui_navigation.h"
#include "ViewportParams.h"
#include "MarbleDebug.h"
#include "MarbleWidget.h"
#include "WidgetGraphicsItem.h"
#include "MarbleGraphicsGridLayout.h"

using namespace Marble;
/* TRANSLATOR Marble::NavigationFloatItem */

const int defaultMinZoom = 900;
const int defaultMaxZoom = 2400;

NavigationFloatItem::NavigationFloatItem()
    : AbstractFloatItem( 0 )
{
}

NavigationFloatItem::NavigationFloatItem( const MarbleModel *marbleModel )
    : AbstractFloatItem( marbleModel, QPointF( -10, -30 ) ),
      m_marbleWidget( 0 ),
      m_widgetItem( 0 ),
      m_navigationWidget( 0 ),
      m_oldViewportRadius( 0 )
{
    // Plugin is enabled by default
    setEnabled( true );
    setVisible( false );

    setCacheMode( NoCache );
    setBackground( QBrush( QColor( Qt::transparent ) ) );
    setFrame( NoFrame );
}

NavigationFloatItem::~NavigationFloatItem()
{
    delete m_navigationWidget;
}

QStringList NavigationFloatItem::backendTypes() const
{
    return QStringList("navigation");
}

QString NavigationFloatItem::name() const
{
    return tr("Navigation");
}

QString NavigationFloatItem::guiString() const
{
    return tr("&Navigation");
}

QString NavigationFloatItem::nameId() const
{
    return QString("navigation");
}

QString NavigationFloatItem::version() const
{
    return "1.0";
}

QString NavigationFloatItem::description() const
{
    return tr("A mouse control to zoom and move the map");
}

QString NavigationFloatItem::copyrightYears() const
{
    return "2008, 2010, 2013";
}

QList<PluginAuthor> NavigationFloatItem::pluginAuthors() const
{
    return QList<PluginAuthor>()
            << PluginAuthor( QString::fromUtf8( "Dennis Nienhüser" ), "earthwings@gentoo.org" )
            << PluginAuthor( "Bastian Holst", "bastianholst@gmx.de" )
            << PluginAuthor( "Mohammed Nafees", "nafees.technocool@gmail.com" );
}

QIcon NavigationFloatItem::icon() const
{
    return QIcon(":/icons/navigation.png");
}

void NavigationFloatItem::initialize()
{
    QWidget *navigationParent = new QWidget( 0 );
    navigationParent->setAttribute( Qt::WA_NoSystemBackground, true );

    m_navigationWidget = new Ui::Navigation;
    m_navigationWidget->setupUi( navigationParent );

    m_widgetItem = new WidgetGraphicsItem( this );
    m_widgetItem->setWidget( navigationParent );

    MarbleGraphicsGridLayout *layout = new MarbleGraphicsGridLayout( 1, 1 );
    layout->addItem( m_widgetItem, 0, 0 );

    setLayout( layout );
}

bool NavigationFloatItem::isInitialized() const
{
    return m_widgetItem;
}

void NavigationFloatItem::changeViewport( ViewportParams *viewport )
{
    if ( viewport->radius() != m_oldViewportRadius ) {
        const qreal zoomValue = (200.0 * qLn( viewport->radius() ) ); // copied from MarbleWidgetPrivate::zoom()
        setZoomSliderValue( zoomValue );

        m_oldViewportRadius = viewport->radius();
        // The slider depends on the map state (zoom factor)
        update();
    }
}

bool NavigationFloatItem::eventFilter( QObject *object, QEvent *e )
{
    if ( !enabled() || !visible() ) {
        return false;
    }

    MarbleWidget *widget = dynamic_cast<MarbleWidget*> (object);
    if ( !widget ) {
        return AbstractFloatItem::eventFilter( object, e );
    }

    if ( m_marbleWidget != widget ) {
        // Delayed initialization
        m_marbleWidget = widget;

        m_navigationWidget->arrowDisc->setMarbleWidget( m_marbleWidget );
        connect( m_navigationWidget->arrowDisc, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()) );

        connect( m_navigationWidget->homeButton, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()) );
        connect( m_navigationWidget->homeButton, SIGNAL(clicked()),
                 m_marbleWidget, SLOT(goHome()) );
     }

    return AbstractFloatItem::eventFilter(object, e);
}

void NavigationFloatItem::setZoomSliderValue( int level )
{
}

void NavigationFloatItem::setMarbleZoomValue( int level )
{
    // There exists a circular signal/slot connection between MarbleWidget and this widget's
    // zoom slider. MarbleWidget prevents recursion, but it still loops one time unless
    // disconnected here.
    // The circular signal/slot connection results into the Marble Globe flickering, when the
    // zoom slider is used.

    if( !m_marbleWidget ) {
        return;
    }

    disconnect( m_marbleWidget, SIGNAL(zoomChanged(int)),
                this, SLOT(setZoomSliderValue(int)) );
    m_marbleWidget->zoomView( level );
    connect( m_marbleWidget, SIGNAL(zoomChanged(int)),
                this, SLOT(setZoomSliderValue(int)) );
}

void NavigationFloatItem::selectTheme( QString theme )
{
    Q_UNUSED(theme);
}

void NavigationFloatItem::adjustForAnimation()
{
    if ( !m_marbleWidget ) {
        return;
    }

    m_marbleWidget->setViewContext( Animation );
}

void NavigationFloatItem::adjustForStill()
{
    if ( !m_marbleWidget ) {
        return;
    }

    m_marbleWidget->setViewContext( Still );
}

void NavigationFloatItem::updateButtons( int zoomValue )
{
}

Q_EXPORT_PLUGIN2( NavigationFloatItem, Marble::NavigationFloatItem )

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


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

#include "callgrinddatamodel.h"

#include "callgrindparsedata.h"
#include "callgrindfunction.h"
#include "callgrindcostitem.h"

#include <utils/qtcassert.h>

#include <QChar>
#include <QDebug>
#include <QStringList>
#include <QTextDocument>
#include <QVector>

namespace Valgrind {
namespace Callgrind {

//BEGIN Helper

namespace {
    // minimum amount of columns, i.e.:
    // function name
    // file name
    // object name
    // num called
    // Additional to this, 2 * ParseData::events().size will be shown (inclusive + self cost)
    const int MinColumnSize = 4;
}

//BEGIN DataModel::Private

class DataModel::Private
{
public:
    Private()
    : m_data(0)
    , m_event(0)
    , m_verboseToolTips(true)
    , m_cycleDetection(false)
    , m_shortenTemplates(false)
    {
    }

    void updateFunctions();

    const ParseData *m_data;
    int m_event;
    bool m_verboseToolTips;
    bool m_cycleDetection;
    bool m_shortenTemplates;
    QVector<const Function *> m_functions;
};

struct SortFunctions {
    SortFunctions(int event)
    : m_event(event)
    {
    }
    bool operator()(const Function *left, const Function *right)
    {
        return left->inclusiveCost(m_event) > right->inclusiveCost(m_event);
    }
    int m_event;
};

void DataModel::Private::updateFunctions()
{
    if (m_data) {
        m_functions = m_data->functions(m_cycleDetection);
        qSort(m_functions.begin(), m_functions.end(), SortFunctions(m_event));
    } else {
        m_functions.clear();
    }
}

//BEGIN DataModel

DataModel::DataModel(QObject *parent)
   : QAbstractItemModel(parent), d(new Private)
{
}

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

void DataModel::setParseData(const ParseData *data)
{
    if (d->m_data == data)
        return;

    beginResetModel();
    d->m_data = data;
    d->m_event = 0;
    d->updateFunctions();
    endResetModel();
}

void DataModel::setVerboseToolTipsEnabled(bool enabled)
{
    d->m_verboseToolTips = enabled;
}

bool DataModel::verboseToolTipsEnabled() const
{
    return d->m_verboseToolTips;
}

const ParseData *DataModel::parseData() const
{
    return d->m_data;
}

void DataModel::setCostEvent(int event)
{
    if (!d->m_data)
        return;

    QTC_ASSERT(event >= 0 && d->m_data->events().size() > event, return);
    beginResetModel();
    d->m_event = event;
    d->updateFunctions();
    endResetModel();
    emit dataChanged(index(0, SelfCostColumn), index(qMax(0, rowCount() - 1), InclusiveCostColumn));
}

int DataModel::costEvent() const
{
    return d->m_event;
}

int DataModel::rowCount(const QModelIndex &parent) const
{
    QTC_ASSERT(!parent.isValid() || parent.model() == this, return 0);

    if (!d->m_data || parent.isValid())
        return 0;

    return d->m_functions.size();
}

int DataModel::columnCount(const QModelIndex &parent) const
{
    QTC_ASSERT(!parent.isValid() || parent.model() == this, return 0);
    if (parent.isValid())
        return 0;

    return ColumnCount;
}

QModelIndex DataModel::index(int row, int column, const QModelIndex &parent) const
{
    QTC_ASSERT(!parent.isValid() || parent.model() == this, return QModelIndex());
    if (row == 0 && rowCount(parent) == 0) // happens with empty models
        return QModelIndex();
    QTC_ASSERT(row >= 0 && row < rowCount(parent), return QModelIndex());
    return createIndex(row, column);
}

QModelIndex DataModel::parent(const QModelIndex &child) const
{
    QTC_ASSERT(!child.isValid() || child.model() == this, return QModelIndex());
    return QModelIndex();
}

QModelIndex DataModel::indexForObject(const Function *function) const
{
    if (!function)
        return QModelIndex();

    const int row = d->m_functions.indexOf(function);
    if (row < 0)
        return QModelIndex();

    return createIndex(row, 0);
}

/**
 * Evil workaround for https://bugreports.qt-project.org/browse/QTBUG-1135
 * Just replace the bad hyphens by a 'NON-BREAKING HYPHEN' unicode char
 */
static QString noWrap(const QString &str)
{
    QString escapedStr = str;
    return escapedStr.replace(QLatin1Char('-'), "‑");
}

static QString shortenTemplate(QString str)
{
    int depth = 0;
    int  j = 0;
    for (int i = 0, n = str.size(); i != n; ++i) {
        int c = str.at(i).unicode();
        if (c == '>')
            --depth;
        if (depth == 0)
            str[j++] = str.at(i);
        if (c == '<')
            ++depth;
    }
    str.truncate(j);
    return str;
}

QVariant DataModel::data(const QModelIndex &index, int role) const
{
    //QTC_ASSERT(index.isValid() && index.model() == this, return QVariant());
    //QTC_ASSERT(index.column() >= 0 && index.column() < columnCount(index.parent()), return QVariant());
    //QTC_ASSERT(index.row() >= 0 && index.row() < rowCount(index.parent()), return QVariant());

    const Function *func = d->m_functions.at(index.row());

    if (role == Qt::DisplayRole) {
        if (index.column() == NameColumn)
            return d->m_shortenTemplates ? shortenTemplate(func->name()) : func->name();
        if (index.column() == LocationColumn)
            return func->location();
        if (index.column() == CalledColumn)
            return func->called();
        if (index.column() == SelfCostColumn)
            return func->selfCost(d->m_event);
        if (index.column() == InclusiveCostColumn)
            return func->inclusiveCost(d->m_event);
        return QVariant();
    }

    if (role == Qt::ToolTipRole) {
        if (!d->m_verboseToolTips)
            return data(index, Qt::DisplayRole);

        QString ret = "\n";

        // body, function info first
        ret += "
";
        ret += "
" + tr("Function:") + "

" + Qt::escape(func->name()) + "
\n";
        ret += "
" + tr("File:") + "

" + func->file() + "
\n";
        if (!func->costItems().isEmpty()) {
            const CostItem *firstItem = func->costItems().first();
            for (int i = 0; i < d->m_data->positions().size(); ++i) {
                ret += "
" + ParseData::prettyStringForPosition(d->m_data->positions().at(i)) + "
";
                ret += "
" + QString::number(firstItem->position(i)) + "
\n";
            }
        }
        ret += "
" + tr("Object:") + "

" + func->object() + "
\n";
        ret += "
" + tr("Called:") + "

" + tr("%n time(s)", 0, func->called()) + "
\n";
        ret += "

";

        // self/inclusive costs
        ret += "
";
        ret += "

" + tr("Events") + "	";
        ret += "" + tr("Self costs") + "	" + tr("(%)") + "	";
        ret += "" + tr("Incl. costs") + "	" + tr("(%)") +  "	";
        ret += "

";
        ret += "
";
        for (int i = 0; i < d->m_data->events().size(); ++i) {
            quint64 selfCost = func->selfCost(i);
            quint64 inclCost = func->inclusiveCost(i);
            quint64 totalCost = d->m_data->totalCost(i);
            // 0.00% format
            const float relSelfCost = (float)qRound((float)selfCost / totalCost * 10000) / 100;
            const float relInclCost = (float)qRound((float)inclCost / totalCost * 10000) / 100;

            ret += "
";
            ret += "<nobr>" + noWrap(ParseData::prettyStringForEvent(d->m_data->events().at(i))) + "</nobr>	";
            ret += "" + tr("%1").arg(selfCost) + "	";
            ret += "" + tr("(%1%)").arg(relSelfCost) + "	";
            ret += "" + tr("%1").arg(inclCost) + "	";
            ret += "" + tr("(%1%)").arg(relInclCost) + "	";
            ret += "
";
        }
        ret += "

";
        ret += "";
        return ret;
    }

    if (role == FunctionRole) {
        return QVariant::fromValue(func);
    }

    if (role == ParentCostRole) {
        const quint64 totalCost = d->m_data->totalCost(d->m_event);
        return totalCost;
    }

    // the data model does not know about parent<->child relationship
    if (role == RelativeParentCostRole || role == RelativeTotalCostRole) {
        const quint64 totalCost = d->m_data->totalCost(d->m_event);
        if (index.column() == SelfCostColumn)
            return double(func->selfCost(d->m_event)) / totalCost;
        if (index.column() == InclusiveCostColumn) {
            return double(func->inclusiveCost(d->m_event)) / totalCost;
        }
    }

    if (role == LineNumberRole) {
        return func->lineNumber();
    }

    if (role == FileNameRole) {
        return func->file();
    }

    if (role == Qt::TextAlignmentRole) {
        if (index.column() == CalledColumn)
            return Qt::AlignRight;
    }

    return QVariant();
}

QVariant DataModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Vertical || (role != Qt::DisplayRole && role != Qt::ToolTipRole))
        return QVariant();

    QTC_ASSERT(section >= 0 && section < columnCount(), return QVariant());

    if (role == Qt::ToolTipRole) {
        if (!d->m_data)
            return QVariant();

        const QString prettyCostStr = ParseData::prettyStringForEvent(d->m_data->events().at(d->m_event));
        if (section == SelfCostColumn)
            return tr("%1 cost spent in a given function excluding costs from called functions.").arg(prettyCostStr);
        if (section == InclusiveCostColumn)
            return tr("%1 cost spent in a given function including costs from called functions.").arg(prettyCostStr);
        return QVariant();
    }

    if (section == NameColumn)
        return tr("Function");
    if (section == LocationColumn)
        return tr("Location");
    if (section == CalledColumn)
        return tr("Called");
    if (section == SelfCostColumn)
        return tr("Self Cost: %1").arg(d->m_data ? d->m_data->events().value(d->m_event) : QString());
    if (section == InclusiveCostColumn)
        return tr("Incl. Cost: %1").arg(d->m_data ? d->m_data->events().value(d->m_event) : QString());

    return QVariant();
}

void DataModel::enableCycleDetection(bool enabled)
{
    beginResetModel();
    d->m_cycleDetection = enabled;
    d->updateFunctions();
    endResetModel();
}

void DataModel::setShortenTemplates(bool enabled)
{
    beginResetModel();
    d->m_shortenTemplates = enabled;
    d->updateFunctions();
    endResetModel();
}

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

#include "callgrinddatamodel.h"

#include "callgrindparsedata.h"
#include "callgrindfunction.h"
#include "callgrindcostitem.h"

#include <utils/qtcassert.h>

#include <QChar>
#include <QDebug>
#include <QStringList>
#include <QTextDocument>
#include <QVector>

namespace Valgrind {
namespace Callgrind {

//BEGIN Helper

namespace {
    // minimum amount of columns, i.e.:
    // function name
    // file name
    // object name
    // num called
    // Additional to this, 2 * ParseData::events().size will be shown (inclusive + self cost)
    const int MinColumnSize = 4;
}

//BEGIN DataModel::Private

class DataModel::Private
{
public:
    Private()
    : m_data(0)
    , m_event(0)
    , m_verboseToolTips(true)
    , m_cycleDetection(false)
    , m_shortenTemplates(false)
    {
    }

    void updateFunctions();

    const ParseData *m_data;
    int m_event;
    bool m_verboseToolTips;
    bool m_cycleDetection;
    bool m_shortenTemplates;
    QVector<const Function *> m_functions;
};

struct SortFunctions {
    SortFunctions(int event)
    : m_event(event)
    {
    }
    bool operator()(const Function *left, const Function *right)
    {
        return left->inclusiveCost(m_event) > right->inclusiveCost(m_event);
    }
    int m_event;
};

void DataModel::Private::updateFunctions()
{
    if (m_data) {
        m_functions = m_data->functions(m_cycleDetection);
        qSort(m_functions.begin(), m_functions.end(), SortFunctions(m_event));
    } else {
        m_functions.clear();
    }
}

//BEGIN DataModel

DataModel::DataModel(QObject *parent)
   : QAbstractItemModel(parent), d(new Private)
{
}

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

void DataModel::setParseData(const ParseData *data)
{
    if (d->m_data == data)
        return;

    beginResetModel();
    d->m_data = data;
    d->m_event = 0;
    d->updateFunctions();
    endResetModel();
}

void DataModel::setVerboseToolTipsEnabled(bool enabled)
{
    d->m_verboseToolTips = enabled;
}

bool DataModel::verboseToolTipsEnabled() const
{
    return d->m_verboseToolTips;
}

const ParseData *DataModel::parseData() const
{
    return d->m_data;
}

void DataModel::setCostEvent(int event)
{
    if (!d->m_data)
        return;

    QTC_ASSERT(event >= 0 && d->m_data->events().size() > event, return);
    beginResetModel();
    d->m_event = event;
    d->updateFunctions();
    endResetModel();
    emit dataChanged(index(0, SelfCostColumn), index(qMax(0, rowCount() - 1), InclusiveCostColumn));
}

int DataModel::costEvent() const
{
    return d->m_event;
}

int DataModel::rowCount(const QModelIndex &parent) const
{
    QTC_ASSERT(!parent.isValid() || parent.model() == this, return 0);

    if (!d->m_data || parent.isValid())
        return 0;

    return d->m_functions.size();
}

int DataModel::columnCount(const QModelIndex &parent) const
{
    QTC_ASSERT(!parent.isValid() || parent.model() == this, return 0);
    if (parent.isValid())
        return 0;

    return ColumnCount;
}

QModelIndex DataModel::index(int row, int column, const QModelIndex &parent) const
{
    QTC_ASSERT(!parent.isValid() || parent.model() == this, return QModelIndex());
    if (row == 0 && rowCount(parent) == 0) // happens with empty models
        return QModelIndex();
    QTC_ASSERT(row >= 0 && row < rowCount(parent), return QModelIndex());
    return createIndex(row, column);
}

QModelIndex DataModel::parent(const QModelIndex &child) const
{
    QTC_ASSERT(!child.isValid() || child.model() == this, return QModelIndex());
    return QModelIndex();
}

QModelIndex DataModel::indexForObject(const Function *function) const
{
    if (!function)
        return QModelIndex();

    const int row = d->m_functions.indexOf(function);
    if (row < 0)
        return QModelIndex();

    return createIndex(row, 0);
}

/**
 * Evil workaround for https://bugreports.qt-project.org/browse/QTBUG-1135
 * Just replace the bad hyphens by a 'NON-BREAKING HYPHEN' unicode char
 */
static QString noWrap(const QString &str)
{
    QString escapedStr = str;
    return escapedStr.replace(QLatin1Char('-'), "‑");
}

static QString shortenTemplate(QString str)
{
    int depth = 0;
    int  j = 0;
    for (int i = 0, n = str.size(); i != n; ++i) {
        int c = str.at(i).unicode();
        if (c == '>')
            --depth;
        if (depth == 0)
            str[j++] = str.at(i);
        if (c == '<')
            ++depth;
    }
    str.truncate(j);
    return str;
}

QVariant DataModel::data(const QModelIndex &index, int role) const
{
    //QTC_ASSERT(index.isValid() && index.model() == this, return QVariant());
    //QTC_ASSERT(index.column() >= 0 && index.column() < columnCount(index.parent()), return QVariant());
    //QTC_ASSERT(index.row() >= 0 && index.row() < rowCount(index.parent()), return QVariant());

    const Function *func = d->m_functions.at(index.row());

    if (role == Qt::DisplayRole) {
        if (index.column() == NameColumn)
            return d->m_shortenTemplates ? shortenTemplate(func->name()) : func->name();
        if (index.column() == LocationColumn)
            return func->location();
        if (index.column() == CalledColumn)
            return func->called();
        if (index.column() == SelfCostColumn)
            return func->selfCost(d->m_event);
        if (index.column() == InclusiveCostColumn)
            return func->inclusiveCost(d->m_event);
        return QVariant();
    }

    if (role == Qt::ToolTipRole) {
        if (!d->m_verboseToolTips)
            return data(index, Qt::DisplayRole);

        QString ret = QLatin1String("\n
");

        QString entry = QLatin1String("
%1

%2
\n");
        // body, function info first
        ret += entry.arg(tr("Function:")).arg(Qt::escape(func->name()));
        ret += entry.arg(tr("File:")).arg(func->file());
        if (!func->costItems().isEmpty()) {
            const CostItem *firstItem = func->costItems().first();
            for (int i = 0; i < d->m_data->positions().size(); ++i) {
                ret += entry.arg(ParseData::prettyStringForPosition(d->m_data->positions().at(i)))
                       .arg(firstItem->position(i));
            }
        }
        ret += entry.arg(tr("Object:")).arg(func->object());
        ret += entry.arg(tr("Called:")).arg(tr("%n time(s)", 0, func->called()));
        ret += QLatin1String("

");

        // self/inclusive costs
        entry = QLatin1String("%1	%2	");
        ret += QLatin1String("
");
        ret += QLatin1String("

");
        ret += QLatin1String("") + tr("Events") + QLatin1String("	");
        ret += entry.arg(tr("Self costs")).arg(tr("(%)"));
        ret += entry.arg(tr("Incl. costs")).arg(tr("(%)"));
        ret += QLatin1String("

");
        ret += QLatin1String("
");
        for (int i = 0; i < d->m_data->events().size(); ++i) {
            quint64 selfCost = func->selfCost(i);
            quint64 inclCost = func->inclusiveCost(i);
            quint64 totalCost = d->m_data->totalCost(i);
            // 0.00% format
            const float relSelfCost = (float)qRound((float)selfCost / totalCost * 10000) / 100;
            const float relInclCost = (float)qRound((float)inclCost / totalCost * 10000) / 100;

            ret += QLatin1String("
");
            ret += QLatin1String("<nobr>") +
                    noWrap(ParseData::prettyStringForEvent(d->m_data->events().at(i)))
                    + QLatin1String("</nobr>	");
            ret += entry.arg(selfCost).arg(tr("(%1%)").arg(relSelfCost));
            ret += entry.arg(inclCost).arg(tr("(%1%)").arg(relInclCost));
            ret += QLatin1String("
");
        }
        ret += QLatin1String("

");
        ret += QLatin1String("");
        return ret;
    }

    if (role == FunctionRole) {
        return QVariant::fromValue(func);
    }

    if (role == ParentCostRole) {
        const quint64 totalCost = d->m_data->totalCost(d->m_event);
        return totalCost;
    }

    // the data model does not know about parent<->child relationship
    if (role == RelativeParentCostRole || role == RelativeTotalCostRole) {
        const quint64 totalCost = d->m_data->totalCost(d->m_event);
        if (index.column() == SelfCostColumn)
            return double(func->selfCost(d->m_event)) / totalCost;
        if (index.column() == InclusiveCostColumn) {
            return double(func->inclusiveCost(d->m_event)) / totalCost;
        }
    }

    if (role == LineNumberRole) {
        return func->lineNumber();
    }

    if (role == FileNameRole) {
        return func->file();
    }

    if (role == Qt::TextAlignmentRole) {
        if (index.column() == CalledColumn)
            return Qt::AlignRight;
    }

    return QVariant();
}

QVariant DataModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Vertical || (role != Qt::DisplayRole && role != Qt::ToolTipRole))
        return QVariant();

    QTC_ASSERT(section >= 0 && section < columnCount(), return QVariant());

    if (role == Qt::ToolTipRole) {
        if (!d->m_data)
            return QVariant();

        const QString prettyCostStr = ParseData::prettyStringForEvent(d->m_data->events().at(d->m_event));
        if (section == SelfCostColumn)
            return tr("%1 cost spent in a given function excluding costs from called functions.").arg(prettyCostStr);
        if (section == InclusiveCostColumn)
            return tr("%1 cost spent in a given function including costs from called functions.").arg(prettyCostStr);
        return QVariant();
    }

    if (section == NameColumn)
        return tr("Function");
    if (section == LocationColumn)
        return tr("Location");
    if (section == CalledColumn)
        return tr("Called");
    if (section == SelfCostColumn)
        return tr("Self Cost: %1").arg(d->m_data ? d->m_data->events().value(d->m_event) : QString());
    if (section == InclusiveCostColumn)
        return tr("Incl. Cost: %1").arg(d->m_data ? d->m_data->events().value(d->m_event) : QString());

    return QVariant();
}

void DataModel::enableCycleDetection(bool enabled)
{
    beginResetModel();
    d->m_cycleDetection = enabled;
    d->updateFunctions();
    endResetModel();
}

void DataModel::setShortenTemplates(bool enabled)
{
    beginResetModel();
    d->m_shortenTemplates = enabled;
    d->updateFunctions();
    endResetModel();
}

} // namespace Valgrind
} // namespace Callgrind
<|endoftext|>