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

#include "compiler/cstring.h"
#include "compiler/compiler.h"
#include "compiler/scope.h"
#include "compiler/value.h"
#include "interpreter/location.hh"
#include "types/native_types.h"

namespace clever {

// Declaration of namespace global type ptrs for Clever native types
DECLARE_CLEVER_NATIVE_TYPES();

/// Compiler initialization phase
void Compiler::init()
{
	m_scope = new Scope;

	m_ir.reserve(20);
	m_scope_pool.reserve(10);
	m_type_pool.reserve(15);

	m_scope_pool[m_scope_id++] = m_scope;

	// Native type allocation
	m_type_pool[m_type_id++] = CLEVER_INT_TYPE    = new IntType;
	m_type_pool[m_type_id++] = CLEVER_DOUBLE_TYPE = new DoubleType;
	m_type_pool[m_type_id++] = CLEVER_STR_TYPE    = new StrType;
	m_type_pool[m_type_id++] = CLEVER_FUNC_TYPE   = new FuncType;

	m_pkg.init();
}

/// Frees all resource used by the compiler
void Compiler::shutdown()
{
	m_pkg.shutdown();

	CLEVER_SAFE_DELETE(g_cstring_tbl);
	CLEVER_SAFE_DELETE(m_scope);

	TypePool::const_iterator it2 = m_type_pool.begin(),
		end2 = m_type_pool.end();

	while (it2 != end2) {
		delete *it2;
		++it2;
	}
}

// Compiler termination phase
void Compiler::end()
{
}

/// Displays an error message and exits
void Compiler::error(const char* msg) const
{
	std::cerr << "Compile error: " << msg << std::endl;
	CLEVER_EXIT_FATAL();
}

/// Displays an error message
void Compiler::error(const std::string& message, const location& loc) const
{
	if (loc.begin.filename) {
		std::cerr << "Compile error: " << message << " on "
			<< *loc.begin.filename << " line " << loc.begin.line << "\n";
	} else {
		std::cerr << "Compile error: " << message << " on line "
			<< loc.begin.line << "\n";
	}
	CLEVER_EXIT_FATAL();
}

/// Displays a formatted error message and abort the compilation
void Compiler::errorf(const location& loc, const char* format, ...) const
{
	std::ostringstream out;
	va_list args;

	va_start(args, format);

	vsprintf(out, format, args);

	va_end(args);

	error(out.str(), loc);
}

/// Abstracts the Value* ptr gets from Node
// NOTE: When the Node is a STRCONST, it automatically increments the Value's
// refcount related to the Symbol
Value* Compiler::getValue(Node& node, Symbol** symbol, const location& loc) const
{
	if (node.type == VALUE) {
		return node.data.val;
	} else if (node.type == STRCONST) {
		Symbol* sym = m_scope->getAny(node.data.str);

		if (!sym) {
			errorf(loc, "Variable `%S' cannot be found!", node.data.str);
		}
		if (symbol) {
			*symbol = sym;
		}

		return m_scope_pool[sym->scope->getId()]->getVar(sym->value_id);
	}
	return NULL;
}

/// Compiles a variable declaration
void Compiler::varDeclaration(Node& var, Node* node, const location& loc)
{
	Symbol* sym = m_scope->getLocal(var.data.str);

	if (sym) {
		errorf(loc, "Variable `%S' already declared in the scope!", var.data.str);
	}

	size_t sym_id = m_scope->pushVar(var.data.str, new Value());

	// A NULL value is created for uninitialized declaration
	sym = NULL;
	Value* val = node ? getValue(*node, &sym, loc) : new Value();

	// Value to be assigned
	if (sym) {
		m_ir.push_back(
			IR(OP_ASSIGN, FETCH_VAL, sym_id, FETCH_VAL, sym->value_id));

		m_ir.back().op2_scope = sym->scope->getId();
	} else {
		m_ir.push_back(
			IR(OP_ASSIGN, FETCH_VAL, sym_id, FETCH_VAL, m_scope->pushConst(val)));

		m_ir.back().op2_scope = m_scope->getId();
	}
	m_ir.back().op1_scope = m_scope->getId();
}

/// Compiles a variable assignment
void Compiler::assignment(Node& var, Node& value, const location& loc)
{
	Symbol* var_sym = NULL, *val_sym = NULL;
	(void)getValue(var, &var_sym, loc);
	Value* val = getValue(value, &val_sym, loc);

	if (val_sym) {
		m_ir.push_back(
			IR(OP_ASSIGN, FETCH_VAL, var_sym->value_id, FETCH_VAL, val_sym->value_id));

		m_ir.back().op1_scope = var_sym->scope->getId();
		m_ir.back().op2_scope = val_sym->scope->getId();
	} else {
		m_ir.push_back(
			IR(OP_ASSIGN, FETCH_VAL, var_sym->value_id, FETCH_VAL, m_scope->pushConst(val)));

		m_ir.back().op1_scope = var_sym->scope->getId();
		m_ir.back().op1_scope = m_scope->getId();

	}
}

/// Compiles a set of binary operation
void Compiler::binOp(Opcode op, Node& lhs, Node& rhs, Node& res,
	const location& loc)
{/*
	size_t rhs_id = 0, lhs_id = 0;
	Value* result = new Value();

	Value* val = getValue(lhs, &lhs_id, loc);

	if (!lhs_id) {
		lhs_id = m_value_id++;
		m_value_pool[lhs_id] = val;
	}

	val = getValue(rhs, &rhs_id, loc);

	if (!rhs_id) {
		rhs_id = m_value_id++;
		m_value_pool[rhs_id] = val;
	}

	m_ir.push_back(
		IR(op, FETCH_VAL, lhs_id, FETCH_VAL, rhs_id, result));

	res.type = VALUE;
	res.data.val = result;*/
}

/// Creates a list of arguments
ArgDeclList* Compiler::newArgDeclList(const CString* arg) const
{
	ArgDeclList* arg_list = new ArgDeclList;
	arg_list->push_back(arg);

	return arg_list;
}

/// Starts the function compilation
void Compiler::funcDecl(Node& node, ArgDeclList* arg_list, const location& loc)
{
	Symbol* sym = m_scope->getAny(node.data.str);

	if (sym) {
		errorf(loc, "Name `%S' already in used!", node.data.str);
	}
	// Saves the current instruction size to be used as a index for
	// changing the jmp address to right after the end of function declaration
	m_curr_func = m_ir.size();

	Value* func = new Value();
	Function* funcdata = static_cast<Function*>(CLEVER_FUNC_TYPE->allocData());

	func->setType(CLEVER_FUNC_TYPE);
	func->setObj(funcdata);

	funcdata->setName(*node.data.str);
	funcdata->setUserDefined();
	funcdata->setAddr(m_curr_func + 1);

	m_ir.push_back(IR(OP_JMP, JMP_ADDR, 0));

	// Adds the function symbol to the current scope
	m_scope->pushVar(node.data.str, func);

	// Create a scope for argument list when used
	if (arg_list) {
		ArgDeclList::const_iterator it = arg_list->begin(),
			end = arg_list->end();

		newScope();

		while (it != end) {
			m_scope->pushVar(*it, new Value());
			++it;
		}
		delete arg_list;

		funcdata->setArgVars(m_scope);
	}

	// Creates a scope for the local vars
	newScope();

	funcdata->setLocalVars(m_scope);
}

/// Adds new argument to the call argument list
ArgCallList* Compiler::addArgCall(ArgCallList* arg_list, Node& arg, const location& loc)
{
	Symbol* sym = NULL;
	Value* val = getValue(arg, &sym, loc);

	if (!arg_list) {
		arg_list = new ArgCallList;
	}

	if (sym) {
		arg_list->push_back(std::pair<size_t, size_t>(sym->scope->getId(), sym->value_id));
	} else {
		arg_list->push_back(std::pair<size_t, size_t>(m_scope->getId(), m_scope->pushConst(val)));
	}

	return arg_list;
}

/// Ends the current function compilation
void Compiler::funcEndDecl(bool has_args)
{
	m_ir.push_back(IR(OP_LEAVE));
	// Changes the JMP's addr created right before the func declaration
	// to point to the end of current function, thus skipping its opcodes
	m_ir[m_curr_func].op1 = m_ir.size();

	// Switchs to the global scope again
	if (has_args) {
		endScope();
	}
	endScope();
}

/// Function call compilation
void Compiler::funcCall(Node& name, ArgCallList* arg_list, Node& res,
	const location& loc)
{
	Symbol* sym = m_scope->getAny(name.data.str);

	if (!sym) {
		errorf(loc, "Function `%S' cannot be found!", name.data.str);
	}

	Value* result = new Value();

	if (arg_list) {
		for (size_t i = 0, j = arg_list->size(); i < j; ++i) {
			m_ir.push_back(IR(OP_SEND_VAL, FETCH_VAL, arg_list->at(i).second));

			m_ir.back().op1_scope = arg_list->at(i).first;
		}
	}

	res.type = VALUE;
	res.data.val = result;

	m_ir.push_back(
		IR(OP_FCALL, FETCH_VAL, sym->value_id, result));

	m_ir.back().op1_scope = sym->scope->getId();

	if (arg_list) {
		delete arg_list;
	}
}

/// Compiles a return statement
void Compiler::retStmt(Node* expr, const location& loc)
{
	if (expr) {
		Symbol* sym;
		Value* value = getValue(*expr, &sym, loc);

		if (sym) {
			m_ir.push_back(IR(OP_RET, FETCH_VAL, sym->value_id));
		} else {
			m_ir.push_back(IR(OP_RET, FETCH_VAL, m_scope->pushConst(value)));
		}
	} else {
		m_ir.push_back(IR(OP_RET));
	}
}

void Compiler::importStmt(Node& package)
{
	m_pkg.importPackage(m_scope, package.data.str);
}

void Compiler::importStmt(Node& package, Node& module)
{
	m_pkg.importModule(m_scope, package.data.str, module.data.str);
}

void Compiler::whileLoop(Node& cond, const location& loc)
{/*
	size_t val_id = 0;
	Value* val = getValue(cond, &val_id, loc);

	if (!val_id) {
		val_id = m_value_id;
		m_value_pool[m_value_id++] = val;
	}

	m_jmps.push(std::vector<size_t>());
	m_jmps.top().push_back(m_ir.size());

	m_ir.push_back(IR(OP_JMPZ, FETCH_VAL, val_id, JMP_ADDR, 0));*/
}

void Compiler::endWhileLoop()
{
	m_ir.push_back(IR(OP_JMP, JMP_ADDR, m_jmps.top().at(0)));

	m_ir[m_jmps.top().at(0)].op2 = m_ir.size();
}

/// Creates a new lexical scope
void Compiler::newScope()
{
	m_scope = m_scope->newLexicalScope();
	m_scope->setId(m_scope_id);

	m_scope_pool[m_scope_id++] = m_scope;
}

/// Scope end marker to switch to parent scope
void Compiler::endScope()
{
	m_scope = m_scope->getParent();
}

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

#include "compiler/cstring.h"
#include "compiler/compiler.h"
#include "compiler/scope.h"
#include "compiler/value.h"
#include "interpreter/location.hh"
#include "types/native_types.h"

namespace clever {

// Declaration of namespace global type ptrs for Clever native types
DECLARE_CLEVER_NATIVE_TYPES();

/// Compiler initialization phase
void Compiler::init()
{
	m_scope = new Scope;

	m_ir.reserve(20);
	m_scope_pool.reserve(10);
	m_type_pool.reserve(15);

	m_scope_pool[m_scope_id++] = m_scope;

	// Native type allocation
	m_type_pool[m_type_id++] = CLEVER_INT_TYPE    = new IntType;
	m_type_pool[m_type_id++] = CLEVER_DOUBLE_TYPE = new DoubleType;
	m_type_pool[m_type_id++] = CLEVER_STR_TYPE    = new StrType;
	m_type_pool[m_type_id++] = CLEVER_FUNC_TYPE   = new FuncType;

	m_pkg.init();
}

/// Frees all resource used by the compiler
void Compiler::shutdown()
{
	m_pkg.shutdown();

	CLEVER_SAFE_DELETE(g_cstring_tbl);
	CLEVER_SAFE_DELETE(m_scope);

	TypePool::const_iterator it2 = m_type_pool.begin(),
		end2 = m_type_pool.end();

	while (it2 != end2) {
		delete *it2;
		++it2;
	}
}

// Compiler termination phase
void Compiler::end()
{
}

/// Displays an error message and exits
void Compiler::error(const char* msg) const
{
	std::cerr << "Compile error: " << msg << std::endl;
	CLEVER_EXIT_FATAL();
}

/// Displays an error message
void Compiler::error(const std::string& message, const location& loc) const
{
	if (loc.begin.filename) {
		std::cerr << "Compile error: " << message << " on "
			<< *loc.begin.filename << " line " << loc.begin.line << "\n";
	} else {
		std::cerr << "Compile error: " << message << " on line "
			<< loc.begin.line << "\n";
	}
	CLEVER_EXIT_FATAL();
}

/// Displays a formatted error message and abort the compilation
void Compiler::errorf(const location& loc, const char* format, ...) const
{
	std::ostringstream out;
	va_list args;

	va_start(args, format);

	vsprintf(out, format, args);

	va_end(args);

	error(out.str(), loc);
}

/// Abstracts the Value* ptr gets from Node
// NOTE: When the Node is a STRCONST, it automatically increments the Value's
// refcount related to the Symbol
Value* Compiler::getValue(Node& node, Symbol** symbol, const location& loc) const
{
	if (node.type == VALUE) {
		return node.data.val;
	} else if (node.type == STRCONST) {
		Symbol* sym = m_scope->getAny(node.data.str);

		if (!sym) {
			errorf(loc, "Variable `%S' cannot be found!", node.data.str);
		}
		if (symbol) {
			*symbol = sym;
		}

		return m_scope_pool[sym->scope->getId()]->getVar(sym->value_id);
	}
	return NULL;
}

/// Compiles a variable declaration
void Compiler::varDeclaration(Node& var, Node* node, const location& loc)
{
	Symbol* sym = m_scope->getLocal(var.data.str);

	if (sym) {
		errorf(loc, "Variable `%S' already declared in the scope!", var.data.str);
	}

	size_t sym_id = m_scope->pushVar(var.data.str, new Value());

	// A NULL value is created for uninitialized declaration
	sym = NULL;
	Value* val = node ? getValue(*node, &sym, loc) : new Value();

	// Value to be assigned
	if (sym) {
		m_ir.push_back(
			IR(OP_ASSIGN, FETCH_VAL, sym_id, FETCH_VAL, sym->value_id));

		m_ir.back().op2_scope = sym->scope->getId();
	} else {
		m_ir.push_back(
			IR(OP_ASSIGN, FETCH_VAL, sym_id, FETCH_VAL, m_scope->pushConst(val)));

		m_ir.back().op2_scope = m_scope->getId();
	}
	m_ir.back().op1_scope = m_scope->getId();
}

/// Compiles a variable assignment
void Compiler::assignment(Node& var, Node& value, const location& loc)
{
	Symbol* var_sym = NULL, *val_sym = NULL;
	(void)getValue(var, &var_sym, loc);
	Value* val = getValue(value, &val_sym, loc);

	if (val_sym) {
		m_ir.push_back(
			IR(OP_ASSIGN, FETCH_VAL, var_sym->value_id, FETCH_VAL, val_sym->value_id));

		m_ir.back().op1_scope = var_sym->scope->getId();
		m_ir.back().op2_scope = val_sym->scope->getId();
	} else {
		m_ir.push_back(
			IR(OP_ASSIGN, FETCH_VAL, var_sym->value_id, FETCH_VAL, m_scope->pushConst(val)));

		m_ir.back().op1_scope = var_sym->scope->getId();
		m_ir.back().op1_scope = m_scope->getId();

	}
}

/// Compiles a set of binary operation
void Compiler::binOp(Opcode op, Node& lhs, Node& rhs, Node& res,
	const location& loc)
{/*
	size_t rhs_id = 0, lhs_id = 0;
	Value* result = new Value();

	Value* val = getValue(lhs, &lhs_id, loc);

	if (!lhs_id) {
		lhs_id = m_value_id++;
		m_value_pool[lhs_id] = val;
	}

	val = getValue(rhs, &rhs_id, loc);

	if (!rhs_id) {
		rhs_id = m_value_id++;
		m_value_pool[rhs_id] = val;
	}

	m_ir.push_back(
		IR(op, FETCH_VAL, lhs_id, FETCH_VAL, rhs_id, result));

	res.type = VALUE;
	res.data.val = result;*/
}

/// Creates a list of arguments
ArgDeclList* Compiler::newArgDeclList(const CString* arg) const
{
	ArgDeclList* arg_list = new ArgDeclList;
	arg_list->push_back(arg);

	return arg_list;
}

/// Starts the function compilation
void Compiler::funcDecl(Node& node, ArgDeclList* arg_list, const location& loc)
{
	Symbol* sym = m_scope->getAny(node.data.str);

	if (sym) {
		errorf(loc, "Name `%S' already in used!", node.data.str);
	}
	// Saves the current instruction size to be used as a index for
	// changing the jmp address to right after the end of function declaration
	m_curr_func = m_ir.size();

	Value* func = new Value();
	Function* funcdata = static_cast<Function*>(CLEVER_FUNC_TYPE->allocData());

	func->setType(CLEVER_FUNC_TYPE);
	func->setObj(funcdata);

	funcdata->setName(*node.data.str);
	funcdata->setUserDefined();
	funcdata->setAddr(m_curr_func + 1);

	m_ir.push_back(IR(OP_JMP, JMP_ADDR, 0));

	// Adds the function symbol to the current scope
	m_scope->pushVar(node.data.str, func);

	// Create a scope for argument list when used
	if (arg_list) {
		ArgDeclList::const_iterator it = arg_list->begin(),
			end = arg_list->end();

		newScope();

		while (it != end) {
			m_scope->pushVar(*it, new Value());
			++it;
		}
		delete arg_list;

		funcdata->setArgVars(m_scope);
	}

	// Creates a scope for the local vars
	newScope();

	funcdata->setLocalVars(m_scope);
}

/// Adds new argument to the call argument list
ArgCallList* Compiler::addArgCall(ArgCallList* arg_list, Node& arg, const location& loc)
{
	Symbol* sym = NULL;
	Value* val = getValue(arg, &sym, loc);

	if (!arg_list) {
		arg_list = new ArgCallList;
	}

	if (sym) {
		arg_list->push_back(std::pair<size_t, size_t>(sym->scope->getId(), sym->value_id));
	} else {
		arg_list->push_back(std::pair<size_t, size_t>(m_scope->getId(), m_scope->pushConst(val)));
	}

	return arg_list;
}

/// Ends the current function compilation
void Compiler::funcEndDecl(bool has_args)
{
	m_ir.push_back(IR(OP_LEAVE));
	// Changes the JMP's addr created right before the func declaration
	// to point to the end of current function, thus skipping its opcodes
	m_ir[m_curr_func].op1 = m_ir.size();

	// Switchs to the global scope again
	if (has_args) {
		endScope();
	}
	endScope();
}

/// Function call compilation
void Compiler::funcCall(Node& name, ArgCallList* arg_list, Node& res,
	const location& loc)
{
	Symbol* sym = m_scope->getAny(name.data.str);

	if (!sym) {
		errorf(loc, "Function `%S' cannot be found!", name.data.str);
	}

	Value* result = new Value();

	if (arg_list) {
		for (size_t i = 0, j = arg_list->size(); i < j; ++i) {
			m_ir.push_back(IR(OP_SEND_VAL, FETCH_VAL, arg_list->at(i).second));

			m_ir.back().op1_scope = arg_list->at(i).first;
		}
	}

	res.type = VALUE;
	res.data.val = result;

	m_ir.push_back(
		IR(OP_FCALL, FETCH_VAL, sym->value_id, result));

	m_ir.back().op1_scope = sym->scope->getId();

	if (arg_list) {
		delete arg_list;
	}
}

/// Compiles a return statement
void Compiler::retStmt(Node* expr, const location& loc)
{
	if (expr) {
		Symbol* sym;
		Value* value = getValue(*expr, &sym, loc);

		if (sym) {
			m_ir.push_back(IR(OP_RET, FETCH_VAL, sym->value_id));
		} else {
			m_ir.push_back(IR(OP_RET, FETCH_VAL, m_scope->pushConst(value)));
		}
	} else {
		m_ir.push_back(IR(OP_RET));
	}
}

void Compiler::importStmt(Node& package)
{
	m_pkg.importPackage(m_scope, package.data.str);
}

void Compiler::importStmt(Node& package, Node& module)
{
	m_pkg.importModule(m_scope, package.data.str, module.data.str);
}

void Compiler::whileLoop(Node& cond, const location& loc)
{
	Symbol* sym = NULL;
	Value* val = getValue(cond, &sym, loc);

	m_jmps.push(std::vector<size_t>());
	m_jmps.top().push_back(m_ir.size());

	if (sym) {
		m_ir.push_back(IR(OP_JMPZ, FETCH_VAL, sym->value_id, JMP_ADDR, 0));

		m_ir.back().op1_scope = sym->scope->getId();
	} else {
		m_ir.push_back(IR(OP_JMPZ, FETCH_VAL, m_scope->pushConst(val), JMP_ADDR, 0));
	}
}

void Compiler::endWhileLoop()
{
	m_ir.push_back(IR(OP_JMP, JMP_ADDR, m_jmps.top().at(0)));

	m_ir[m_jmps.top().at(0)].op2 = m_ir.size();
}

/// Creates a new lexical scope
void Compiler::newScope()
{
	m_scope = m_scope->newLexicalScope();
	m_scope->setId(m_scope_id);

	m_scope_pool[m_scope_id++] = m_scope;
}

/// Scope end marker to switch to parent scope
void Compiler::endScope()
{
	m_scope = m_scope->getParent();
}

} // clever
<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * Copyright 2015 Cloudius Systems
 */

#ifndef JSON_ELEMENTS_HH_
#define JSON_ELEMENTS_HH_

#include <string>
#include <vector>
#include <time.h>
#include <sstream>
#include "formatter.hh"
#include "core/sstring.hh"

namespace json {

/**
 * The base class for all json element.
 * Every json element has a name
 * An indication if it was set or not
 * And is this element is mandatory.
 * When a mandatory element is not set
 * this is not a valid object
 */
class json_base_element {
public:
    /**
     * The constructors
     */
    json_base_element()
            : _mandatory(false), _set(false) {
    }

    virtual ~json_base_element() = default;

    /**
     * Check if it's a mandatory parameter
     * and if it's set.
     * @return true if this is not a mandatory parameter
     * or if it is and it's value is set
     */
    virtual bool is_verify() {
        return !(_mandatory && !_set);
    }

    /**
     * returns the internal value in a json format
     * Each inherit class must implement this method
     * @return formated internal value
     */
    virtual std::string to_string() = 0;

    std::string _name;
    bool _mandatory;
    bool _set;
};

/**
 * Basic json element instantiate
 * the json_element template.
 * it adds a value to the base definition
 * and the to_string implementation using the formatter
 */
template<class T>
class json_element : public json_base_element {
public:

    /**
     * the assignment operator also set
     * the set value to true.
     * @param new_value the new value
     * @return the value itself
     */
    json_element &operator=(const T& new_value) {
        _value = new_value;
        _set = true;
        return *this;
    }
    /**
     * the assignment operator also set
     * the set value to true.
     * @param new_value the new value
     * @return the value itself
     */
    template<class C>
    json_element &operator=(const C& new_value) {
        _value = new_value;
        _set = true;
        return *this;
    }
    /**
     * The brackets operator
     * @return the value
     */
    const T& operator()() const {
        return _value;
    }

    /**
     * The to_string return the value
     * formated as a json value
     * @return the value foramted for json
     */
    virtual std::string to_string() override
    {
        return formatter::to_json(_value);
    }

private:
    T _value;
};

/**
 * json_list is based on std vector implementation.
 *
 * When values are added with push it is set the "set" flag to true
 * hence will be included in the parsed object
 */
template<class T>
class json_list : public json_base_element {
public:

    /**
     * Add an element to the list.
     * @param element a new element that will be added to the list
     */
    void push(const T& element) {
        _set = true;
        _elements.push_back(element);
    }

    virtual std::string to_string() override
    {
        return formatter::to_json(_elements);
    }

    /**
     * Assignment can be done from any object that support const range
     * iteration and that it's elements can be assigned to the list elements
     */
    template<class C>
    json_list& operator=(const C& list) {
        _elements.clear();
        for  (auto i : list) {
            push(i);
        }
        return *this;
    }

    std::vector<T> _elements;
};

class jsonable {
public:
    virtual ~jsonable() = default;
    /**
     * create a foramted string of the object.
     * @return the object formated.
     */
    virtual std::string to_json() const = 0;
};

/**
 * The base class for all json objects
 * It holds a list of all the element in it,
 * allowing it implement the to_json method.
 *
 * It also allows iterating over the element
 * in the object, even if not all the member
 * are known in advance and in practice mimic
 * reflection
 */
struct json_base : public jsonable {

    virtual ~json_base() = default;

    json_base() = default;

    json_base(const json_base&) = delete;

    json_base operator=(const json_base&) = delete;

    /**
     * create a foramted string of the object.
     * @return the object formated.
     */
    virtual std::string to_json() const;

    /**
     * Check that all mandatory elements are set
     * @return true if all mandatory parameters are set
     */
    virtual bool is_verify() const;

    /**
     * Register an element in an object
     * @param element the element to be added
     * @param name the element name
     * @param mandatory is this element mandatory.
     */
    virtual void add(json_base_element* element, std::string name,
            bool mandatory = false);

    std::vector<json_base_element*> _elements;
};

/**
 * The json return type, is a helper class to return a json
 * formatted string.
 * It uses autoboxing in its constructor so when a function return
 * type is json_return_type, it could return a type that would be converted
 * ie.
 * json_return_type foo() {
 *     return "hello";
 * }
 *
 * would return a json formatted string: "hello" (rather then hello)
 */
struct json_return_type {
    sstring _res;
    template<class T>
    json_return_type(const T& res) {
        _res = formatter::to_json(res);
    }
};

}

#endif /* JSON_ELEMENTS_HH_ */
<commit_msg>Adding a void_json object to the json_elements<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * Copyright 2015 Cloudius Systems
 */

#ifndef JSON_ELEMENTS_HH_
#define JSON_ELEMENTS_HH_

#include <string>
#include <vector>
#include <time.h>
#include <sstream>
#include "formatter.hh"
#include "core/sstring.hh"

namespace json {

/**
 * The base class for all json element.
 * Every json element has a name
 * An indication if it was set or not
 * And is this element is mandatory.
 * When a mandatory element is not set
 * this is not a valid object
 */
class json_base_element {
public:
    /**
     * The constructors
     */
    json_base_element()
            : _mandatory(false), _set(false) {
    }

    virtual ~json_base_element() = default;

    /**
     * Check if it's a mandatory parameter
     * and if it's set.
     * @return true if this is not a mandatory parameter
     * or if it is and it's value is set
     */
    virtual bool is_verify() {
        return !(_mandatory && !_set);
    }

    /**
     * returns the internal value in a json format
     * Each inherit class must implement this method
     * @return formated internal value
     */
    virtual std::string to_string() = 0;

    std::string _name;
    bool _mandatory;
    bool _set;
};

/**
 * Basic json element instantiate
 * the json_element template.
 * it adds a value to the base definition
 * and the to_string implementation using the formatter
 */
template<class T>
class json_element : public json_base_element {
public:

    /**
     * the assignment operator also set
     * the set value to true.
     * @param new_value the new value
     * @return the value itself
     */
    json_element &operator=(const T& new_value) {
        _value = new_value;
        _set = true;
        return *this;
    }
    /**
     * the assignment operator also set
     * the set value to true.
     * @param new_value the new value
     * @return the value itself
     */
    template<class C>
    json_element &operator=(const C& new_value) {
        _value = new_value;
        _set = true;
        return *this;
    }
    /**
     * The brackets operator
     * @return the value
     */
    const T& operator()() const {
        return _value;
    }

    /**
     * The to_string return the value
     * formated as a json value
     * @return the value foramted for json
     */
    virtual std::string to_string() override
    {
        return formatter::to_json(_value);
    }

private:
    T _value;
};

/**
 * json_list is based on std vector implementation.
 *
 * When values are added with push it is set the "set" flag to true
 * hence will be included in the parsed object
 */
template<class T>
class json_list : public json_base_element {
public:

    /**
     * Add an element to the list.
     * @param element a new element that will be added to the list
     */
    void push(const T& element) {
        _set = true;
        _elements.push_back(element);
    }

    virtual std::string to_string() override
    {
        return formatter::to_json(_elements);
    }

    /**
     * Assignment can be done from any object that support const range
     * iteration and that it's elements can be assigned to the list elements
     */
    template<class C>
    json_list& operator=(const C& list) {
        _elements.clear();
        for  (auto i : list) {
            push(i);
        }
        return *this;
    }

    std::vector<T> _elements;
};

class jsonable {
public:
    virtual ~jsonable() = default;
    /**
     * create a foramted string of the object.
     * @return the object formated.
     */
    virtual std::string to_json() const = 0;
};

/**
 * The base class for all json objects
 * It holds a list of all the element in it,
 * allowing it implement the to_json method.
 *
 * It also allows iterating over the element
 * in the object, even if not all the member
 * are known in advance and in practice mimic
 * reflection
 */
struct json_base : public jsonable {

    virtual ~json_base() = default;

    json_base() = default;

    json_base(const json_base&) = delete;

    json_base operator=(const json_base&) = delete;

    /**
     * create a foramted string of the object.
     * @return the object formated.
     */
    virtual std::string to_json() const;

    /**
     * Check that all mandatory elements are set
     * @return true if all mandatory parameters are set
     */
    virtual bool is_verify() const;

    /**
     * Register an element in an object
     * @param element the element to be added
     * @param name the element name
     * @param mandatory is this element mandatory.
     */
    virtual void add(json_base_element* element, std::string name,
            bool mandatory = false);

    std::vector<json_base_element*> _elements;
};

/**
 * There are cases where a json request needs to return a successful
 * empty reply.
 * The json_void class will be used to mark that the reply should be empty.
 *
 */
struct json_void : public jsonable{
    virtual std::string to_json() const {
        return "";
    }
};

/**
 * The json return type, is a helper class to return a json
 * formatted string.
 * It uses autoboxing in its constructor so when a function return
 * type is json_return_type, it could return a type that would be converted
 * ie.
 * json_return_type foo() {
 *     return "hello";
 * }
 *
 * would return a json formatted string: "hello" (rather then hello)
 */
struct json_return_type {
    sstring _res;
    template<class T>
    json_return_type(const T& res) {
        _res = formatter::to_json(res);
    }
};

}

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


<commit_before>/*
 *  traywindow.cpp  -  the KDE system tray applet
 *  Program:  kalarm
 *  (C) 2002, 2003 by David Jarvie <software@astrojar.org.uk>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *  As a special exception, permission is given to link this program
 *  with any edition of Qt, and distribute the resulting executable,
 *  without including the source code for Qt in the source distribution.
 */
#include "kalarm.h"
#include <stdlib.h>

#include <qtooltip.h>
#include <qlabel.h>

#include <kapplication.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kstdaction.h>
#include <kaboutdata.h>
#include <kpopupmenu.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kstdguiitem.h>
#include <kconfig.h>
#include <kdebug.h>

#include "kalarmapp.h"
#include "mainwindow.h"
#include "messagewin.h"
#include "alarmcalendar.h"
#include "alarmlistview.h"
#include "daemongui.h"
#include "preferences.h"
#include "traywindow.moc"

class TrayTooltip : public QToolTip
{
	public:
		TrayTooltip(QWidget* parent) : QToolTip(parent) { }
	protected:
		virtual void maybeTip(const QPoint&);
};

/*=============================================================================
= Class: TrayWindow
= The KDE system tray window.
=============================================================================*/
const QString TrayWindow::QUIT_WARN = QString::fromLatin1("QuitWarn");

TrayWindow::TrayWindow(KAlarmMainWindow* parent, const char* name)
	: KSystemTray((theApp()->wantRunInSystemTray() ? parent : 0), name),
	  mAssocMainWindow(parent)
#if KDE_VERSION < 310
	  , mActionCollection(new KActionCollection(this)),
	  mQuitReplaced(false)
#endif
{
	kdDebug(5950) << "TrayWindow::TrayWindow()\n";
	// Set up GUI icons
	mPixmapEnabled  = BarIcon("kalarm");
	mPixmapDisabled = BarIcon("kalarm_disabled");
	if (mPixmapEnabled.isNull() || mPixmapDisabled.isNull())
		KMessageBox::sorry(this, i18n("Can't load system tray icon!"),
		                         i18n("%1 Error").arg(kapp->aboutData()->programName()));
	setAcceptDrops(true);         // allow drag-and-drop onto this window

#if KDE_VERSION >= 310
	KAction* quit = actionCollection()->action(KStdAction::stdName(KStdAction::Quit));
	actionCollection()->remove(quit);
	mActionQuit = KStdAction::quit(this, SLOT(slotQuit()), actionCollection());
	actionCollection()->insert(mActionQuit);
#else
	mActionQuit = KStdAction::quit(this, SLOT(slotQuit()), mActionCollection);
#endif

	// Set up the context menu
	ActionAlarmsEnabled* a = theApp()->actionAlarmEnable();
	mAlarmsEnabledId = a->itemId(a->plug(contextMenu()));
	connect(a, SIGNAL(alarmsEnabledChange(bool)), this, SLOT(setEnabledStatus(bool)));
	theApp()->actionNewAlarm()->plug(contextMenu());
	theApp()->actionPreferences()->plug(contextMenu());
	theApp()->actionDaemonControl()->plug(contextMenu());

	// Set icon to correspond with the alarms enabled menu status
	DaemonGuiHandler* daemonGui = theApp()->daemonGuiHandler();
	daemonGui->checkStatus();
	setEnabledStatus(daemonGui->monitoringAlarms());

	mTooltip = new TrayTooltip(this);
}

TrayWindow::~TrayWindow()
{
	kdDebug(5950) << "TrayWindow::~TrayWindow()\n";
	delete mTooltip;
	mTooltip = 0;
	theApp()->removeWindow(this);
	emit deleted();
}

/******************************************************************************
* Called just before the context menu is displayed.
* Modify the Quit context menu item to only close the system tray widget.
*/
void TrayWindow::contextMenuAboutToShow(KPopupMenu* menu)
{
#if KDE_VERSION < 310
	if (!mQuitReplaced)
	{
		// Prevent Quit from quitting the program
		QString quitText = mActionQuit->text();
		for (unsigned n = 0;  n < menu->count();  ++n)
		{
			QString txt = menu->text(menu->idAt(n));
			if (txt.startsWith(quitText))
			{
				menu->removeItemAt(n);
				break;
			}
		}
		mActionQuit->plug(menu);
		mQuitReplaced = true;
	}
#endif

	// Update the Alarms Enabled item status
	theApp()->daemonGuiHandler()->checkStatus();
}

/******************************************************************************
* Called when the Quit context menu item is selected.
* Closes the system tray window, and if in 'run in system tray' mode closes all
* main windows, but does not exit the program if other windows are still open.
*/
void TrayWindow::slotQuit()
{
	kdDebug(5950)<<"TrayWindow::slotQuit()\n";
	if (theApp()->alarmsDisabledIfStopped()
#if KDE_VERSION < 290
	&&  Preferences::notifying(QUIT_WARN)
#endif
	&&  KMessageBox::warningYesNo(this, i18n("Quitting will disable alarms\n"
	                                         "(once any alarm message windows are closed)."),
	                              QString::null, mActionQuit->text(), KStdGuiItem::cancel(),
	                              QUIT_WARN
	                             ) != KMessageBox::Yes)
		return;
	if (theApp()->wantRunInSystemTray())
	{
		if (!MessageWin::instanceCount())
			theApp()->quit();
		else
			KAlarmMainWindow::closeAll();
	}
	theApp()->displayTrayIcon(false);
}

/******************************************************************************
* Called when the Alarms Enabled action status has changed.
* Updates the alarms enabled menu item check state, and the icon pixmap.
*/
void TrayWindow::setEnabledStatus(bool status)
{
	kdDebug(5950)<<"TrayWindow::setEnabledStatus(" << (int)status << ")\n";
	setPixmap(status ? mPixmapEnabled : mPixmapDisabled);
	contextMenu()->setItemChecked(mAlarmsEnabledId, status);
}

/******************************************************************************
*  Called when the mouse is clicked over the panel icon.
*  A left click displays the KAlarm main window.
*/
void TrayWindow::mousePressEvent(QMouseEvent* e)
{
	if (e->button() == LeftButton  &&  !theApp()->wantRunInSystemTray())
	{
		// Left click: display/hide the first main window
		mAssocMainWindow = KAlarmMainWindow::toggleWindow(mAssocMainWindow);
	}
	else
		KSystemTray::mousePressEvent(e);
}

/******************************************************************************
*  Called when the mouse is released over the panel icon.
*  The main window (if not hidden) is raised and made the active window.
*  If this is done in mousePressEvent(), it doesn't work.
*/
void TrayWindow::mouseReleaseEvent(QMouseEvent* e)
{
	if (e->button() == LeftButton  &&  mAssocMainWindow  &&  mAssocMainWindow->isVisible())
	{
		mAssocMainWindow->raise();
		mAssocMainWindow->setActiveWindow();
	}
	else
		KSystemTray::mouseReleaseEvent(e);
}

/******************************************************************************
*  Called when the drag cursor enters the panel icon.
*/
void TrayWindow::dragEnterEvent(QDragEnterEvent* e)
{
	KAlarmMainWindow::executeDragEnterEvent(e);
}

/******************************************************************************
*  Called when an object is dropped on the panel icon.
*  If the object is recognised, the edit alarm dialog is opened appropriately.
*/
void TrayWindow::dropEvent(QDropEvent* e)
{
	KAlarmMainWindow::executeDropEvent(0, e);
}

/******************************************************************************
*  Return the tooltip text showing alarms due in the next 24 hours.
*  The limit of 24 hours is because only times, not dates, are displayed.
*/
QString TrayWindow::tooltipAlarmText() const
{
	QString text = kapp->aboutData()->programName();
	KAlarmEvent event;
	Preferences* preferences = theApp()->preferences();
	const QString& prefix = preferences->tooltipTimeToPrefix();
	int maxCount = preferences->tooltipAlarmCount();
	QDateTime now = QDateTime::currentDateTime();

	// Get today's and tomorrow's alarms, sorted in time order
	KCal::Event::List events = theApp()->getCalendar().events(now.date(), true);
	KCal::Event::List events2 = theApp()->getCalendar().events(now.date().addDays(1), true);

	int count = 0;
	bool todayEvents = true;
	KCal::Event::List::ConstIterator it1 = events.begin();
	KCal::Event::List::ConstIterator it2 = events2.begin();
        KCal::Event *kcalEvent;
	if (it1 == events.end())
	{
		todayEvents = false;
		kcalEvent = events2.first();
	}
	else
                kcalEvent = *it1;
	while (kcalEvent  &&  count != maxCount)
	{
		event.set(*kcalEvent);
		if (!event.expired()  &&  event.action() == KAlarmEvent::MESSAGE)
		{
			DateTime dateTime = event.nextDateTime();
			if (dateTime.date() != now.date())
			{
				// Ignore tomorrow's alarms after the current time
				if (dateTime.time() >= now.time())
					break;
			}

			// The alarm is due today, or early tomorrow
			text += "\n";
			bool space = false;
			if (preferences->showTooltipAlarmTime())
			{
				text += KGlobal::locale()->formatTime(dateTime.time());
				text += ' ';
				space = true;
			}
			if (preferences->showTooltipTimeToAlarm())
			{
				int mins = (now.secsTo(dateTime.dateTime()) + 59) / 60;
				if (mins < 0)
					mins = 0;
				char minutes[3] = "00";
				minutes[0] = (mins%60) / 10 + '0';
				minutes[1] = (mins%60) % 10 + '0';
				if (preferences->showTooltipAlarmTime())
					text += i18n("prefix + hours:minutes", "(%1%2:%3)").arg(prefix).arg(mins/60).arg(minutes);
				else
					text += i18n("prefix + hours:minutes", "%1%2:%3").arg(prefix).arg(mins/60).arg(minutes);
				text += ' ';
				space = true;
			}
			if (space)
				text += ' ';
			text += AlarmListViewItem::alarmText(event);
			++count;
		}

		// Get the next event
		if (todayEvents)
		{
			++it1;
			if (it1 == events.end())
				todayEvents = false;
			else
				kcalEvent = *it1;
		}
		else
			++it2;
		if (!todayEvents)
                {
			if (it2 == events2.end())
				kcalEvent = 0;
			else
				kcalEvent = *it2;
	        }
        }
	return text;
}

/******************************************************************************
* Called when the associated main window is closed.
*/
void TrayWindow::removeWindow(KAlarmMainWindow* win)
{
	if (win == mAssocMainWindow)
		mAssocMainWindow = 0;
}

#ifdef HAVE_X11_HEADERS
	#include <X11/X.h>
	#include <X11/Xlib.h>
	#include <X11/Xutil.h>
#endif

/******************************************************************************
* Check whether the widget is in the system tray.
* Note that it is only sometime AFTER the show event that the system tray
* becomes the widget's parent. So for a definitive status, call this method
* only after waiting a bit...
* Reply = true if the widget is in the system tray, or its status can't be determined.
*       = false if it is not currently in the system tray.
*/
bool TrayWindow::inSystemTray() const
{
#ifdef HAVE_X11_HEADERS
	Window  xParent;    // receives parent window
	Window  root;
	Window* children = 0;
	unsigned int nchildren;
	// Find the X parent window of the widget. This is not the same as the Qt parent widget.
	if (!XQueryTree(qt_xdisplay(), winId(), &root, &xParent, &children, &nchildren))
		return true;    // error determining its parent X window
	if (children)
		XFree(children);

	// If it is in the system tray, the system tray window will be its X parent.
	// Otherwise, the root window will be its X parent.
	return xParent != root;
#else
	return true;
#endif // HAVE_X11_HEADERS
}

/******************************************************************************
*  Displays the appropriate tooltip depending on preference settings.
*/
void TrayTooltip::maybeTip(const QPoint&)
{
	TrayWindow* parent = (TrayWindow*)parentWidget();
	if (theApp()->preferences()->tooltipAlarmCount())
		tip(parent->rect(), parent->tooltipAlarmText());
	else
		tip(parent->rect(), kapp->aboutData()->programName());
}
<commit_msg>Fix crash when tooltip is shown with no alarms<commit_after>/*
 *  traywindow.cpp  -  the KDE system tray applet
 *  Program:  kalarm
 *  (C) 2002, 2003 by David Jarvie <software@astrojar.org.uk>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *  As a special exception, permission is given to link this program
 *  with any edition of Qt, and distribute the resulting executable,
 *  without including the source code for Qt in the source distribution.
 */
#include "kalarm.h"
#include <stdlib.h>

#include <qtooltip.h>
#include <qlabel.h>

#include <kapplication.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kstdaction.h>
#include <kaboutdata.h>
#include <kpopupmenu.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kstdguiitem.h>
#include <kconfig.h>
#include <kdebug.h>

#include "kalarmapp.h"
#include "mainwindow.h"
#include "messagewin.h"
#include "alarmcalendar.h"
#include "alarmlistview.h"
#include "daemongui.h"
#include "preferences.h"
#include "traywindow.moc"

class TrayTooltip : public QToolTip
{
	public:
		TrayTooltip(QWidget* parent) : QToolTip(parent) { }
	protected:
		virtual void maybeTip(const QPoint&);
};

/*=============================================================================
= Class: TrayWindow
= The KDE system tray window.
=============================================================================*/
const QString TrayWindow::QUIT_WARN = QString::fromLatin1("QuitWarn");

TrayWindow::TrayWindow(KAlarmMainWindow* parent, const char* name)
	: KSystemTray((theApp()->wantRunInSystemTray() ? parent : 0), name),
	  mAssocMainWindow(parent)
#if KDE_VERSION < 310
	  , mActionCollection(new KActionCollection(this)),
	  mQuitReplaced(false)
#endif
{
	kdDebug(5950) << "TrayWindow::TrayWindow()\n";
	// Set up GUI icons
	mPixmapEnabled  = BarIcon("kalarm");
	mPixmapDisabled = BarIcon("kalarm_disabled");
	if (mPixmapEnabled.isNull() || mPixmapDisabled.isNull())
		KMessageBox::sorry(this, i18n("Can't load system tray icon!"),
		                         i18n("%1 Error").arg(kapp->aboutData()->programName()));
	setAcceptDrops(true);         // allow drag-and-drop onto this window

#if KDE_VERSION >= 310
	KAction* quit = actionCollection()->action(KStdAction::stdName(KStdAction::Quit));
	actionCollection()->remove(quit);
	mActionQuit = KStdAction::quit(this, SLOT(slotQuit()), actionCollection());
	actionCollection()->insert(mActionQuit);
#else
	mActionQuit = KStdAction::quit(this, SLOT(slotQuit()), mActionCollection);
#endif

	// Set up the context menu
	ActionAlarmsEnabled* a = theApp()->actionAlarmEnable();
	mAlarmsEnabledId = a->itemId(a->plug(contextMenu()));
	connect(a, SIGNAL(alarmsEnabledChange(bool)), this, SLOT(setEnabledStatus(bool)));
	theApp()->actionNewAlarm()->plug(contextMenu());
	theApp()->actionPreferences()->plug(contextMenu());
	theApp()->actionDaemonControl()->plug(contextMenu());

	// Set icon to correspond with the alarms enabled menu status
	DaemonGuiHandler* daemonGui = theApp()->daemonGuiHandler();
	daemonGui->checkStatus();
	setEnabledStatus(daemonGui->monitoringAlarms());

	mTooltip = new TrayTooltip(this);
}

TrayWindow::~TrayWindow()
{
	kdDebug(5950) << "TrayWindow::~TrayWindow()\n";
	delete mTooltip;
	mTooltip = 0;
	theApp()->removeWindow(this);
	emit deleted();
}

/******************************************************************************
* Called just before the context menu is displayed.
* Modify the Quit context menu item to only close the system tray widget.
*/
void TrayWindow::contextMenuAboutToShow(KPopupMenu* menu)
{
#if KDE_VERSION < 310
	if (!mQuitReplaced)
	{
		// Prevent Quit from quitting the program
		QString quitText = mActionQuit->text();
		for (unsigned n = 0;  n < menu->count();  ++n)
		{
			QString txt = menu->text(menu->idAt(n));
			if (txt.startsWith(quitText))
			{
				menu->removeItemAt(n);
				break;
			}
		}
		mActionQuit->plug(menu);
		mQuitReplaced = true;
	}
#endif

	// Update the Alarms Enabled item status
	theApp()->daemonGuiHandler()->checkStatus();
}

/******************************************************************************
* Called when the Quit context menu item is selected.
* Closes the system tray window, and if in 'run in system tray' mode closes all
* main windows, but does not exit the program if other windows are still open.
*/
void TrayWindow::slotQuit()
{
	kdDebug(5950)<<"TrayWindow::slotQuit()\n";
	if (theApp()->alarmsDisabledIfStopped()
#if KDE_VERSION < 290
	&&  Preferences::notifying(QUIT_WARN)
#endif
	&&  KMessageBox::warningYesNo(this, i18n("Quitting will disable alarms\n"
	                                         "(once any alarm message windows are closed)."),
	                              QString::null, mActionQuit->text(), KStdGuiItem::cancel(),
	                              QUIT_WARN
	                             ) != KMessageBox::Yes)
		return;
	if (theApp()->wantRunInSystemTray())
	{
		if (!MessageWin::instanceCount())
			theApp()->quit();
		else
			KAlarmMainWindow::closeAll();
	}
	theApp()->displayTrayIcon(false);
}

/******************************************************************************
* Called when the Alarms Enabled action status has changed.
* Updates the alarms enabled menu item check state, and the icon pixmap.
*/
void TrayWindow::setEnabledStatus(bool status)
{
	kdDebug(5950)<<"TrayWindow::setEnabledStatus(" << (int)status << ")\n";
	setPixmap(status ? mPixmapEnabled : mPixmapDisabled);
	contextMenu()->setItemChecked(mAlarmsEnabledId, status);
}

/******************************************************************************
*  Called when the mouse is clicked over the panel icon.
*  A left click displays the KAlarm main window.
*/
void TrayWindow::mousePressEvent(QMouseEvent* e)
{
	if (e->button() == LeftButton  &&  !theApp()->wantRunInSystemTray())
	{
		// Left click: display/hide the first main window
		mAssocMainWindow = KAlarmMainWindow::toggleWindow(mAssocMainWindow);
	}
	else
		KSystemTray::mousePressEvent(e);
}

/******************************************************************************
*  Called when the mouse is released over the panel icon.
*  The main window (if not hidden) is raised and made the active window.
*  If this is done in mousePressEvent(), it doesn't work.
*/
void TrayWindow::mouseReleaseEvent(QMouseEvent* e)
{
	if (e->button() == LeftButton  &&  mAssocMainWindow  &&  mAssocMainWindow->isVisible())
	{
		mAssocMainWindow->raise();
		mAssocMainWindow->setActiveWindow();
	}
	else
		KSystemTray::mouseReleaseEvent(e);
}

/******************************************************************************
*  Called when the drag cursor enters the panel icon.
*/
void TrayWindow::dragEnterEvent(QDragEnterEvent* e)
{
	KAlarmMainWindow::executeDragEnterEvent(e);
}

/******************************************************************************
*  Called when an object is dropped on the panel icon.
*  If the object is recognised, the edit alarm dialog is opened appropriately.
*/
void TrayWindow::dropEvent(QDropEvent* e)
{
	KAlarmMainWindow::executeDropEvent(0, e);
}

/******************************************************************************
*  Return the tooltip text showing alarms due in the next 24 hours.
*  The limit of 24 hours is because only times, not dates, are displayed.
*/
QString TrayWindow::tooltipAlarmText() const
{
	QString text = kapp->aboutData()->programName();
	KAlarmEvent event;
	Preferences* preferences = theApp()->preferences();
	const QString& prefix = preferences->tooltipTimeToPrefix();
	int maxCount = preferences->tooltipAlarmCount();
	QDateTime now = QDateTime::currentDateTime();

	// Get today's and tomorrow's alarms, sorted in time order
	KCal::Event::List events = theApp()->getCalendar().events(now.date(), true);
	KCal::Event::List events2 = theApp()->getCalendar().events(now.date().addDays(1), true);

	int count = 0;
	bool todayEvents = true;
	KCal::Event::List::ConstIterator it1 = events.begin();
	KCal::Event::List::ConstIterator it2 = events2.begin();
        KCal::Event *kcalEvent;
	if (it1 == events.end())
	{
		todayEvents = false;
		kcalEvent = (it2 == events2.end()) ? 0 : *it2;
	}
	else
                kcalEvent = *it1;
	while (kcalEvent  &&  count != maxCount)
	{
		event.set(*kcalEvent);
		if (!event.expired()  &&  event.action() == KAlarmEvent::MESSAGE)
		{
			DateTime dateTime = event.nextDateTime();
			if (dateTime.date() != now.date())
			{
				// Ignore tomorrow's alarms after the current time
				if (dateTime.time() >= now.time())
					break;
			}

			// The alarm is due today, or early tomorrow
			text += "\n";
			bool space = false;
			if (preferences->showTooltipAlarmTime())
			{
				text += KGlobal::locale()->formatTime(dateTime.time());
				text += ' ';
				space = true;
			}
			if (preferences->showTooltipTimeToAlarm())
			{
				int mins = (now.secsTo(dateTime.dateTime()) + 59) / 60;
				if (mins < 0)
					mins = 0;
				char minutes[3] = "00";
				minutes[0] = (mins%60) / 10 + '0';
				minutes[1] = (mins%60) % 10 + '0';
				if (preferences->showTooltipAlarmTime())
					text += i18n("prefix + hours:minutes", "(%1%2:%3)").arg(prefix).arg(mins/60).arg(minutes);
				else
					text += i18n("prefix + hours:minutes", "%1%2:%3").arg(prefix).arg(mins/60).arg(minutes);
				text += ' ';
				space = true;
			}
			if (space)
				text += ' ';
			text += AlarmListViewItem::alarmText(event);
			++count;
		}

		// Get the next event
		if (todayEvents)
		{
			++it1;
			if (it1 == events.end())
				todayEvents = false;
			else
				kcalEvent = *it1;
		}
		else
			++it2;
		if (!todayEvents)
                {
			if (it2 == events2.end())
				kcalEvent = 0;
			else
				kcalEvent = *it2;
	        }
        }
	return text;
}

/******************************************************************************
* Called when the associated main window is closed.
*/
void TrayWindow::removeWindow(KAlarmMainWindow* win)
{
	if (win == mAssocMainWindow)
		mAssocMainWindow = 0;
}

#ifdef HAVE_X11_HEADERS
	#include <X11/X.h>
	#include <X11/Xlib.h>
	#include <X11/Xutil.h>
#endif

/******************************************************************************
* Check whether the widget is in the system tray.
* Note that it is only sometime AFTER the show event that the system tray
* becomes the widget's parent. So for a definitive status, call this method
* only after waiting a bit...
* Reply = true if the widget is in the system tray, or its status can't be determined.
*       = false if it is not currently in the system tray.
*/
bool TrayWindow::inSystemTray() const
{
#ifdef HAVE_X11_HEADERS
	Window  xParent;    // receives parent window
	Window  root;
	Window* children = 0;
	unsigned int nchildren;
	// Find the X parent window of the widget. This is not the same as the Qt parent widget.
	if (!XQueryTree(qt_xdisplay(), winId(), &root, &xParent, &children, &nchildren))
		return true;    // error determining its parent X window
	if (children)
		XFree(children);

	// If it is in the system tray, the system tray window will be its X parent.
	// Otherwise, the root window will be its X parent.
	return xParent != root;
#else
	return true;
#endif // HAVE_X11_HEADERS
}

/******************************************************************************
*  Displays the appropriate tooltip depending on preference settings.
*/
void TrayTooltip::maybeTip(const QPoint&)
{
	TrayWindow* parent = (TrayWindow*)parentWidget();
	if (theApp()->preferences()->tooltipAlarmCount())
		tip(parent->rect(), parent->tooltipAlarmText());
	else
		tip(parent->rect(), kapp->aboutData()->programName());
}
<|endoftext|>


<commit_before>// Standard includes
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cmath>
#include <string.h>
#include <inttypes.h>
#include <fstream>

// Serial includes
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#
#ifdef __linux
#include <sys/ioctl.h>
#endif

#include "serialwifly.h" 	// this is from Louis' wifly code, which will be a library
#include "common.h"
#include "wifly_thread.h"
#include "test.h" 			// for bearing calculation
#include "commander.h"

using std::string;
using std::vector;
using namespace std;

/* this is to help with some of the rotation logic */
bool in_rotation = false;

int wifly_connect(char *port) {

	/* Start the connection to the WiFly */
	/* If the connection does not exist, quit */
	/* This is assuming we want to connect to /dev/ttyUSB0 */
	/* TODO: Don't make that assumption */
	int fd = start_connection(port);
	if (fd < 0)
	{
		// TODO: figure out what we do want to return when there is an error
		printf("Error connecting to wifly. Exiting...\n");
		return 0;
	}

	return fd;
}

void *wifly_thread(void *param) {

	// retrieve the MAVInfo struct that is sent to this function as a parameter
	struct MAVInfo *uavData = (struct MAVInfo *)param;

	// some constants that all need to become parameters
	int num_samples = 1;
	char *ssid = (char *) "JAMMER01";
	char *file_name = (char *) "wifly.csv";
	char *bearing_file_name = (char *) "bearing_calc.csv";
	char *port = (char *) "/dev/ttyUSB0";

	// connect to the wifly
	int wifly_fd = wifly_connect(port);

	if (wifly_fd < 0) {
		printf("Error opening wifly connection\n");
		return NULL;
	}

	/* Go into command mode */
	commandmode(wifly_fd);

	/* Open a file to write values to */
	/* Appending values */
	FILE *wifly_file = fopen(file_name, "a");
	if (wifly_file == NULL)
	{
		// TODO: figure out what we do want to return when there is an error
		printf("Error opening wifly output file\n");
		return NULL;
	}

	/* Open a file to write bearing calcs to */
	FILE *bearing_file = fopen(bearing_file_name, "a");
	if (bearing_file == NULL)
	{
		// TODO: figure out what we do want to return when there is an error
		printf("Error opening bearing output file\n");
		return NULL;
	}

	vector<double> angles;
	vector<double> gains;

	// main loop that should be constantly taking measurements
	// until the main program is stopped
	while (RUNNING_FLAG) {

		/* check if we are in an official rotation */
		if (rotating) {
			if (!in_rotation) {
				// set our logic to mark we are now running the rotation logic
				in_rotation = true;

				// clear the vectors
				angles.clear();
				gains.clear();
			}

			angles.push_back((double) uavData->vfr_hud.heading);
			gains.push_back(scanrssi(wifly_fd, ssid));

		}

		if (!rotating && in_rotation) {
			in_rotation = false;

			// do bearing calculation at this point
			double bearing = get_bearing(angles, gains);

			// write the lat, lon, alt and bearing to file
			fprintf(bearing_file, "%i,%i,%f,%f\n", uavData->gps_position.lat, uavData->gps_position.lon, uavData->vfr_hud.alt, bearing);

			// send a mavlink message of the calculated bearing
			send_bearing_message(bearing, uavData->gps_position.lat, uavData->gps_position.lon, uavData->vfr_hud.alt);
		}

		/* Scan values to this file */
		/* Add degree at which you measure first */
		cout << uavData->vfr_hud.heading << " ";
		fprintf(wifly_file, "%ui,%i,%i,%i,%f,", uavData->custom_mode, uavData->vfr_hud.heading, uavData->gps_position.lat, uavData->gps_position.lon, uavData->vfr_hud.alt);
		scanrssi_f(wifly_fd, ssid, wifly_file, num_samples);

		// TODO: send mavlink message of calculated rssi...

		/* sleep for some time before making another measurement (30 ms for now) */
		usleep(30000);

	}

	/* Be sure to close the output file and connection */
	fclose(wifly_file);
	close(wifly_fd);

	return NULL;
}
<commit_msg>fix typo in logging<commit_after>// Standard includes
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cmath>
#include <string.h>
#include <inttypes.h>
#include <fstream>

// Serial includes
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#
#ifdef __linux
#include <sys/ioctl.h>
#endif

#include "serialwifly.h" 	// this is from Louis' wifly code, which will be a library
#include "common.h"
#include "wifly_thread.h"
#include "test.h" 			// for bearing calculation
#include "commander.h"

using std::string;
using std::vector;
using namespace std;

/* this is to help with some of the rotation logic */
bool in_rotation = false;

int wifly_connect(char *port) {

	/* Start the connection to the WiFly */
	/* If the connection does not exist, quit */
	/* This is assuming we want to connect to /dev/ttyUSB0 */
	/* TODO: Don't make that assumption */
	int fd = start_connection(port);
	if (fd < 0)
	{
		// TODO: figure out what we do want to return when there is an error
		printf("Error connecting to wifly. Exiting...\n");
		return 0;
	}

	return fd;
}

void *wifly_thread(void *param) {

	// retrieve the MAVInfo struct that is sent to this function as a parameter
	struct MAVInfo *uavData = (struct MAVInfo *)param;

	// some constants that all need to become parameters
	int num_samples = 1;
	char *ssid = (char *) "JAMMER01";
	char *file_name = (char *) "wifly.csv";
	char *bearing_file_name = (char *) "bearing_calc.csv";
	char *port = (char *) "/dev/ttyUSB0";

	// connect to the wifly
	int wifly_fd = wifly_connect(port);

	if (wifly_fd < 0) {
		printf("Error opening wifly connection\n");
		return NULL;
	}

	/* Go into command mode */
	commandmode(wifly_fd);

	/* Open a file to write values to */
	/* Appending values */
	FILE *wifly_file = fopen(file_name, "a");
	if (wifly_file == NULL)
	{
		// TODO: figure out what we do want to return when there is an error
		printf("Error opening wifly output file\n");
		return NULL;
	}

	/* Open a file to write bearing calcs to */
	FILE *bearing_file = fopen(bearing_file_name, "a");
	if (bearing_file == NULL)
	{
		// TODO: figure out what we do want to return when there is an error
		printf("Error opening bearing output file\n");
		return NULL;
	}

	vector<double> angles;
	vector<double> gains;

	// main loop that should be constantly taking measurements
	// until the main program is stopped
	while (RUNNING_FLAG) {

		/* check if we are in an official rotation */
		if (rotating) {
			if (!in_rotation) {
				// set our logic to mark we are now running the rotation logic
				in_rotation = true;

				// clear the vectors
				angles.clear();
				gains.clear();
			}

			angles.push_back((double) uavData->vfr_hud.heading);
			gains.push_back(scanrssi(wifly_fd, ssid));

		}

		if (!rotating && in_rotation) {
			in_rotation = false;

			// do bearing calculation at this point
			double bearing = get_bearing(angles, gains);

			// write the lat, lon, alt and bearing to file
			fprintf(bearing_file, "%i,%i,%f,%f\n", uavData->gps_position.lat, uavData->gps_position.lon, uavData->vfr_hud.alt, bearing);

			// send a mavlink message of the calculated bearing
			send_bearing_message(bearing, uavData->gps_position.lat, uavData->gps_position.lon, uavData->vfr_hud.alt);
		}

		/* Scan values to this file */
		/* Add degree at which you measure first */
		cout << uavData->vfr_hud.heading << " ";
		fprintf(wifly_file, "%u,%i,%i,%i,%f,", uavData->custom_mode, uavData->vfr_hud.heading, uavData->gps_position.lat, uavData->gps_position.lon, uavData->vfr_hud.alt);
		scanrssi_f(wifly_fd, ssid, wifly_file, num_samples);

		// TODO: send mavlink message of calculated rssi...

		/* sleep for some time before making another measurement (30 ms for now) */
		usleep(30000);

	}

	/* Be sure to close the output file and connection */
	fclose(wifly_file);
	close(wifly_fd);

	return NULL;
}
<|endoftext|>


<commit_before>#include "TagLayer.h"
#include "Hash.h"
#include "Layer.h"
#include "LonLatToXYTransformation.h"
#include "State.h"
#include <ctpp2/CDT.hpp>
#include <grid-files/common/GeneralFunctions.h>
#include <macgyver/Exception.h>
#include <ogr_spatialref.h>

namespace SmartMet
{
namespace Plugin
{
namespace Dali
{
// ----------------------------------------------------------------------
/*!
 * \brief Initialize from JSON
 */
// ----------------------------------------------------------------------

void TagLayer::init(const Json::Value& theJson,
                    const State& theState,
                    const Config& theConfig,
                    const Properties& theProperties)
{
  try
  {
    if (!theJson.isObject())
      throw Fmi::Exception(BCP, "Symbol-layer JSON is not a JSON object");

    Layer::init(theJson, theState, theConfig, theProperties);

    // Extract member values

    type = "tag";
    Json::Value nulljson;

    auto json = theJson.get("tag", nulljson);
    if (!json.isNull())
      tag = json.asString();

    json = theJson.get("cdata", nulljson);
    if (!json.isNull())
      (cdata = Text())->init(json, theConfig);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Generate the layer details into the template hash
 */
// ----------------------------------------------------------------------

void TagLayer::generate(CTPP::CDT& theGlobals, CTPP::CDT& theLayersCdt, State& theState)
{
  try
  {
    if (!tag || tag->empty())
      throw Fmi::Exception(BCP, "TagLayer tag must be defined and be non-empty");

    if (!validLayer(theState))
      return;

    // longitude & latitude
    std::string longitude = attributes.value("longitude");
    std::string latitude = attributes.value("latitude");
    if (!longitude.empty() && !latitude.empty())
    {
      double xCoord = 0;
      double yCoord = 0;
      LonLatToXYTransformation transformation(projection);
      transformation.transform(Fmi::stod(longitude), Fmi::stod(latitude), xCoord, yCoord);
      attributes.add("x", Fmi::to_string(xCoord));
      attributes.add("y", Fmi::to_string(yCoord));
      attributes.remove("latitude");
      attributes.remove("longitude");
    }

#if 0
    // GRIB VERSION CODE, NOT SURE WHY THIS WAS ADDED
    std::string x = attributes.value("x");
    std::string y = attributes.value("y");

    if (!x.empty() && !y.empty())
    {
      double xx = toDouble(x.c_str());
      double yy = toDouble(y.c_str());

      const auto& box = projection.getBox();

      if (xx < 0)
        attributes.add("x", std::to_string(box.width() + xx));

      if (yy < 0)
        attributes.add("y", std::to_string(box.height() + yy));
    }
#endif

    // Update the globals

    if (css)
    {
      std::string name = theState.getCustomer() + "/" + *css;
      theGlobals["css"][name] = theState.getStyle(*css);
    }

    // Detect whether we're defining a composite tag such as
    // clipPath or mask or a normal element such as circle
    // or polyline based on the presence of child elements
    // or cdata to be embedded in the tag.

    bool composite = !layers.empty() || cdata;

    if (!composite)
    {
      // Do not group this layer and use attributes in tag instead

      CTPP::CDT group_cdt(CTPP::CDT::HASH_VAL);
      group_cdt["start"] = "";
      group_cdt["end"] = "";
      group_cdt["attributes"] = CTPP::CDT(CTPP::CDT::HASH_VAL);

      // Use tag inside layer instead

      CTPP::CDT tag_cdt(CTPP::CDT::HASH_VAL);
      tag_cdt["start"] = "<" + *tag;
      tag_cdt["end"] = "/>";
      theState.addAttributes(theGlobals, tag_cdt, attributes);

      group_cdt["tags"].PushBack(tag_cdt);

      theLayersCdt.PushBack(group_cdt);
    }
    else
    {
      // The tag is a composite
      // Update coordinates of sublayers
      if (!longitude.empty() && !latitude.empty())
      {
        for (const auto& layer : layers.layers)
        {
          std::string x = layer->attributes.value("x");
          std::string y = layer->attributes.value("y");
          if (!x.empty() && !y.empty())
          {
            double xCoord = 0;
            double yCoord = 0;
            LonLatToXYTransformation transformation(projection);
            transformation.transform(Fmi::stod(longitude), Fmi::stod(latitude), xCoord, yCoord);
            xCoord += Fmi::stod(x);
            yCoord += Fmi::stod(y);
            layer->attributes.add("x", Fmi::to_string(xCoord));
            layer->attributes.add("y", Fmi::to_string(yCoord));
          }
        }
      }

      CTPP::CDT group_cdt(CTPP::CDT::HASH_VAL);
      group_cdt["start"] = "<" + *tag;
      group_cdt["end"] = "";
      group_cdt["attributes"] = CTPP::CDT(CTPP::CDT::HASH_VAL);
      if (cdata)
        group_cdt["cdata"] = cdata->translate(language);
      theState.addAttributes(theGlobals, group_cdt, attributes);

      theLayersCdt.PushBack(group_cdt);

      // Then expand the inner layers

      layers.generate(theGlobals, theLayersCdt, theState);

      // Add the extra terminator to end the composite element as well once
      // the last layer has has been terminated.

      std::string end;

      if (layers.empty() && cdata)
        ;  // for example <text>Foo bar</text>
      else
      {
        end += "\n";
        if (!theState.inDefs())  // ident in body, not in defs
          end += "  ";
      }
      end += "</" + *tag + ">";

      theLayersCdt[theLayersCdt.Size() - 1]["end"].Concat(end);
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Hash value
 */
// ----------------------------------------------------------------------

std::size_t TagLayer::hash_value(const State& theState) const
{
  try
  {
    auto hash = Layer::hash_value(theState);
    Dali::hash_combine(hash, Dali::hash_value(tag));
    Dali::hash_combine(hash, Dali::hash_value(cdata, theState));
    return hash;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

}  // namespace Dali
}  // namespace Plugin
}  // namespace SmartMet
<commit_msg>Fixed TagLayer to work better if there is no projeciton<commit_after>#include "TagLayer.h"
#include "Hash.h"
#include "Layer.h"
#include "LonLatToXYTransformation.h"
#include "State.h"
#include <ctpp2/CDT.hpp>
#include <grid-files/common/GeneralFunctions.h>
#include <macgyver/Exception.h>
#include <ogr_spatialref.h>

namespace SmartMet
{
namespace Plugin
{
namespace Dali
{
// ----------------------------------------------------------------------
/*!
 * \brief Initialize from JSON
 */
// ----------------------------------------------------------------------

void TagLayer::init(const Json::Value& theJson,
                    const State& theState,
                    const Config& theConfig,
                    const Properties& theProperties)
{
  try
  {
    if (!theJson.isObject())
      throw Fmi::Exception(BCP, "Symbol-layer JSON is not a JSON object");

    Layer::init(theJson, theState, theConfig, theProperties);

    // Extract member values

    type = "tag";
    Json::Value nulljson;

    auto json = theJson.get("tag", nulljson);
    if (!json.isNull())
      tag = json.asString();

    json = theJson.get("cdata", nulljson);
    if (!json.isNull())
      (cdata = Text())->init(json, theConfig);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Generate the layer details into the template hash
 */
// ----------------------------------------------------------------------

void TagLayer::generate(CTPP::CDT& theGlobals, CTPP::CDT& theLayersCdt, State& theState)
{
  try
  {
    if (!tag || tag->empty())
      throw Fmi::Exception(BCP, "TagLayer tag must be defined and be non-empty");

    if (!validLayer(theState))
      return;

    // Update projection specs from querydata in case crs=data
    projection.update(getModel(theState));

    // longitude & latitude
    std::string longitude = attributes.value("longitude");
    std::string latitude = attributes.value("latitude");
    if (!longitude.empty() && !latitude.empty())
    {
      double xCoord = 0;
      double yCoord = 0;
      LonLatToXYTransformation transformation(projection);
      transformation.transform(Fmi::stod(longitude), Fmi::stod(latitude), xCoord, yCoord);
      attributes.add("x", Fmi::to_string(xCoord));
      attributes.add("y", Fmi::to_string(yCoord));
      attributes.remove("latitude");
      attributes.remove("longitude");
    }

    std::string x = attributes.value("x");
    std::string y = attributes.value("y");

    if (!x.empty() && !y.empty())
    {
      double xx = toDouble(x.c_str());
      double yy = toDouble(y.c_str());

      if (xx < 0 || yy < 0)
      {
        // Projection may not be available. We should really not require a projection
        // here, but just check the size and position of the view.

        const auto& box = projection.getBox();

        if (xx < 0)
          attributes.add("x", std::to_string(box.width() + xx));

        if (yy < 0)
          attributes.add("y", std::to_string(box.height() + yy));
      }
    }

    // Update the globals

    if (css)
    {
      std::string name = theState.getCustomer() + "/" + *css;
      theGlobals["css"][name] = theState.getStyle(*css);
    }

    // Detect whether we're defining a composite tag such as
    // clipPath or mask or a normal element such as circle
    // or polyline based on the presence of child elements
    // or cdata to be embedded in the tag.

    bool composite = !layers.empty() || cdata;

    if (!composite)
    {
      // Do not group this layer and use attributes in tag instead

      CTPP::CDT group_cdt(CTPP::CDT::HASH_VAL);
      group_cdt["start"] = "";
      group_cdt["end"] = "";
      group_cdt["attributes"] = CTPP::CDT(CTPP::CDT::HASH_VAL);

      // Use tag inside layer instead

      CTPP::CDT tag_cdt(CTPP::CDT::HASH_VAL);
      tag_cdt["start"] = "<" + *tag;
      tag_cdt["end"] = "/>";
      theState.addAttributes(theGlobals, tag_cdt, attributes);

      group_cdt["tags"].PushBack(tag_cdt);

      theLayersCdt.PushBack(group_cdt);
    }
    else
    {
      // The tag is a composite
      // Update coordinates of sublayers
      if (!longitude.empty() && !latitude.empty())
      {
        for (const auto& layer : layers.layers)
        {
          std::string x = layer->attributes.value("x");
          std::string y = layer->attributes.value("y");
          if (!x.empty() && !y.empty())
          {
            double xCoord = 0;
            double yCoord = 0;
            LonLatToXYTransformation transformation(projection);
            transformation.transform(Fmi::stod(longitude), Fmi::stod(latitude), xCoord, yCoord);
            xCoord += Fmi::stod(x);
            yCoord += Fmi::stod(y);
            layer->attributes.add("x", Fmi::to_string(xCoord));
            layer->attributes.add("y", Fmi::to_string(yCoord));
          }
        }
      }

      CTPP::CDT group_cdt(CTPP::CDT::HASH_VAL);
      group_cdt["start"] = "<" + *tag;
      group_cdt["end"] = "";
      group_cdt["attributes"] = CTPP::CDT(CTPP::CDT::HASH_VAL);
      if (cdata)
        group_cdt["cdata"] = cdata->translate(language);
      theState.addAttributes(theGlobals, group_cdt, attributes);

      theLayersCdt.PushBack(group_cdt);

      // Then expand the inner layers

      layers.generate(theGlobals, theLayersCdt, theState);

      // Add the extra terminator to end the composite element as well once
      // the last layer has has been terminated.

      std::string end;

      if (layers.empty() && cdata)
        ;  // for example <text>Foo bar</text>
      else
      {
        end += "\n";
        if (!theState.inDefs())  // ident in body, not in defs
          end += "  ";
      }
      end += "</" + *tag + ">";

      theLayersCdt[theLayersCdt.Size() - 1]["end"].Concat(end);
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Hash value
 */
// ----------------------------------------------------------------------

std::size_t TagLayer::hash_value(const State& theState) const
{
  try
  {
    auto hash = Layer::hash_value(theState);
    Dali::hash_combine(hash, Dali::hash_value(tag));
    Dali::hash_combine(hash, Dali::hash_value(cdata, theState));
    return hash;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

}  // namespace Dali
}  // namespace Plugin
}  // namespace SmartMet
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS rowlimit (1.1.1.1.346); FILE MERGED 2004/01/13 20:04:36 er 1.1.1.1.346.1: #i1967# SCCOL,SCROW,SCTAB replace USHORT; SCsCOL,SCsROW,SCsTAB replace short<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: morphdlg.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 04:08:28 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifdef SD_DLLIMPLEMENTATION
#undef SD_DLLIMPLEMENTATION
#endif

#include "morphdlg.hxx"

#include "strings.hrc"
#include "sdresid.hxx"
#include "sdmod.hxx"
#include "sdiocmpt.hxx"
#include "morphdlg.hrc"

#ifndef _CONFIG_HXX
#include <tools/config.hxx>
#endif
#ifndef SVX_XFILLIT0_HXX //autogen
#include <svx/xfillit0.hxx>
#endif
#ifndef _SVX_XLINEIT0_HXX //autogen
#include <svx/xlineit0.hxx>
#endif
#ifndef _XENUM_HXX //autogen
#include <svx/xenum.hxx>
#endif
#ifndef _SVDOBJ_HXX //autogen
#include <svx/svdobj.hxx>
#endif
#ifndef _SFXITEMSET_HXX //autogen
#include <svtools/itemset.hxx>
#endif
#ifndef _SFXITEMPOOL_HXX //autogen
#include <svtools/itempool.hxx>
#endif

namespace sd {

/******************************************************************************/

#define FADE_STEP   "FadeSteps"
#define FADE_ATTRIB "FadeAttributes"
#define FADE_ORIENT "FadeOrientation"
#define FADE_TRUE   "true"
#define FADE_FALSE  "false"

/******************************************************************************/

/******************************************************************************
|*
|*
|*
\******************************************************************************/

MorphDlg::MorphDlg( ::Window* pParent, const SdrObject* pObj1, const SdrObject* pObj2 ) :
            ModalDialog     ( pParent, SdResId( DLG_MORPH ) ),
            aBtnOK          ( this, SdResId( BTN_OK ) ),
            aBtnCancel      ( this, SdResId( BTN_CANCEL ) ),
            aBtnHelp        ( this, SdResId( BTN_HELP ) ),
            aGrpPreset      ( this, SdResId( GRP_PRESET ) ),
            aFtSteps        ( this, SdResId( FT_STEPS ) ),
            aMtfSteps       ( this, SdResId( MTF_STEPS ) ),
            aCbxAttributes  ( this, SdResId( CBX_ATTRIBUTES ) ),
            aCbxOrientation ( this, SdResId( CBX_ORIENTATION ) )
{
    FreeResource();
    LoadSettings();

    SfxItemPool*    pPool = (SfxItemPool*) pObj1->GetObjectItemPool();
    SfxItemSet      aSet1( *pPool );
    SfxItemSet      aSet2( *pPool );

    aSet1.Put(pObj1->GetMergedItemSet());
    aSet2.Put(pObj2->GetMergedItemSet());

    const XLineStyle    eLineStyle1 = ( (const XLineStyleItem&) aSet1.Get( XATTR_LINESTYLE ) ).GetValue();
    const XLineStyle    eLineStyle2 = ( (const XLineStyleItem&) aSet2.Get( XATTR_LINESTYLE ) ).GetValue();
    const XFillStyle    eFillStyle1 = ( (const XFillStyleItem&) aSet1.Get( XATTR_FILLSTYLE ) ).GetValue();
    const XFillStyle    eFillStyle2 = ( (const XFillStyleItem&) aSet2.Get( XATTR_FILLSTYLE ) ).GetValue();

    if ( ( ( eLineStyle1 == XLINE_NONE ) || ( eLineStyle2 == XLINE_NONE ) ) &&
         ( ( eFillStyle1 != XFILL_SOLID ) || ( eFillStyle2 != XFILL_SOLID ) ) )
    {
        aCbxAttributes.Disable();
    }
}

/******************************************************************************
|*
|*
|*
\******************************************************************************/

MorphDlg::~MorphDlg()
{
}

/******************************************************************************
|*
|*
|*
\******************************************************************************/

void MorphDlg::LoadSettings()
{
    SvStorageStreamRef  xIStm( SD_MOD()->GetOptionStream( UniString::CreateFromAscii(
                               RTL_CONSTASCII_STRINGPARAM( SD_OPTION_MORPHING ) ),
                               SD_OPTION_LOAD ) );
    UINT16              nSteps;
    BOOL                bOrient, bAttrib;

    if( xIStm.Is() )
    {
        SdIOCompat aCompat( *xIStm, STREAM_READ );

        *xIStm >> nSteps >> bOrient >> bAttrib;
    }
    else
    {
        nSteps = 16;
        bOrient = bAttrib = TRUE;
    }

    aMtfSteps.SetValue( nSteps );
    aCbxOrientation.Check( bOrient );
    aCbxAttributes.Check( bAttrib );
}

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

void MorphDlg::SaveSettings() const
{
    SvStorageStreamRef xOStm( SD_MOD()->GetOptionStream( UniString::CreateFromAscii(
                               RTL_CONSTASCII_STRINGPARAM( SD_OPTION_MORPHING ) ),
                               SD_OPTION_STORE ) );

    if( xOStm.Is() )
    {
        SdIOCompat aCompat( *xOStm, STREAM_WRITE, 1 );

        *xOStm << (UINT16) aMtfSteps.GetValue()
               << aCbxOrientation.IsChecked()
               << aCbxAttributes.IsChecked();
    }
}

} // end of namespace sd
<commit_msg>INTEGRATION: CWS pchfix02 (1.10.282); FILE MERGED 2006/09/01 17:37:00 kaib 1.10.282.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: morphdlg.cxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 18:40:36 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#ifdef SD_DLLIMPLEMENTATION
#undef SD_DLLIMPLEMENTATION
#endif

#include "morphdlg.hxx"

#include "strings.hrc"
#include "sdresid.hxx"
#include "sdmod.hxx"
#include "sdiocmpt.hxx"
#include "morphdlg.hrc"

#ifndef _CONFIG_HXX
#include <tools/config.hxx>
#endif
#ifndef SVX_XFILLIT0_HXX //autogen
#include <svx/xfillit0.hxx>
#endif
#ifndef _SVX_XLINEIT0_HXX //autogen
#include <svx/xlineit0.hxx>
#endif
#ifndef _XENUM_HXX //autogen
#include <svx/xenum.hxx>
#endif
#ifndef _SVDOBJ_HXX //autogen
#include <svx/svdobj.hxx>
#endif
#ifndef _SFXITEMSET_HXX //autogen
#include <svtools/itemset.hxx>
#endif
#ifndef _SFXITEMPOOL_HXX //autogen
#include <svtools/itempool.hxx>
#endif

namespace sd {

/******************************************************************************/

#define FADE_STEP   "FadeSteps"
#define FADE_ATTRIB "FadeAttributes"
#define FADE_ORIENT "FadeOrientation"
#define FADE_TRUE   "true"
#define FADE_FALSE  "false"

/******************************************************************************/

/******************************************************************************
|*
|*
|*
\******************************************************************************/

MorphDlg::MorphDlg( ::Window* pParent, const SdrObject* pObj1, const SdrObject* pObj2 ) :
            ModalDialog     ( pParent, SdResId( DLG_MORPH ) ),
            aBtnOK          ( this, SdResId( BTN_OK ) ),
            aBtnCancel      ( this, SdResId( BTN_CANCEL ) ),
            aBtnHelp        ( this, SdResId( BTN_HELP ) ),
            aGrpPreset      ( this, SdResId( GRP_PRESET ) ),
            aFtSteps        ( this, SdResId( FT_STEPS ) ),
            aMtfSteps       ( this, SdResId( MTF_STEPS ) ),
            aCbxAttributes  ( this, SdResId( CBX_ATTRIBUTES ) ),
            aCbxOrientation ( this, SdResId( CBX_ORIENTATION ) )
{
    FreeResource();
    LoadSettings();

    SfxItemPool*    pPool = (SfxItemPool*) pObj1->GetObjectItemPool();
    SfxItemSet      aSet1( *pPool );
    SfxItemSet      aSet2( *pPool );

    aSet1.Put(pObj1->GetMergedItemSet());
    aSet2.Put(pObj2->GetMergedItemSet());

    const XLineStyle    eLineStyle1 = ( (const XLineStyleItem&) aSet1.Get( XATTR_LINESTYLE ) ).GetValue();
    const XLineStyle    eLineStyle2 = ( (const XLineStyleItem&) aSet2.Get( XATTR_LINESTYLE ) ).GetValue();
    const XFillStyle    eFillStyle1 = ( (const XFillStyleItem&) aSet1.Get( XATTR_FILLSTYLE ) ).GetValue();
    const XFillStyle    eFillStyle2 = ( (const XFillStyleItem&) aSet2.Get( XATTR_FILLSTYLE ) ).GetValue();

    if ( ( ( eLineStyle1 == XLINE_NONE ) || ( eLineStyle2 == XLINE_NONE ) ) &&
         ( ( eFillStyle1 != XFILL_SOLID ) || ( eFillStyle2 != XFILL_SOLID ) ) )
    {
        aCbxAttributes.Disable();
    }
}

/******************************************************************************
|*
|*
|*
\******************************************************************************/

MorphDlg::~MorphDlg()
{
}

/******************************************************************************
|*
|*
|*
\******************************************************************************/

void MorphDlg::LoadSettings()
{
    SvStorageStreamRef  xIStm( SD_MOD()->GetOptionStream( UniString::CreateFromAscii(
                               RTL_CONSTASCII_STRINGPARAM( SD_OPTION_MORPHING ) ),
                               SD_OPTION_LOAD ) );
    UINT16              nSteps;
    BOOL                bOrient, bAttrib;

    if( xIStm.Is() )
    {
        SdIOCompat aCompat( *xIStm, STREAM_READ );

        *xIStm >> nSteps >> bOrient >> bAttrib;
    }
    else
    {
        nSteps = 16;
        bOrient = bAttrib = TRUE;
    }

    aMtfSteps.SetValue( nSteps );
    aCbxOrientation.Check( bOrient );
    aCbxAttributes.Check( bAttrib );
}

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

void MorphDlg::SaveSettings() const
{
    SvStorageStreamRef xOStm( SD_MOD()->GetOptionStream( UniString::CreateFromAscii(
                               RTL_CONSTASCII_STRINGPARAM( SD_OPTION_MORPHING ) ),
                               SD_OPTION_STORE ) );

    if( xOStm.Is() )
    {
        SdIOCompat aCompat( *xOStm, STREAM_WRITE, 1 );

        *xOStm << (UINT16) aMtfSteps.GetValue()
               << aCbxOrientation.IsChecked()
               << aCbxAttributes.IsChecked();
    }
}

} // end of namespace sd
<|endoftext|>