<commit_before>#include "optimal_solver.h"
#include "indexing.h"
#include "corner_permutation.h"
#include "corner_orientation.h"
#include "corner.h"
#include "edge_orientation.h"
#include "edge_permutation.h"
#include <iostream>
#include <conio.h>
#include <ctime>

double diffclock(clock_t clock1, clock_t clock2)
{
	double diffticks = abs(clock1 - clock2);
	double diffms = (diffticks) / (CLOCKS_PER_SEC / 1000);
	return diffms;
}

OptimalSolver::OptimalSolver()
{
	CornerPermutation cp;
	cp.buildTransitionTable();
	cp.buildPruneTable();
	cp_transition = cp.getTransitionTable();

	CornerOrientation co;
	co.buildTransitionTable();
	co.buildPruneTable();
	co_transition = co.getTransitionTable();

	Corner corner(cp_transition, co_transition);
	corner.buildPruneTable();
	c_prune = corner.getPruneTable();

	EdgeOrientation eo;
	eo.buildTransitionTable();
	eo.buildPruneTable();
	eo_transition = eo.getTransitionTable();
	eo_prune = eo.getPruneTable();

	EdgePermutation ep;
	ep.buildTransitionTable();
	ep.buildPruneTable();
	ep.buildPruneTable2();
	ep_transition = ep.getTransitionTable();
	ep1_prune = ep.getPruneTable();
	ep2_prune = ep.getPruneTable2();

	// IDA* for e_prune
	prune_count = 0;
	e_prune.clear();
	int depth = 0;
	long max = 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1;
	cout << endl << "Edge Prune Table:" << endl;
	while (prune_count < max && depth < 7)
	{
		prune_treeSearch(0, 366288, depth, depth, -1);
		cout << "Depth " << depth << ": " << prune_count << endl;
		depth++;
	}

	long sum_c_prune = 0;
	for (long i = 0; i < c_prune.size(); i++)
		sum_c_prune += c_prune[i];
	cout << "average prune depth corners: " << (sum_c_prune / (double)c_prune.size()) << endl;

	long sum_e1_prune = 0;
	for (long i = 0; i < ep1_prune.size(); i++)
		sum_e1_prune += ep1_prune[i];
	cout << "average prune depth corners: " << (sum_e1_prune / (double)ep1_prune.size()) << endl;

	moveNames[0] = string("U");
	moveNames[1] = string("D");
	moveNames[2] = string("R");
	moveNames[3] = string("L");
	moveNames[4] = string("F");
	moveNames[5] = string("B");
	moveCntNames[0] = string(" ");
	moveCntNames[1] = string("2");
	moveCntNames[2] = string("'");
};

int OptimalSolver::IDA(vector<int> cornerPermutation, vector<int> cornerOrientation, vector<int> edgeOrientation, vector<int> edgePermutation1, vector<int> edgePermutation2)
{
	int cornerPerm = Indexing::permutation_to_index(cornerPermutation);
	int cornerOrient = Indexing::orientation_to_index_dependent(cornerOrientation, 3);
	int edgeOrient = Indexing::orientation_to_index_dependent(edgeOrientation, 2);
	EdgePermutation ep;
	int edgePerm1 = ep.array_to_index(edgePermutation1);
	int edgePerm2 = ep.array_to_index(edgePermutation2);

	solution = "";
	nodeCnt = 0;
	clock_t start = clock();

	cout << "Start solving" << endl;
	int depth;
	for (depth = 0; depth <= 20; depth++)
	{
		cout << "Depth " << depth << ": ";
		if (treeSearch(cornerPerm, cornerOrient, edgeOrient, edgePerm1, edgePerm2, depth, -1))
		{
			cout << "solution found (" << nodeCnt << " nodes visited)\n" << solution.c_str() << endl;
			break;
		}
		else
		{
			cout << "nothing (" << nodeCnt << " nodes visited)" << endl;
		}
	}
	cout << "total: " << nodeCnt << " nodes visited" << endl;
	clock_t end = clock();
	double seconds = diffclock(start, end) / 1000.0;
	cout << "Time: " << seconds << " seconds(" << (int)(nodeCnt / seconds) << " nodes / second)" << endl;

	return depth;
}

bool OptimalSolver::treeSearch(int cornerPermutation, int cornerOrientation, int edgeOrientation, int edgePermutation1, int edgePermutation2, int depth, int lastMove)
{
	nodeCnt++;
	if (depth == 0)
	{
		return (cornerPermutation == 0 && cornerOrientation == 0 && edgeOrientation == 0 && edgePermutation1 == 0 && edgePermutation2 == 366288);
	}
	else
	{
		long p = edgePermutation1 * 665280 + edgePermutation2;
		int ep_prune_value = 7;
		if (e_prune.count(p) == 1)
			ep_prune_value = e_prune[p];

		if (c_prune[cornerPermutation * 2187 + cornerOrientation] <= depth && eo_prune[edgeOrientation] <= depth && ep_prune_value <= depth)
		{
			for (int move = 0; move < 6; move++)
			{
				if (move == lastMove)
					continue;
				if ((lastMove & 1) == 1 && move == lastMove - 1)
					continue;

				for (int j = 0; j < 3; j++)
				{
					cornerPermutation = cp_transition[cornerPermutation][move];
					cornerOrientation = co_transition[cornerOrientation][move];
					edgeOrientation = eo_transition[edgeOrientation][move];
					edgePermutation1 = ep_transition[edgePermutation1][move];
					edgePermutation2 = ep_transition[edgePermutation2][move];

					if (treeSearch(cornerPermutation, cornerOrientation, edgeOrientation, edgePermutation1, edgePermutation2, depth - 1, move))
					{
						solution = moveNames[move] + moveCntNames[j] + string(" ") + solution;
						return true;
					}
				}
				cornerPermutation = cp_transition[cornerPermutation][move];
				cornerOrientation = co_transition[cornerOrientation][move];
				edgeOrientation = eo_transition[edgeOrientation][move];
				edgePermutation1 = ep_transition[edgePermutation1][move];
				edgePermutation2 = ep_transition[edgePermutation2][move];
			}
		}

		return false;
	}
}

void OptimalSolver::prune_treeSearch(long ep1, long ep2, int depth_left, int depth, int lastMove)
{
	long p = ep1 * 665280 + ep2;

	if (depth_left == 0)
	{
		if (e_prune.count(p) == 0)
		{
			e_prune[p] = depth;
			prune_count++;
		}
	}
	else
	{
		if (e_prune[p] == depth - depth_left)
		{
			for (int move = 0; move < 6; move++)
			{
				if (move == lastMove)
					continue;
				if ((lastMove & 1) == 1 && move == lastMove - 1)
					continue;

				for (int j = 0; j < 3; j++)
				{
					ep1 = ep_transition[ep1][move];
					ep2 = ep_transition[ep2][move];
					prune_treeSearch(ep1, ep2, depth_left - 1, depth, move);
				}
				ep1 = ep_transition[ep1][move];
				ep2 = ep_transition[ep2][move];
			}
		}
	}
}
<commit_msg>Remove conio.h<commit_after>#include "optimal_solver.h"
#include "indexing.h"
#include "corner_permutation.h"
#include "corner_orientation.h"
#include "corner.h"
#include "edge_orientation.h"
#include "edge_permutation.h"
#include <iostream>
#include <ctime>

double diffclock(clock_t clock1, clock_t clock2)
{
	double diffticks = abs(clock1 - clock2);
	double diffms = (diffticks) / (CLOCKS_PER_SEC / 1000);
	return diffms;
}

OptimalSolver::OptimalSolver()
{
	CornerPermutation cp;
	cp.buildTransitionTable();
	cp.buildPruneTable();
	cp_transition = cp.getTransitionTable();

	CornerOrientation co;
	co.buildTransitionTable();
	co.buildPruneTable();
	co_transition = co.getTransitionTable();

	Corner corner(cp_transition, co_transition);
	corner.buildPruneTable();
	c_prune = corner.getPruneTable();

	EdgeOrientation eo;
	eo.buildTransitionTable();
	eo.buildPruneTable();
	eo_transition = eo.getTransitionTable();
	eo_prune = eo.getPruneTable();

	EdgePermutation ep;
	ep.buildTransitionTable();
	ep.buildPruneTable();
	ep.buildPruneTable2();
	ep_transition = ep.getTransitionTable();
	ep1_prune = ep.getPruneTable();
	ep2_prune = ep.getPruneTable2();

	// IDA* for e_prune
	prune_count = 0;
	e_prune.clear();
	int depth = 0;
	long max = 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1;
	cout << endl << "Edge Prune Table:" << endl;
	while (prune_count < max && depth < 7)
	{
		prune_treeSearch(0, 366288, depth, depth, -1);
		cout << "Depth " << depth << ": " << prune_count << endl;
		depth++;
	}

	long sum_c_prune = 0;
	for (long i = 0; i < c_prune.size(); i++)
		sum_c_prune += c_prune[i];
	cout << "average prune depth corners: " << (sum_c_prune / (double)c_prune.size()) << endl;

	long sum_e1_prune = 0;
	for (long i = 0; i < ep1_prune.size(); i++)
		sum_e1_prune += ep1_prune[i];
	cout << "average prune depth corners: " << (sum_e1_prune / (double)ep1_prune.size()) << endl;

	moveNames[0] = string("U");
	moveNames[1] = string("D");
	moveNames[2] = string("R");
	moveNames[3] = string("L");
	moveNames[4] = string("F");
	moveNames[5] = string("B");
	moveCntNames[0] = string(" ");
	moveCntNames[1] = string("2");
	moveCntNames[2] = string("'");
};

int OptimalSolver::IDA(vector<int> cornerPermutation, vector<int> cornerOrientation, vector<int> edgeOrientation, vector<int> edgePermutation1, vector<int> edgePermutation2)
{
	int cornerPerm = Indexing::permutation_to_index(cornerPermutation);
	int cornerOrient = Indexing::orientation_to_index_dependent(cornerOrientation, 3);
	int edgeOrient = Indexing::orientation_to_index_dependent(edgeOrientation, 2);
	EdgePermutation ep;
	int edgePerm1 = ep.array_to_index(edgePermutation1);
	int edgePerm2 = ep.array_to_index(edgePermutation2);

	solution = "";
	nodeCnt = 0;
	clock_t start = clock();

	cout << "Start solving" << endl;
	int depth;
	for (depth = 0; depth <= 20; depth++)
	{
		cout << "Depth " << depth << ": ";
		if (treeSearch(cornerPerm, cornerOrient, edgeOrient, edgePerm1, edgePerm2, depth, -1))
		{
			cout << "solution found (" << nodeCnt << " nodes visited)\n" << solution.c_str() << endl;
			break;
		}
		else
		{
			cout << "nothing (" << nodeCnt << " nodes visited)" << endl;
		}
	}
	cout << "total: " << nodeCnt << " nodes visited" << endl;
	clock_t end = clock();
	double seconds = diffclock(start, end) / 1000.0;
	cout << "Time: " << seconds << " seconds(" << (int)(nodeCnt / seconds) << " nodes / second)" << endl;

	return depth;
}

bool OptimalSolver::treeSearch(int cornerPermutation, int cornerOrientation, int edgeOrientation, int edgePermutation1, int edgePermutation2, int depth, int lastMove)
{
	nodeCnt++;
	if (depth == 0)
	{
		return (cornerPermutation == 0 && cornerOrientation == 0 && edgeOrientation == 0 && edgePermutation1 == 0 && edgePermutation2 == 366288);
	}
	else
	{
		long p = edgePermutation1 * 665280 + edgePermutation2;
		int ep_prune_value = 7;
		if (e_prune.count(p) == 1)
			ep_prune_value = e_prune[p];

		if (c_prune[cornerPermutation * 2187 + cornerOrientation] <= depth && eo_prune[edgeOrientation] <= depth && ep_prune_value <= depth)
		{
			for (int move = 0; move < 6; move++)
			{
				if (move == lastMove)
					continue;
				if ((lastMove & 1) == 1 && move == lastMove - 1)
					continue;

				for (int j = 0; j < 3; j++)
				{
					cornerPermutation = cp_transition[cornerPermutation][move];
					cornerOrientation = co_transition[cornerOrientation][move];
					edgeOrientation = eo_transition[edgeOrientation][move];
					edgePermutation1 = ep_transition[edgePermutation1][move];
					edgePermutation2 = ep_transition[edgePermutation2][move];

					if (treeSearch(cornerPermutation, cornerOrientation, edgeOrientation, edgePermutation1, edgePermutation2, depth - 1, move))
					{
						solution = moveNames[move] + moveCntNames[j] + string(" ") + solution;
						return true;
					}
				}
				cornerPermutation = cp_transition[cornerPermutation][move];
				cornerOrientation = co_transition[cornerOrientation][move];
				edgeOrientation = eo_transition[edgeOrientation][move];
				edgePermutation1 = ep_transition[edgePermutation1][move];
				edgePermutation2 = ep_transition[edgePermutation2][move];
			}
		}

		return false;
	}
}

void OptimalSolver::prune_treeSearch(long ep1, long ep2, int depth_left, int depth, int lastMove)
{
	long p = ep1 * 665280 + ep2;

	if (depth_left == 0)
	{
		if (e_prune.count(p) == 0)
		{
			e_prune[p] = depth;
			prune_count++;
		}
	}
	else
	{
		if (e_prune[p] == depth - depth_left)
		{
			for (int move = 0; move < 6; move++)
			{
				if (move == lastMove)
					continue;
				if ((lastMove & 1) == 1 && move == lastMove - 1)
					continue;

				for (int j = 0; j < 3; j++)
				{
					ep1 = ep_transition[ep1][move];
					ep2 = ep_transition[ep2][move];
					prune_treeSearch(ep1, ep2, depth_left - 1, depth, move);
				}
				ep1 = ep_transition[ep1][move];
				ep2 = ep_transition[ep2][move];
			}
		}
	}
}
<|endoftext|>


<commit_before>#include "cv.h"

//' @export
// [[Rcpp::export]]
arma::uvec split_in_groups(size_t length, size_t k)
{
    std::unique_ptr<size_t[]> groups( new size_t[ k ] );
    size_t n_group = length / k;
    size_t last_group = length - (n_group * (k-1));

    for (size_t i = 0; i < k; ++i)
        groups[i] = n_group;

    // add leftovers in one-by-one
    for (size_t i = 0; i < last_group - n_group; ++i)
        ++groups[i];

    arma::uvec x(length);

    size_t n_samp = 0;
    while (n_samp < length)
    {
        size_t samp = std::rand() % k;
        if ( groups[samp] > 0 )
        {
            --groups[samp];
            x[n_samp] = samp;
            ++n_samp;
        }
    }

    return x;
}

void groups_to_row_ptr(arma::uvec& x, size_t k,
        std::vector< arma_uvec_ptr >& fit, std::vector< arma_uvec_ptr >& test)
{

    std::unique_ptr<size_t[]> groups( new size_t[ k ] );

    for (size_t i = 0; i < x.n_rows; ++i)
        ++groups[ x[i] ];

    for (size_t grp = 0; grp < k; ++grp)
    {
        arma_uvec_ptr fit_vec( new arma::uvec( x.n_rows - groups[grp] ) );
        arma_uvec_ptr test_vec( new arma::uvec( groups[grp] ) );
        size_t fit_count = 0;
        size_t test_count = 0;
        for (size_t j = 0; j < x.n_rows; ++j)
        {
            if ( x[j] == grp)
            {
                (*test_vec)[test_count] = j;
                ++test_count;
            }
            else
            {
                (*fit_vec)[fit_count] = j;
                ++fit_count;
            }
        }
        fit.push_back( fit_vec );
        test.push_back( test_vec );
    }

}

// This function does the bulk of the CV
void cross_validation_alt(const arma::mat& X, const arma::mat& Y,
        const std::string& penalty_x, const std::string& penalty_y,
        size_t k_folds,
        const arma::vec& lamx, const arma::vec& lamy,
        unsigned int& best_lamx_idx, unsigned int& best_lamy_idx,
        double& best_avg_cv)
{

    // TODO: add seed for randomness

    // get rows for cross validation
    arma::uvec groups = split_in_groups(X.n_rows, k_folds);

    std::vector< arma_uvec_ptr > fit;
    std::vector< arma_uvec_ptr > test;

    // fit and test now contain k_folds arma_uvec_ptrs of rows for fit and test
    // set for each k
    groups_to_row_ptr(groups, k_folds, fit, test);

    size_t it = 0;
    double cov = 1.0;

    // initialize all the penalties
    std::vector< std::shared_ptr<NipalsPenalty> > pen_x;
    std::vector< std::shared_ptr<NipalsPenalty> > pen_y;

    for (size_t i = 0; i < lamx.n_rows; ++i)
        pen_x.push_back( PenaltyFactory::make_penalty(penalty_x, lamx[i]) );
    for (size_t i = 0; i < lamx.n_rows; ++i)
        pen_y.push_back( PenaltyFactory::make_penalty(penalty_y, lamy[i]) );

    unsigned int opt_x = std::rand() % pen_x.size();
    unsigned int opt_y = 0;

    NipalsPenalty* cur_pen_x;
    NipalsPenalty* cur_pen_y;
    cur_pen_x = pen_x[opt_x].get();

    arma::mat avg_cv_cor( pen_x.size(), pen_y.size(), arma::fill::zeros );

    double cur_max = 0.0, prev_max = 0.0;

    while (cov > 1e-02 & it < 20)
    {
        for (size_t i_y = 0; i_y < pen_y.size(); ++i_y)
        {
            cur_pen_y = pen_y[i_y].get();
            double cur_cv_cor = 0.0;
            for (size_t k = 0; k < k_folds; ++k)
            {
                arma::mat X_ = X.rows( *(fit[k]) );
                arma::mat Y_ = Y.rows( *(fit[k]) );
                arma::vec a(X_.n_cols), b(Y_.n_cols), u(X_.n_rows), v(X_.n_rows);
                sparse_nipals_(X_, Y_, a, b, u, v, *cur_pen_x, *cur_pen_y);
                arma::mat X_t = X.rows( *(test[k]) );
                arma::mat Y_t = Y.rows( *(test[k]) );

                cur_cv_cor += abs(nipals_cov(X_t, a, Y_t, b));
            }
            cur_cv_cor /= k_folds;

            avg_cv_cor(opt_x, i_y) = cur_cv_cor;
        }

        // gets the index of the optimal y
        avg_cv_cor.row( opt_x ).max( opt_y );

        cur_pen_y = pen_y[opt_y].get();

        for (size_t i_x = 0; i_x < pen_x.size(); ++i_x)
        {
            cur_pen_x = pen_x[i_x].get();
            double cur_cv_cor = 0.0;
            for (size_t k = 0; k < k_folds; ++k)
            {
                arma::mat X_ = X.rows( *(fit[k]) );
                arma::mat Y_ = Y.rows( *(fit[k]) );
                arma::vec a(X_.n_cols), b(Y_.n_cols), u(X_.n_rows), v(X_.n_rows);

                sparse_nipals_(X_, Y_, a, b, u, v, *cur_pen_x, *cur_pen_y);

                arma::mat X_t = X.rows( *(test[k]) );
                arma::mat Y_t = Y.rows( *(test[k]) );
                cur_cv_cor += abs(nipals_cov(X_t, a, Y_t, b));
            }

            cur_cv_cor /= k_folds;
            avg_cv_cor(i_x, opt_y) = cur_cv_cor;
        }

        // should have the optimum x now
        avg_cv_cor.col( opt_y ).max( opt_x );

        cur_max = avg_cv_cor(opt_x, opt_y);
        cov = abs( cur_max - prev_max );
        prev_max = cur_max;
        ++it;
    }

    best_lamx_idx = opt_x;
    best_lamy_idx = opt_y;
    best_avg_cv = avg_cv_cor(opt_x, opt_y);
}
<commit_msg>rename some vars<commit_after>#include "cv.h"

//' @export
// [[Rcpp::export]]
arma::uvec split_in_groups(size_t length, size_t k)
{
    std::unique_ptr<size_t[]> groups( new size_t[ k ] );
    size_t n_group = length / k;
    size_t last_group = length - (n_group * (k-1));

    for (size_t i = 0; i < k; ++i)
        groups[i] = n_group;

    // add leftovers in one-by-one
    for (size_t i = 0; i < last_group - n_group; ++i)
        ++groups[i];

    arma::uvec x(length);

    size_t n_samp = 0;
    while (n_samp < length)
    {
        size_t samp = std::rand() % k;
        if ( groups[samp] > 0 )
        {
            --groups[samp];
            x[n_samp] = samp;
            ++n_samp;
        }
    }

    return x;
}

void groups_to_row_ptr(arma::uvec& x, size_t k,
        std::vector< arma_uvec_ptr >& fit, std::vector< arma_uvec_ptr >& test)
{

    std::unique_ptr<size_t[]> groups( new size_t[ k ] );

    for (size_t i = 0; i < x.n_rows; ++i)
        ++groups[ x[i] ];

    for (size_t grp = 0; grp < k; ++grp)
    {
        arma_uvec_ptr fit_vec( new arma::uvec( x.n_rows - groups[grp] ) );
        arma_uvec_ptr test_vec( new arma::uvec( groups[grp] ) );
        size_t fit_count = 0;
        size_t test_count = 0;
        for (size_t j = 0; j < x.n_rows; ++j)
        {
            if ( x[j] == grp)
            {
                (*test_vec)[test_count] = j;
                ++test_count;
            }
            else
            {
                (*fit_vec)[fit_count] = j;
                ++fit_count;
            }
        }
        fit.push_back( fit_vec );
        test.push_back( test_vec );
    }

}

// This function does the bulk of the CV
void cross_validation_alt(const arma::mat& X, const arma::mat& Y,
        const std::string& penalty_x, const std::string& penalty_y,
        size_t k_folds,
        const arma::vec& lamx, const arma::vec& lamy,
        unsigned int& best_lamx_idx, unsigned int& best_lamy_idx,
        double& best_avg_cv)
{

    // TODO: add seed for randomness

    // get rows for cross validation
    arma::uvec groups = split_in_groups(X.n_rows, k_folds);

    std::vector< arma_uvec_ptr > fit;
    std::vector< arma_uvec_ptr > test;

    // fit and test now contain k_folds arma_uvec_ptrs of rows for fit and test
    // set for each k
    groups_to_row_ptr(groups, k_folds, fit, test);

    size_t it = 0;
    double eps = 1.0;

    // initialize all the penalties
    std::vector< std::shared_ptr<NipalsPenalty> > pen_x;
    std::vector< std::shared_ptr<NipalsPenalty> > pen_y;

    for (size_t i = 0; i < lamx.n_rows; ++i)
        pen_x.push_back( PenaltyFactory::make_penalty(penalty_x, lamx[i]) );
    for (size_t i = 0; i < lamx.n_rows; ++i)
        pen_y.push_back( PenaltyFactory::make_penalty(penalty_y, lamy[i]) );

    unsigned int opt_x = std::rand() % pen_x.size();
    unsigned int opt_y = 0;

    NipalsPenalty* cur_pen_x;
    NipalsPenalty* cur_pen_y;
    cur_pen_x = pen_x[opt_x].get();

    arma::mat avg_cv_cor( pen_x.size(), pen_y.size(), arma::fill::zeros );

    double cur_max = 0.0, prev_max = 0.0;

    while (eps > 1e-02 & it < 20)
    {
        for (size_t i_y = 0; i_y < pen_y.size(); ++i_y)
        {
            cur_pen_y = pen_y[i_y].get();
            double cur_cv_cor = 0.0;
            for (size_t k = 0; k < k_folds; ++k)
            {
                arma::mat X_ = X.rows( *(fit[k]) );
                arma::mat Y_ = Y.rows( *(fit[k]) );
                arma::vec a(X_.n_cols), b(Y_.n_cols), u(X_.n_rows), v(X_.n_rows);
                sparse_nipals_(X_, Y_, a, b, u, v, *cur_pen_x, *cur_pen_y);
                arma::mat X_t = X.rows( *(test[k]) );
                arma::mat Y_t = Y.rows( *(test[k]) );

                cur_cv_cor += abs(nipals_cov(X_t, a, Y_t, b));
            }
            cur_cv_cor /= k_folds;

            avg_cv_cor(opt_x, i_y) = cur_cv_cor;
        }

        // gets the index of the optimal y
        avg_cv_cor.row( opt_x ).max( opt_y );

        cur_pen_y = pen_y[opt_y].get();

        for (size_t i_x = 0; i_x < pen_x.size(); ++i_x)
        {
            cur_pen_x = pen_x[i_x].get();
            double cur_cv_cor = 0.0;
            for (size_t k = 0; k < k_folds; ++k)
            {
                arma::mat X_ = X.rows( *(fit[k]) );
                arma::mat Y_ = Y.rows( *(fit[k]) );
                arma::vec a(X_.n_cols), b(Y_.n_cols), u(X_.n_rows), v(X_.n_rows);

                sparse_nipals_(X_, Y_, a, b, u, v, *cur_pen_x, *cur_pen_y);

                arma::mat X_t = X.rows( *(test[k]) );
                arma::mat Y_t = Y.rows( *(test[k]) );
                cur_cv_cor += abs(nipals_cov(X_t, a, Y_t, b));
            }

            cur_cv_cor /= k_folds;
            avg_cv_cor(i_x, opt_y) = cur_cv_cor;
        }

        // should have the optimum x now
        avg_cv_cor.col( opt_y ).max( opt_x );

        cur_max = avg_cv_cor(opt_x, opt_y);
        eps = abs( cur_max - prev_max );
        prev_max = cur_max;
        ++it;
    }

    best_lamx_idx = opt_x;
    best_lamy_idx = opt_y;
    best_avg_cv = avg_cv_cor(opt_x, opt_y);
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/
#include <stdlib.h>

#include <osg/Referenced>
#include <osg/Notify>
#include <osg/ApplicationUsage>
#include <osg/Observer>

#include <typeinfo>
#include <memory>
#include <set>

#include <OpenThreads/ScopedLock>
#include <OpenThreads/Mutex>

#include <osg/DeleteHandler>

namespace osg
{

//#define ENFORCE_THREADSAFE
//#define DEBUG_OBJECT_ALLOCATION_DESTRUCTION

// specialized smart pointer, used to get round auto_ptr<>'s lack of the destructor reseting itself to 0.
template<typename T>
struct ResetPointer
{
    ResetPointer():
        _ptr(0) {}

    ResetPointer(T* ptr):
        _ptr(ptr) {}

    ~ResetPointer()
    {
        delete _ptr;
        _ptr = 0;
    }

    inline ResetPointer& operator = (T* ptr)
    {
        if (_ptr==ptr) return *this;
        delete _ptr;
        _ptr = ptr;
        return *this;
    }

    void reset(T* ptr)
    {
        if (_ptr==ptr) return;
        delete _ptr;
        _ptr = ptr;
    }

    inline T& operator*()  { return *_ptr; }

    inline const T& operator*() const { return *_ptr; }

    inline T* operator->() { return _ptr; }

    inline const T* operator->() const   { return _ptr; }

    T* get() { return _ptr; }

    const T* get() const { return _ptr; }

    T* _ptr;
};

typedef ResetPointer<DeleteHandler> DeleteHandlerPointer;
typedef ResetPointer<OpenThreads::Mutex> GlobalMutexPointer;

OpenThreads::Mutex* Referenced::getGlobalReferencedMutex()
{
    static GlobalMutexPointer s_ReferencedGlobalMutext = new OpenThreads::Mutex;
    return s_ReferencedGlobalMutext.get();
}

// we'll implement Observer::getGlobalObserverMutex() here for convinience as ResetPointer is available.
OpenThreads::Mutex* Observer::getGlobalObserverMutex()
{
    static GlobalMutexPointer s_ReferencedGlobalMutext = new OpenThreads::Mutex(OpenThreads::Mutex::MUTEX_RECURSIVE);
    return s_ReferencedGlobalMutext.get();
}

// helper class for forcing the global mutex to be constructed when the library is loaded.
struct InitGlobalMutexes
{
    InitGlobalMutexes()
    {
        Referenced::getGlobalReferencedMutex();
        Observer::getGlobalObserverMutex();
    }
};
static InitGlobalMutexes s_initGlobalMutexes;

#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
static bool s_useThreadSafeReferenceCounting = getenv("OSG_THREAD_SAFE_REF_UNREF")!=0;
#endif
// static std::auto_ptr<DeleteHandler> s_deleteHandler(0);
static DeleteHandlerPointer s_deleteHandler(0);

static ApplicationUsageProxy Referenced_e0(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREAD_SAFE_REF_UNREF","");

void Referenced::setThreadSafeReferenceCounting(bool enableThreadSafeReferenceCounting)
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    s_useThreadSafeReferenceCounting = enableThreadSafeReferenceCounting;
#endif
}

bool Referenced::getThreadSafeReferenceCounting()
{
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    return true;
#else
    return s_useThreadSafeReferenceCounting;
#endif
}

void Referenced::setDeleteHandler(DeleteHandler* handler)
{
    s_deleteHandler.reset(handler);
}

DeleteHandler* Referenced::getDeleteHandler()
{
    return s_deleteHandler.get();
}

#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
OpenThreads::Mutex& getNumObjectMutex()
{
    static OpenThreads::Mutex s_numObjectMutex;
    return s_numObjectMutex;
}
static int s_numObjects = 0;
#endif

Referenced::Referenced():
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    _observerSet(0),
    _refCount(0)
#else
    _refMutex(0),
    _refCount(0),
    _observerSet(0)
#endif
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
#ifndef ENFORCE_THREADSAFE
    if (s_useThreadSafeReferenceCounting)
#endif
        _refMutex = new OpenThreads::Mutex;
#endif

#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
        ++s_numObjects;
        printf("Object created, total num=%d\n",s_numObjects);
    }
#endif

}

Referenced::Referenced(bool threadSafeRefUnref):
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    _observerSet(0),
    _refCount(0)
#else
    _refMutex(0),
    _refCount(0),
    _observerSet(0)
#endif
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
#ifndef ENFORCE_THREADSAFE
    if (threadSafeRefUnref)
#endif
        _refMutex = new OpenThreads::Mutex;
#endif

#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
        ++s_numObjects;
        printf("Object created, total num=%d\n",s_numObjects);
    }
#endif
}

Referenced::Referenced(const Referenced&):
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    _observerSet(0),
    _refCount(0)
#else
    _refMutex(0),
    _refCount(0),
    _observerSet(0)
#endif
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
#ifndef ENFORCE_THREADSAFE
    if (s_useThreadSafeReferenceCounting)
#endif
        _refMutex = new OpenThreads::Mutex;
#endif

#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
        ++s_numObjects;
        printf("Object created, total num=%d\n",s_numObjects);
    }
#endif
}

Referenced::~Referenced()
{
#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
        --s_numObjects;
        printf("Object created, total num=%d\n",s_numObjects);
    }
#endif

    if (_refCount>0)
    {
        OSG_WARN<<"Warning: deleting still referenced object "<<this<<" of type '"<<typeid(this).name()<<"'"<<std::endl;
        OSG_WARN<<"         the final reference count was "<<_refCount<<", memory corruption possible."<<std::endl;
    }

    // signal observers that we are being deleted.
    signalObserversAndDelete(false, true, false);

    // delete the ObserverSet
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    if (_observerSet.get()) delete static_cast<ObserverSet*>(_observerSet.get());
#else
    if (_observerSet) delete static_cast<ObserverSet*>(_observerSet);
#endif
}

ObserverSet* Referenced::getOrCreateObserverSet() const
{
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet.get());
    while (0 == observerSet) {
        ObserverSet* newObserverSet = new ObserverSet;
        if (!_observerSet.assign(newObserverSet, 0))
            delete newObserverSet;
        observerSet = static_cast<ObserverSet*>(_observerSet.get());
    }
    return observerSet;
#else
    if (_refMutex)
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
        if (!_observerSet) _observerSet = new ObserverSet;
        return static_cast<ObserverSet*>(_observerSet);
    }
    else
    {
        if (!_observerSet) _observerSet = new ObserverSet;
        return static_cast<ObserverSet*>(_observerSet);
    }
#endif
}

void Referenced::signalObserversAndDelete(bool signalUnreferened, bool signalDelete, bool doDelete) const
{
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet.get());
#else
    ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet);
#endif

    if (observerSet)
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*(observerSet->getObserverSetMutex()));
        if (signalUnreferened)
        {
            observerSet->signalObjectUnreferenced(const_cast<Referenced*>(this));
        }

        if (_refCount!=0)
        {
            OSG_NOTICE<<"Referenced::signalObserversAndDelete(,,) disabling delete as _refCount="<<_refCount<<std::endl;
            return;
        }

        if (signalDelete)
        {
            observerSet->signalObjectDeleted(const_cast<Referenced*>(this));
        }
    }

    if (doDelete && _refCount==0)
    {
        //OSG_NOTICE<<"Referenced::signalObserversAndDelete(,,) doing delete as _refCount="<<_refCount<<std::endl;
        if (getDeleteHandler()) deleteUsingDeleteHandler();
        else delete this;
    }
}

void Referenced::setThreadSafeRefUnref(bool threadSafe)
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    if (threadSafe)
    {
        if (!_refMutex)
        {
            // we want thread safe ref()/unref() so assign a mutex
            _refMutex = new OpenThreads::Mutex;
        }
    }
    else
    {
        if (_refMutex)
        {
            // we don't want thread safe ref()/unref() so remove any assigned mutex
            OpenThreads::Mutex* tmpMutexPtr = _refMutex;
            _refMutex = 0;
            delete tmpMutexPtr;
        }
    }
#endif
}

void Referenced::unref_nodelete() const
{
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    bool needUnreferencedSignal = ((--_refCount) == 0);
#else
    bool needUnreferencedSignal = false;
    if (_refMutex)
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
        needUnreferencedSignal = ((--_refCount) == 0);
    }
    else
    {
        needUnreferencedSignal = ((--_refCount) == 0);
    }
#endif

    if (needUnreferencedSignal)
    {
        signalObserversAndDelete(true,false,false);
    }
}

void Referenced::deleteUsingDeleteHandler() const
{
    getDeleteHandler()->requestDelete(this);
}

} // end of namespace osg
<commit_msg>From Mathias Froehlich, fixed memory leak when using OpenThread::Mutex based reference counting.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/
#include <stdlib.h>

#include <osg/Referenced>
#include <osg/Notify>
#include <osg/ApplicationUsage>
#include <osg/Observer>

#include <typeinfo>
#include <memory>
#include <set>

#include <OpenThreads/ScopedLock>
#include <OpenThreads/Mutex>

#include <osg/DeleteHandler>

namespace osg
{

//#define ENFORCE_THREADSAFE
//#define DEBUG_OBJECT_ALLOCATION_DESTRUCTION

// specialized smart pointer, used to get round auto_ptr<>'s lack of the destructor reseting itself to 0.
template<typename T>
struct ResetPointer
{
    ResetPointer():
        _ptr(0) {}

    ResetPointer(T* ptr):
        _ptr(ptr) {}

    ~ResetPointer()
    {
        delete _ptr;
        _ptr = 0;
    }

    inline ResetPointer& operator = (T* ptr)
    {
        if (_ptr==ptr) return *this;
        delete _ptr;
        _ptr = ptr;
        return *this;
    }

    void reset(T* ptr)
    {
        if (_ptr==ptr) return;
        delete _ptr;
        _ptr = ptr;
    }

    inline T& operator*()  { return *_ptr; }

    inline const T& operator*() const { return *_ptr; }

    inline T* operator->() { return _ptr; }

    inline const T* operator->() const   { return _ptr; }

    T* get() { return _ptr; }

    const T* get() const { return _ptr; }

    T* _ptr;
};

typedef ResetPointer<DeleteHandler> DeleteHandlerPointer;
typedef ResetPointer<OpenThreads::Mutex> GlobalMutexPointer;

OpenThreads::Mutex* Referenced::getGlobalReferencedMutex()
{
    static GlobalMutexPointer s_ReferencedGlobalMutext = new OpenThreads::Mutex;
    return s_ReferencedGlobalMutext.get();
}

// we'll implement Observer::getGlobalObserverMutex() here for convinience as ResetPointer is available.
OpenThreads::Mutex* Observer::getGlobalObserverMutex()
{
    static GlobalMutexPointer s_ReferencedGlobalMutext = new OpenThreads::Mutex(OpenThreads::Mutex::MUTEX_RECURSIVE);
    return s_ReferencedGlobalMutext.get();
}

// helper class for forcing the global mutex to be constructed when the library is loaded.
struct InitGlobalMutexes
{
    InitGlobalMutexes()
    {
        Referenced::getGlobalReferencedMutex();
        Observer::getGlobalObserverMutex();
    }
};
static InitGlobalMutexes s_initGlobalMutexes;

#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
static bool s_useThreadSafeReferenceCounting = getenv("OSG_THREAD_SAFE_REF_UNREF")!=0;
#endif
// static std::auto_ptr<DeleteHandler> s_deleteHandler(0);
static DeleteHandlerPointer s_deleteHandler(0);

static ApplicationUsageProxy Referenced_e0(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREAD_SAFE_REF_UNREF","");

void Referenced::setThreadSafeReferenceCounting(bool enableThreadSafeReferenceCounting)
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    s_useThreadSafeReferenceCounting = enableThreadSafeReferenceCounting;
#endif
}

bool Referenced::getThreadSafeReferenceCounting()
{
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    return true;
#else
    return s_useThreadSafeReferenceCounting;
#endif
}

void Referenced::setDeleteHandler(DeleteHandler* handler)
{
    s_deleteHandler.reset(handler);
}

DeleteHandler* Referenced::getDeleteHandler()
{
    return s_deleteHandler.get();
}

#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
OpenThreads::Mutex& getNumObjectMutex()
{
    static OpenThreads::Mutex s_numObjectMutex;
    return s_numObjectMutex;
}
static int s_numObjects = 0;
#endif

Referenced::Referenced():
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    _observerSet(0),
    _refCount(0)
#else
    _refMutex(0),
    _refCount(0),
    _observerSet(0)
#endif
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
#ifndef ENFORCE_THREADSAFE
    if (s_useThreadSafeReferenceCounting)
#endif
        _refMutex = new OpenThreads::Mutex;
#endif

#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
        ++s_numObjects;
        printf("Object created, total num=%d\n",s_numObjects);
    }
#endif

}

Referenced::Referenced(bool threadSafeRefUnref):
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    _observerSet(0),
    _refCount(0)
#else
    _refMutex(0),
    _refCount(0),
    _observerSet(0)
#endif
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
#ifndef ENFORCE_THREADSAFE
    if (threadSafeRefUnref)
#endif
        _refMutex = new OpenThreads::Mutex;
#endif

#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
        ++s_numObjects;
        printf("Object created, total num=%d\n",s_numObjects);
    }
#endif
}

Referenced::Referenced(const Referenced&):
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    _observerSet(0),
    _refCount(0)
#else
    _refMutex(0),
    _refCount(0),
    _observerSet(0)
#endif
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
#ifndef ENFORCE_THREADSAFE
    if (s_useThreadSafeReferenceCounting)
#endif
        _refMutex = new OpenThreads::Mutex;
#endif

#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
        ++s_numObjects;
        printf("Object created, total num=%d\n",s_numObjects);
    }
#endif
}

Referenced::~Referenced()
{
#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
        --s_numObjects;
        printf("Object created, total num=%d\n",s_numObjects);
    }
#endif

    if (_refCount>0)
    {
        OSG_WARN<<"Warning: deleting still referenced object "<<this<<" of type '"<<typeid(this).name()<<"'"<<std::endl;
        OSG_WARN<<"         the final reference count was "<<_refCount<<", memory corruption possible."<<std::endl;
    }

    // signal observers that we are being deleted.
    signalObserversAndDelete(false, true, false);

    // delete the ObserverSet
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    if (_observerSet.get()) delete static_cast<ObserverSet*>(_observerSet.get());
#else
    if (_observerSet) delete static_cast<ObserverSet*>(_observerSet);
#endif

#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    if (_refMutex) delete _refMutex;
#endif
}

ObserverSet* Referenced::getOrCreateObserverSet() const
{
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet.get());
    while (0 == observerSet) {
        ObserverSet* newObserverSet = new ObserverSet;
        if (!_observerSet.assign(newObserverSet, 0))
            delete newObserverSet;
        observerSet = static_cast<ObserverSet*>(_observerSet.get());
    }
    return observerSet;
#else
    if (_refMutex)
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
        if (!_observerSet) _observerSet = new ObserverSet;
        return static_cast<ObserverSet*>(_observerSet);
    }
    else
    {
        if (!_observerSet) _observerSet = new ObserverSet;
        return static_cast<ObserverSet*>(_observerSet);
    }
#endif
}

void Referenced::signalObserversAndDelete(bool signalUnreferened, bool signalDelete, bool doDelete) const
{
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet.get());
#else
    ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet);
#endif

    if (observerSet)
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*(observerSet->getObserverSetMutex()));
        if (signalUnreferened)
        {
            observerSet->signalObjectUnreferenced(const_cast<Referenced*>(this));
        }

        if (_refCount!=0)
        {
            OSG_NOTICE<<"Referenced::signalObserversAndDelete(,,) disabling delete as _refCount="<<_refCount<<std::endl;
            return;
        }

        if (signalDelete)
        {
            observerSet->signalObjectDeleted(const_cast<Referenced*>(this));
        }
    }

    if (doDelete && _refCount==0)
    {
        //OSG_NOTICE<<"Referenced::signalObserversAndDelete(,,) doing delete as _refCount="<<_refCount<<std::endl;
        if (getDeleteHandler()) deleteUsingDeleteHandler();
        else delete this;
    }
}

void Referenced::setThreadSafeRefUnref(bool threadSafe)
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    if (threadSafe)
    {
        if (!_refMutex)
        {
            // we want thread safe ref()/unref() so assign a mutex
            _refMutex = new OpenThreads::Mutex;
        }
    }
    else
    {
        if (_refMutex)
        {
            // we don't want thread safe ref()/unref() so remove any assigned mutex
            OpenThreads::Mutex* tmpMutexPtr = _refMutex;
            _refMutex = 0;
            delete tmpMutexPtr;
        }
    }
#endif
}

void Referenced::unref_nodelete() const
{
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
    bool needUnreferencedSignal = ((--_refCount) == 0);
#else
    bool needUnreferencedSignal = false;
    if (_refMutex)
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
        needUnreferencedSignal = ((--_refCount) == 0);
    }
    else
    {
        needUnreferencedSignal = ((--_refCount) == 0);
    }
#endif

    if (needUnreferencedSignal)
    {
        signalObserversAndDelete(true,false,false);
    }
}

void Referenced::deleteUsingDeleteHandler() const
{
    getDeleteHandler()->requestDelete(this);
}

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


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2014 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgUI/ComboBox>
#include <osgText/String>
#include <osgText/Font>
#include <osgText/Text>
#include <osg/Notify>
#include <osg/ValueObject>
#include <osg/io_utils>

using namespace osgUI;

ComboBox::ComboBox():
    _currentIndex(0)
{
}

ComboBox::ComboBox(const osgUI::ComboBox& combobox, const osg::CopyOp& copyop):
    Widget(combobox, copyop),
    _items(combobox._items)
{
}

bool ComboBox::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event)
{
    // OSG_NOTICE<<"ComboBox::handleImplementation"<<std::endl;

    osgGA::GUIEventAdapter* ea = event->asGUIEventAdapter();
    if (!ea) return false;

    bool hasFocus = getHasEventFocus() ||
                   (_popup->getVisible() && _popup->getHasEventFocus());

    if (!hasFocus)
    {
        if (ea->getEventType()==osgGA::GUIEventAdapter::PUSH && _popup->getVisible())
        {
            _popup->setVisible(false);
        }

        return false;
    }

    switch(ea->getEventType())
    {
        case(osgGA::GUIEventAdapter::SCROLL):
            if (ea->getScrollingMotion()==osgGA::GUIEventAdapter::SCROLL_DOWN)
            {
                if (getCurrentIndex()<getNumItems()-1) setCurrentIndex(getCurrentIndex()+1);
                return true;
            }
            else if (ea->getScrollingMotion()==osgGA::GUIEventAdapter::SCROLL_UP)
            {
                if (getCurrentIndex()>0) setCurrentIndex(getCurrentIndex()-1);
                return true;
            }
            break;

        case(osgGA::GUIEventAdapter::KEYDOWN):
            if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Down)
            {
                if (getCurrentIndex()<getNumItems()-1) setCurrentIndex(getCurrentIndex()+1);
                return true;
            }
            else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Up)
            {
                if (getCurrentIndex()>0) setCurrentIndex(getCurrentIndex()-1);
                return true;
            }

            break;

        case(osgGA::GUIEventAdapter::PUSH):
        {
            if (_popup->getVisible() && _popup->getHasEventFocus())
            {
                osg::Vec3d position;
                if (_popup->computeExtentsPositionInLocalCoordinates(ev, ea, position))
                {
                    position -= _popupItemOrigin;
                    position.x() /= _popupItemSize.x();
                    position.y() /= _popupItemSize.y();
                    int index = static_cast<int>(position.y());
                    if (index>=0 && index<static_cast<int>(_items.size()))
                    {
                        setCurrentIndex(index);
                    }
                }
                _popup->setVisible(false);
            }
            else if (getHasEventFocus())
            {
                _popup->setVisible(!_popup->getVisible());
            }
            else
            {
                _popup->setVisible(false);
                return false;
            }
            break;
        }
        case(osgGA::GUIEventAdapter::RELEASE):
            OSG_NOTICE<<"Button release "<<std::endl;
            break;

        default:
            break;
    }

    return false;
}

void ComboBox::enterImplementation()
{
    OSG_NOTICE<<"ComboBox enter"<<std::endl;
    if (_backgroundSwitch.valid()) _backgroundSwitch->setSingleChildOn(1);
}

void ComboBox::leaveImplementation()
{
    OSG_NOTICE<<"ComboBox leave"<<std::endl;
    if (_backgroundSwitch.valid()) _backgroundSwitch->setSingleChildOn(0);
}

void ComboBox::setCurrentIndex(unsigned int i)
{
    // OSG_NOTICE << "ComboBox::setCurrentIndex("<<i<<")"<<std::endl;
    if (_currentIndex==i) return;

    _currentIndex = i;
    if (_buttonSwitch.valid()) _buttonSwitch->setSingleChildOn(_currentIndex);

    currrentIndexChanged(_currentIndex);
}

void ComboBox::currrentIndexChanged(unsigned int i)
{
    osg::CallbackObject* co = getCallbackObject(this, "currentIndexChanged");
    if (co)
    {
        osg::Parameters inputParameters, outputParameters;
        inputParameters.push_back(new osg::UIntValueObject("index",i));
        if (co->run(this, inputParameters, outputParameters))
        {
            return;
        }
    }
    currentIndexChangedImplementation(i);
}

void ComboBox::currentIndexChangedImplementation(unsigned int i)
{
  OSG_NOTICE<<"ComboBox::currentIndexChangedImplementation("<<i<<")"<<std::endl;
}

void ComboBox::createGraphicsImplementation()
{
    Style* style = (getStyle()!=0) ? getStyle() : Style::instance().get();

    _buttonSwitch = new osg::Switch;
    _popup = new osgUI::Popup;
    _popup->setVisible(false);
    _popup->setFrameSettings(getFrameSettings());

    osg::BoundingBox extents(_extents);

    osg::ref_ptr<osg::Group> group = new osg::Group;
    bool requiresFrame = (getFrameSettings() && getFrameSettings()->getShape()!=osgUI::FrameSettings::NO_FRAME);
    float frameWidth = 0.0;
    float unFocused = 0.92;
    float withFocus = 0.97;
    osg::Vec4 frameColor(unFocused,unFocused,unFocused,1.0f);

    if (requiresFrame)
    {
        frameWidth = getFrameSettings()->getLineWidth();

        group->addChild(style->createFrame(_extents, getFrameSettings(), frameColor));
        extents.xMin() += frameWidth;
        extents.xMax() -= frameWidth;
        extents.yMin() += frameWidth;
        extents.yMax() -= frameWidth;
    }

    bool itemsHaveColor = false;
    for(Items::iterator itr = _items.begin();
        itr != _items.end();
        ++itr)
    {
        Item* item = itr->get();
        if (item->getColor().a()!=0.0f)
        {
            itemsHaveColor = true; break;
        }
    }

    // work out position of carat.
    float h = extents.yMax()-extents.yMin();
    float w = h*0.7;
    float minItemWidth = (extents.xMax()-extents.xMin())*0.5f;
    if (w>minItemWidth) w = minItemWidth;
    float xDivision = extents.xMax()-w;

    osg::BoundingBox backgroundExtents = extents;
    osg::BoundingBox iconExtents = backgroundExtents;
    iconExtents.xMin() = xDivision;
    extents.xMax() = xDivision;

    if (itemsHaveColor)
    {
        backgroundExtents.xMin() = xDivision;
    }

    OSG_NOTICE<<"itemsHaveColor = "<<itemsHaveColor<<std::endl;

    // clear background of edit region
    _backgroundSwitch = new osg::Switch;
    _backgroundSwitch->addChild(style->createPanel(backgroundExtents, osg::Vec4(unFocused, unFocused, unFocused, 1.0)));
    _backgroundSwitch->addChild(style->createPanel(backgroundExtents, osg::Vec4(withFocus, withFocus, withFocus,1.0)));
    _backgroundSwitch->setSingleChildOn(0);

    // assign carat
    group->addChild(_backgroundSwitch.get());

    group->addChild(_buttonSwitch.get());

    //group->addChild(style->createIcon(iconExtents, "cow.osgt", osg::Vec4(withFocus, withFocus, withFocus,1.0)));
    group->addChild(style->createIcon(iconExtents, "Images/osg64.png", osg::Vec4(withFocus, withFocus, withFocus,1.0)));

    if (!_items.empty())
    {

        float margin = (extents.yMax()-extents.yMin())*0.1f;
        // float itemWidth = (_extents.xMax()-_extents.xMin()) - 2.0f*frameWidth;
        float itemHeight = (_extents.yMax()-_extents.yMin()) - 2.0f*frameWidth;
        float popupHeight = (itemHeight)* _items.size() + margin*static_cast<float>(_items.size()-1) + 2.0f*frameWidth;
        float popupTop = _extents.yMin()-frameWidth-margin*1.0f;
        float popupLeft = _extents.xMin();
        float popupRight = _extents.xMax();

        osg::BoundingBox popupExtents(popupLeft, popupTop-popupHeight, _extents.zMin(), popupRight, popupTop, _extents.zMax());
        _popup->setExtents(popupExtents);

        osg::BoundingBox popupItemExtents(popupExtents.xMin()+frameWidth, popupTop-frameWidth-itemHeight, popupExtents.zMin(), popupExtents.xMax()-frameWidth, popupTop-frameWidth, popupExtents.zMax());

        _popupItemOrigin.set(popupItemExtents.xMin(), popupItemExtents.yMax(), popupExtents.zMin());
        _popupItemSize.set(popupItemExtents.xMax()-popupItemExtents.xMin(), -(itemHeight+margin), 0.0);

        unsigned int index = 0;
        for(Items::iterator itr = _items.begin();
            itr != _items.end();
            ++itr, ++index)
        {
            Item* item = itr->get();
            OSG_NOTICE<<"Creating item "<<item->getText()<<", "<<item->getColor()<<std::endl;

            // setup graphics for button
            {
                osg::ref_ptr<osg::Group> group = new osg::Group;
                if (item->getColor().a()!=0.0f) group->addChild( style->createPanel(extents, item->getColor()) );
                if (!item->getText().empty()) group->addChild( style->createText(extents, getAlignmentSettings(), getTextSettings(), item->getText()) );
                _buttonSwitch->addChild(group.get());
            }

            // setup graphics for popup
            {
                osg::ref_ptr<osg::Group> group = new osg::Group;

                if (item->getColor().a()!=0.0f) group->addChild( style->createPanel(popupItemExtents, item->getColor()) );
                if (!item->getText().empty()) group->addChild( style->createText(popupItemExtents, getAlignmentSettings(), getTextSettings(), item->getText()) );
                _popup->addChild(group.get());

                popupItemExtents.yMin() -= (itemHeight+margin);
                popupItemExtents.yMax() -= (itemHeight+margin);
            }

        }

    }
    else
    {
        _buttonSwitch->addChild( style->createPanel(_extents, frameColor) );
    }

    _buttonSwitch->setSingleChildOn(_currentIndex);

    style->setupClipStateSet(_extents, getOrCreateWidgetStateSet());

    setGraphicsSubgraph(0, group.get());
    addChild(_popup.get());
}
<commit_msg>Fixed shadows warning<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2014 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgUI/ComboBox>
#include <osgText/String>
#include <osgText/Font>
#include <osgText/Text>
#include <osg/Notify>
#include <osg/ValueObject>
#include <osg/io_utils>

using namespace osgUI;

ComboBox::ComboBox():
    _currentIndex(0)
{
}

ComboBox::ComboBox(const osgUI::ComboBox& combobox, const osg::CopyOp& copyop):
    Widget(combobox, copyop),
    _items(combobox._items)
{
}

bool ComboBox::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event)
{
    // OSG_NOTICE<<"ComboBox::handleImplementation"<<std::endl;

    osgGA::GUIEventAdapter* ea = event->asGUIEventAdapter();
    if (!ea) return false;

    bool hasFocus = getHasEventFocus() ||
                   (_popup->getVisible() && _popup->getHasEventFocus());

    if (!hasFocus)
    {
        if (ea->getEventType()==osgGA::GUIEventAdapter::PUSH && _popup->getVisible())
        {
            _popup->setVisible(false);
        }

        return false;
    }

    switch(ea->getEventType())
    {
        case(osgGA::GUIEventAdapter::SCROLL):
            if (ea->getScrollingMotion()==osgGA::GUIEventAdapter::SCROLL_DOWN)
            {
                if (getCurrentIndex()<getNumItems()-1) setCurrentIndex(getCurrentIndex()+1);
                return true;
            }
            else if (ea->getScrollingMotion()==osgGA::GUIEventAdapter::SCROLL_UP)
            {
                if (getCurrentIndex()>0) setCurrentIndex(getCurrentIndex()-1);
                return true;
            }
            break;

        case(osgGA::GUIEventAdapter::KEYDOWN):
            if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Down)
            {
                if (getCurrentIndex()<getNumItems()-1) setCurrentIndex(getCurrentIndex()+1);
                return true;
            }
            else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Up)
            {
                if (getCurrentIndex()>0) setCurrentIndex(getCurrentIndex()-1);
                return true;
            }

            break;

        case(osgGA::GUIEventAdapter::PUSH):
        {
            if (_popup->getVisible() && _popup->getHasEventFocus())
            {
                osg::Vec3d position;
                if (_popup->computeExtentsPositionInLocalCoordinates(ev, ea, position))
                {
                    position -= _popupItemOrigin;
                    position.x() /= _popupItemSize.x();
                    position.y() /= _popupItemSize.y();
                    int index = static_cast<int>(position.y());
                    if (index>=0 && index<static_cast<int>(_items.size()))
                    {
                        setCurrentIndex(index);
                    }
                }
                _popup->setVisible(false);
            }
            else if (getHasEventFocus())
            {
                _popup->setVisible(!_popup->getVisible());
            }
            else
            {
                _popup->setVisible(false);
                return false;
            }
            break;
        }
        case(osgGA::GUIEventAdapter::RELEASE):
            OSG_NOTICE<<"Button release "<<std::endl;
            break;

        default:
            break;
    }

    return false;
}

void ComboBox::enterImplementation()
{
    OSG_NOTICE<<"ComboBox enter"<<std::endl;
    if (_backgroundSwitch.valid()) _backgroundSwitch->setSingleChildOn(1);
}

void ComboBox::leaveImplementation()
{
    OSG_NOTICE<<"ComboBox leave"<<std::endl;
    if (_backgroundSwitch.valid()) _backgroundSwitch->setSingleChildOn(0);
}

void ComboBox::setCurrentIndex(unsigned int i)
{
    // OSG_NOTICE << "ComboBox::setCurrentIndex("<<i<<")"<<std::endl;
    if (_currentIndex==i) return;

    _currentIndex = i;
    if (_buttonSwitch.valid()) _buttonSwitch->setSingleChildOn(_currentIndex);

    currrentIndexChanged(_currentIndex);
}

void ComboBox::currrentIndexChanged(unsigned int i)
{
    osg::CallbackObject* co = getCallbackObject(this, "currentIndexChanged");
    if (co)
    {
        osg::Parameters inputParameters, outputParameters;
        inputParameters.push_back(new osg::UIntValueObject("index",i));
        if (co->run(this, inputParameters, outputParameters))
        {
            return;
        }
    }
    currentIndexChangedImplementation(i);
}

void ComboBox::currentIndexChangedImplementation(unsigned int i)
{
  OSG_NOTICE<<"ComboBox::currentIndexChangedImplementation("<<i<<")"<<std::endl;
}

void ComboBox::createGraphicsImplementation()
{
    Style* style = (getStyle()!=0) ? getStyle() : Style::instance().get();

    _buttonSwitch = new osg::Switch;
    _popup = new osgUI::Popup;
    _popup->setVisible(false);
    _popup->setFrameSettings(getFrameSettings());

    osg::BoundingBox extents(_extents);

    osg::ref_ptr<osg::Group> group = new osg::Group;
    bool requiresFrame = (getFrameSettings() && getFrameSettings()->getShape()!=osgUI::FrameSettings::NO_FRAME);
    float frameWidth = 0.0;
    float unFocused = 0.92;
    float withFocus = 0.97;
    osg::Vec4 frameColor(unFocused,unFocused,unFocused,1.0f);

    if (requiresFrame)
    {
        frameWidth = getFrameSettings()->getLineWidth();

        group->addChild(style->createFrame(_extents, getFrameSettings(), frameColor));
        extents.xMin() += frameWidth;
        extents.xMax() -= frameWidth;
        extents.yMin() += frameWidth;
        extents.yMax() -= frameWidth;
    }

    bool itemsHaveColor = false;
    for(Items::iterator itr = _items.begin();
        itr != _items.end();
        ++itr)
    {
        Item* item = itr->get();
        if (item->getColor().a()!=0.0f)
        {
            itemsHaveColor = true; break;
        }
    }

    // work out position of carat.
    float h = extents.yMax()-extents.yMin();
    float w = h*0.7;
    float minItemWidth = (extents.xMax()-extents.xMin())*0.5f;
    if (w>minItemWidth) w = minItemWidth;
    float xDivision = extents.xMax()-w;

    osg::BoundingBox backgroundExtents = extents;
    osg::BoundingBox iconExtents = backgroundExtents;
    iconExtents.xMin() = xDivision;
    extents.xMax() = xDivision;

    if (itemsHaveColor)
    {
        backgroundExtents.xMin() = xDivision;
    }

    OSG_NOTICE<<"itemsHaveColor = "<<itemsHaveColor<<std::endl;

    // clear background of edit region
    _backgroundSwitch = new osg::Switch;
    _backgroundSwitch->addChild(style->createPanel(backgroundExtents, osg::Vec4(unFocused, unFocused, unFocused, 1.0)));
    _backgroundSwitch->addChild(style->createPanel(backgroundExtents, osg::Vec4(withFocus, withFocus, withFocus,1.0)));
    _backgroundSwitch->setSingleChildOn(0);

    // assign carat
    group->addChild(_backgroundSwitch.get());

    group->addChild(_buttonSwitch.get());

    //group->addChild(style->createIcon(iconExtents, "cow.osgt", osg::Vec4(withFocus, withFocus, withFocus,1.0)));
    group->addChild(style->createIcon(iconExtents, "Images/osg64.png", osg::Vec4(withFocus, withFocus, withFocus,1.0)));

    if (!_items.empty())
    {

        float margin = (extents.yMax()-extents.yMin())*0.1f;
        // float itemWidth = (_extents.xMax()-_extents.xMin()) - 2.0f*frameWidth;
        float itemHeight = (_extents.yMax()-_extents.yMin()) - 2.0f*frameWidth;
        float popupHeight = (itemHeight)* _items.size() + margin*static_cast<float>(_items.size()-1) + 2.0f*frameWidth;
        float popupTop = _extents.yMin()-frameWidth-margin*1.0f;
        float popupLeft = _extents.xMin();
        float popupRight = _extents.xMax();

        osg::BoundingBox popupExtents(popupLeft, popupTop-popupHeight, _extents.zMin(), popupRight, popupTop, _extents.zMax());
        _popup->setExtents(popupExtents);

        osg::BoundingBox popupItemExtents(popupExtents.xMin()+frameWidth, popupTop-frameWidth-itemHeight, popupExtents.zMin(), popupExtents.xMax()-frameWidth, popupTop-frameWidth, popupExtents.zMax());

        _popupItemOrigin.set(popupItemExtents.xMin(), popupItemExtents.yMax(), popupExtents.zMin());
        _popupItemSize.set(popupItemExtents.xMax()-popupItemExtents.xMin(), -(itemHeight+margin), 0.0);

        unsigned int index = 0;
        for(Items::iterator itr = _items.begin();
            itr != _items.end();
            ++itr, ++index)
        {
            Item* item = itr->get();
            OSG_NOTICE<<"Creating item "<<item->getText()<<", "<<item->getColor()<<std::endl;

            // setup graphics for button
            {
                osg::ref_ptr<osg::Group> button_group = new osg::Group;
                if (item->getColor().a()!=0.0f) button_group->addChild( style->createPanel(extents, item->getColor()) );
                if (!item->getText().empty()) button_group->addChild( style->createText(extents, getAlignmentSettings(), getTextSettings(), item->getText()) );
                _buttonSwitch->addChild(button_group.get());
            }

            // setup graphics for popup
            {
                osg::ref_ptr<osg::Group> popup_group = new osg::Group;

                if (item->getColor().a()!=0.0f) popup_group->addChild( style->createPanel(popupItemExtents, item->getColor()) );
                if (!item->getText().empty()) popup_group->addChild( style->createText(popupItemExtents, getAlignmentSettings(), getTextSettings(), item->getText()) );
                _popup->addChild(popup_group.get());

                popupItemExtents.yMin() -= (itemHeight+margin);
                popupItemExtents.yMax() -= (itemHeight+margin);
            }

        }

    }
    else
    {
        _buttonSwitch->addChild( style->createPanel(_extents, frameColor) );
    }

    _buttonSwitch->setSingleChildOn(_currentIndex);

    style->setupClipStateSet(_extents, getOrCreateWidgetStateSet());

    setGraphicsSubgraph(0, group.get());
    addChild(_popup.get());
}
<|endoftext|>


<commit_before>#include "get.h"

void Get(const Nan::FunctionCallbackInfo<Value>& args) {
  Local<Object> record = Nan::New<Object>();

  // Ensure that we have at least the file's location
  if (args.Length() == 0)
    return Nan::ThrowRangeError("Wrong number of arguments");

  Nan::Utf8String v8_file_name(args[0]);

  std::string location = std::string(*v8_file_name);

  // Raise if the file actually doesn't exist
  if (!exist(location))
    return Nan::ThrowError("The audio file doesn't exist");

  TagLib::FileRef f(location.c_str());
  TagLib::Tag *tag = f.tag();
  TagLib::AudioProperties *properties = f.audioProperties();

  TagLib::String title  = tag->title();
  TagLib::String artist = tag->artist();
  TagLib::String album  = tag->album();
  TagLib::String genre  = tag->genre();

  // std::string title;

  // Set the default title based on the file's location
  // if there's no tags for the file.
  if (!title.length()) {
    std::string::size_type slash  = location.rfind('/');
    std::string::size_type dot    = location.rfind('.');

    std::string default_title = location.substr(slash+1, dot - slash - 1);

    for (std::string::iterator it = default_title.begin(); it != default_title.end(); it++)
      title += *it;
  }

  record->Set(string("title"),    string(title.toCString()));
  record->Set(string("artist"),   string(artist.toCString()));
  record->Set(string("album"),    string(album.toCString()));
  record->Set(string("genre"),    string(genre.toCString()));
  record->Set(string("id"),       string(location));
  record->Set(string("track"),    Nan::New(tag->track()));
  record->Set(string("duration"), Nan::New(properties->length()));

  if (args.Length() > 1) {
    Nan::Utf8String v8_cover_folder(args[1]);
    std::string cover_folder = std::string(*v8_cover_folder);

    //   1 ('/')
    // + 3 (" - ")
    // + 1 ('.')
    // + 3 ("png" or "jpg")
    // + 1 ('\0')
    // = 9
    std::string img_path;
    img_path.reserve(cover_folder.length() + artist.length() + 9 +
                     album.length() ? album.length() : title.length());

    img_path.append(cover_folder);
    img_path += '/';

    // Copy the name of the artist making sure that we are
    // only copying alpha-numeric chars in order to avoid
    // any filesystem errors creating the file.
    if (artist.length()) {
      for (TagLib::String::Iterator it = artist.begin(); it != artist.end(); it++) {
        if (isalnum(*it) || isspace(*it))
          img_path += *it;
      }

      img_path.append(" - ");
    }

    // Ditto `artist` but for the album or the title variable;
    // we only want the alpha-numeric chars.
    if (album.size())
      for (TagLib::String::Iterator it = album.begin(); it != album.end(); it++) {
        if (isalnum(*it) || isspace(*it))
          img_path += *it;
      }
    else
      for (TagLib::String::Iterator it = title.begin(); it != title.end(); it++) {
        if (isalnum(*it) || isspace(*it))
          img_path += *it;
      }

    if (image_exist(&img_path)) {
      record->Set(string("icon"), string(img_path.c_str()));
    } else {
      std::string extension = location.substr(location.length() - 3, 3);

      if (extension == "mp3")
        mp3Picture(location, img_path, record);
      else if (extension == "m4a")
        mp4Picture(location, img_path, record);
    }
  }

  args.GetReturnValue().Set(record);
}

void mp3Picture(std::string location, std::string img_path, Local<Object> record) {
  TagLib::MPEG::File mp3_file(location.c_str());
  TagLib::ID3v2::Tag *mp3_tag = mp3_file.ID3v2Tag(true);
  TagLib::ID3v2::FrameList pictures = mp3_tag->frameList("APIC");

  if (pictures.isEmpty())
    return;

  TagLib::ID3v2::AttachedPictureFrame *picture_frame;

  for (TagLib::ID3v2::FrameList::ConstIterator it = pictures.begin(); it != pictures.end(); it++) {
    picture_frame = static_cast<TagLib::ID3v2::AttachedPictureFrame *> (*it);

    if (picture_frame->mimeType() == "image/png")
      img_path.append(".png");
    else
      img_path.append(".jpg");

    if (!exist(img_path)) {
      size_t image_size = picture_frame->picture().size();
      const char *data  = picture_frame->picture().data();
      FILE *cover_file  = fopen(img_path.c_str(), "wb");

      fwrite(data, image_size, 1, cover_file);
      fclose(cover_file);
    }

    record->Set(string("icon"), string(img_path));
  }
}

void mp4Picture(std::string location, std::string img_path, Local<Object> record) {
  TagLib::MP4::File mp4_file(location.c_str());
  TagLib::MP4::Tag *mp4_tag = mp4_file.tag();
  TagLib::MP4::ItemListMap items_list_map = mp4_tag->itemListMap();
  TagLib::MP4::Item cover_item = items_list_map["covr"];
  TagLib::MP4::CoverArtList covert_art_list = cover_item.toCoverArtList();

  if (covert_art_list.isEmpty())
    return;

  TagLib::MP4::CoverArt cover_art = covert_art_list.front();

  img_path.append(".jpg");

  if (!exist(img_path)) {
    size_t image_size = cover_art.data().size();
    const char *data  = cover_art.data().data();
    FILE *cover_file  = fopen(img_path.c_str(), "wb");

    fwrite(data, image_size, 1, cover_file);
    fclose(cover_file);
  }

  record->Set(string("icon"), string(img_path));
}
<commit_msg>Avoid segmentation faults reading M4A cover art<commit_after>#include "get.h"

void Get(const Nan::FunctionCallbackInfo<Value>& args) {
  Local<Object> record = Nan::New<Object>();

  // Ensure that we have at least the file's location
  if (args.Length() == 0)
    return Nan::ThrowRangeError("Wrong number of arguments");

  Nan::Utf8String v8_file_name(args[0]);

  std::string location = std::string(*v8_file_name);

  // Raise if the file actually doesn't exist
  if (!exist(location))
    return Nan::ThrowError("The audio file doesn't exist");

  TagLib::FileRef f(location.c_str());
  TagLib::Tag *tag = f.tag();
  TagLib::AudioProperties *properties = f.audioProperties();

  TagLib::String title  = tag->title();
  TagLib::String artist = tag->artist();
  TagLib::String album  = tag->album();
  TagLib::String genre  = tag->genre();

  // std::string title;

  // Set the default title based on the file's location
  // if there's no tags for the file.
  if (!title.length()) {
    std::string::size_type slash  = location.rfind('/');
    std::string::size_type dot    = location.rfind('.');

    std::string default_title = location.substr(slash+1, dot - slash - 1);

    for (std::string::iterator it = default_title.begin(); it != default_title.end(); it++)
      title += *it;
  }

  record->Set(string("title"),    string(title.toCString()));
  record->Set(string("artist"),   string(artist.toCString()));
  record->Set(string("album"),    string(album.toCString()));
  record->Set(string("genre"),    string(genre.toCString()));
  record->Set(string("id"),       string(location));
  record->Set(string("track"),    Nan::New(tag->track()));
  record->Set(string("duration"), Nan::New(properties->length()));

  if (args.Length() > 1) {
    Nan::Utf8String v8_cover_folder(args[1]);
    std::string cover_folder = std::string(*v8_cover_folder);

    //   1 ('/')
    // + 3 (" - ")
    // + 1 ('.')
    // + 3 ("png" or "jpg")
    // + 1 ('\0')
    // = 9
    std::string img_path;
    img_path.reserve(cover_folder.length() + artist.length() + 9 +
                     album.length() ? album.length() : title.length());

    img_path.append(cover_folder);
    img_path += '/';

    // Copy the name of the artist making sure that we are
    // only copying alpha-numeric chars in order to avoid
    // any filesystem errors creating the file.
    if (artist.length()) {
      for (TagLib::String::Iterator it = artist.begin(); it != artist.end(); it++) {
        if (isalnum(*it) || isspace(*it))
          img_path += *it;
      }

      img_path.append(" - ");
    }

    // Ditto `artist` but for the album or the title variable;
    // we only want the alpha-numeric chars.
    if (album.size())
      for (TagLib::String::Iterator it = album.begin(); it != album.end(); it++) {
        if (isalnum(*it) || isspace(*it))
          img_path += *it;
      }
    else
      for (TagLib::String::Iterator it = title.begin(); it != title.end(); it++) {
        if (isalnum(*it) || isspace(*it))
          img_path += *it;
      }

    if (image_exist(&img_path)) {
      record->Set(string("icon"), string(img_path.c_str()));
    } else {
      std::string extension = location.substr(location.length() - 3, 3);

      if (extension == "mp3")
        mp3Picture(location, img_path, record);
      else if (extension == "m4a")
        mp4Picture(location, img_path, record);
    }
  }

  args.GetReturnValue().Set(record);
}

void mp3Picture(std::string location, std::string img_path, Local<Object> record) {
  TagLib::MPEG::File mp3_file(location.c_str());
  TagLib::ID3v2::Tag *mp3_tag = mp3_file.ID3v2Tag(true);
  TagLib::ID3v2::FrameList pictures = mp3_tag->frameList("APIC");

  if (pictures.isEmpty())
    return;

  TagLib::ID3v2::AttachedPictureFrame *picture_frame;

  for (TagLib::ID3v2::FrameList::ConstIterator it = pictures.begin(); it != pictures.end(); it++) {
    picture_frame = static_cast<TagLib::ID3v2::AttachedPictureFrame *> (*it);

    if (picture_frame->mimeType() == "image/png")
      img_path.append(".png");
    else
      img_path.append(".jpg");

    if (!exist(img_path)) {
      size_t image_size = picture_frame->picture().size();
      const char *data  = picture_frame->picture().data();
      FILE *cover_file  = fopen(img_path.c_str(), "wb");

      fwrite(data, image_size, 1, cover_file);
      fclose(cover_file);
    }

    record->Set(string("icon"), string(img_path));
  }
}

void mp4Picture(std::string location, std::string img_path, Local<Object> record) {
  TagLib::MP4::File mp4_file(location.c_str());
  TagLib::MP4::Tag *mp4_tag = mp4_file.tag();

  if (!mp4_tag->contains("covr"))
    return;

  TagLib::MP4::CoverArtList covert_art_list = mp4_tag->item("covr").toCoverArtList();

  if (covert_art_list.isEmpty())
    return;

  TagLib::MP4::CoverArt cover_art = covert_art_list[0];

  img_path.append(".jpg");

  if (!exist(img_path)) {
    size_t image_size = cover_art.data().size();
    const char *data  = cover_art.data().data();
    FILE *cover_file  = fopen(img_path.c_str(), "wb");

    fwrite(data, image_size, 1, cover_file);
    fclose(cover_file);
  }

  record->Set(string("icon"), string(img_path));
}
<|endoftext|>


<commit_before>#include <QApplication>
#include <QFontDatabase>
#include <QtGlobal>
#include <QFile>
#include <QCommandLineParser>
#include <QFileInfo>
#include <QDir>
#include "neovimconnector.h"
#include "mainwindow.h"
#include "app.h"

/// A log handler for Qt messages, all messages are dumped into the file
/// passed via the NVIM_QT_LOG variable. Some information is only available
/// in debug builds (e.g. qDebug is only called in debug builds).
///
/// In UNIX Qt prints messages to the console output, but in Windows this is
/// the only way to get Qt's debug/warning messages.
void logger(QtMsgType type, const QMessageLogContext& ctx, const QString& msg)
{
	QFile logFile(qgetenv("NVIM_QT_LOG"));
	if (logFile.open(QIODevice::Append | QIODevice::Text)) {
		QTextStream stream(&logFile);
		stream << msg << "\n";
	}
}

#ifdef Q_OS_MAC
bool getLoginEnvironment(const QString& path)
{
	QProcess proc;
	proc.start(path, {"-l", "-c", "env", "-i"});
	if (!proc.waitForFinished()) {
		qDebug() << "Failed to execute shell to get environemnt" << path;
		return false;
	}

	QByteArray out = proc.readAllStandardOutput();
	foreach(const QByteArray& item, out.split('\n')) {
		int index = item.indexOf('=');
		if (index > 0) {
			qputenv(item.mid(0, index), item.mid(index+1));
			qDebug() << item.mid(0, index) << item.mid(index+1);
		}
	}
	return true;
}

void loadLoginEnvironmen()
{
	QByteArray shellPath = qgetenv("SHELL");
	if (!getLoginEnvironment(shellPath)) {
		getLoginEnvironment("/bin/bash");
	}
}
#endif

int main(int argc, char **argv)
{
	NeovimQt::App app(argc, argv);
	app.setApplicationDisplayName("Neovim");
	app.setWindowIcon(QIcon(":/neovim.png"));

	if (!qgetenv("NVIM_QT_LOG").isEmpty()) {
		qInstallMessageHandler(logger);
	}

	QCommandLineParser parser;
	parser.addOption(QCommandLineOption("embed",
		QCoreApplication::translate("main", "Communicate with Neovim over stdin/out")));
	parser.addOption(QCommandLineOption("nvim",
		QCoreApplication::translate("main", "nvim executable path"),
		QCoreApplication::translate("main", "nvim_path"),
		"nvim"));
	parser.addOption(QCommandLineOption("server",
		QCoreApplication::translate("main", "Connect to existing Neovim instance"),
		QCoreApplication::translate("main", "addr")));
	parser.addOption(QCommandLineOption("geometry",
		QCoreApplication::translate("main", "Initial window geometry"),
		QCoreApplication::translate("main", "geometry")));
	parser.addOption(QCommandLineOption("maximized",
		QCoreApplication::translate("main", "Maximize the window on startup")));
	parser.addOption(QCommandLineOption("fullscreen",
		QCoreApplication::translate("main", "Open the window in fullscreen on startup")));
	parser.addPositionalArgument("file",
		QCoreApplication::translate("main", "Edit specified file(s)"), "[file...]");
	parser.addPositionalArgument("...", "Additional arguments are fowarded to Neovim", "[-- ...]");
	parser.addHelpOption();

	int sep = app.arguments().indexOf("--");
	QStringList neovimArgs;
	neovimArgs << "--cmd";
	neovimArgs << "set termguicolors";
	if (sep != -1) {
		QStringList args = app.arguments().mid(0, sep);
		neovimArgs += app.arguments().mid(sep+1);
		parser.process(args);
	} else {
		parser.process(app.arguments());
	}

	if (parser.isSet("help")) {
		parser.showHelp();
	}

#ifdef Q_OS_MAC
	// In Mac OS X we can be running off a bundle in which case the user
	// shell environment variabls ($PATH, etc) are not set - try to load them
	loadLoginEnvironmen();
#endif

	NeovimQt::NeovimConnector *c;
	if (parser.isSet("embed")) {
		c = NeovimQt::NeovimConnector::fromStdinOut();
	} else {
		if (parser.isSet("server")) {
			QString server = parser.value("server");
			c = NeovimQt::NeovimConnector::connectToNeovim(server);
		} else {
			auto path = qgetenv("NVIM_QT_RUNTIME_PATH");
			if (QFileInfo(path).isDir()) {
				neovimArgs.insert(0, "--cmd");
				neovimArgs.insert(1, QString("set rtp+=%1")
						.arg(QString::fromLocal8Bit(path)));
			}
#ifdef NVIM_QT_RUNTIME_PATH
			else if (QFileInfo(NVIM_QT_RUNTIME_PATH).isDir()) {
				neovimArgs.insert(0, "--cmd");
				neovimArgs.insert(1, QString("set rtp+=%1")
						.arg(NVIM_QT_RUNTIME_PATH));
			} else
#endif
			{
				// Look for the runtime relative to the nvim-qt binary
				QDir d = QFileInfo(QCoreApplication::applicationDirPath()).dir();
#ifdef Q_OS_MAC
				// within the bundle at ../Resources/runtime
				d.cd("Resources");
				d.cd("runtime");
#else
				// ../share/nvim-qt/runtime
				d.cd("share");
				d.cd("nvim-qt");
				d.cd("runtime");
#endif

				if (d.exists()) {
					neovimArgs.insert(0, "--cmd");
					neovimArgs.insert(1, QString("set rtp+=%1")
							.arg(d.path()));
				}
			}

			// Pass positional file arguments to Neovim
			neovimArgs.append(parser.positionalArguments());
			c = NeovimQt::NeovimConnector::spawn(neovimArgs, parser.value("nvim"));
		}
	}

#ifdef NEOVIMQT_GUI_WIDGET
	NeovimQt::Shell *win = new NeovimQt::Shell(c);
	win->show();
	if (parser.isSet("fullscreen")) {
		win->showFullScreen();
	} else if (parser.isSet("maximized")) {
		win->showMaximized();
	} else {
		win->show();
	}
#else
	NeovimQt::MainWindow *win = new NeovimQt::MainWindow(c);

	QObject::connect(&app, SIGNAL(openFilesTriggered(const QList<QUrl>)),
		win->shell(), SLOT(openFiles(const QList<QUrl>)));

	if (parser.isSet("fullscreen")) {
		win->delayedShow(NeovimQt::MainWindow::DelayedShow::FullScreen);
	} else if (parser.isSet("maximized")) {
		win->delayedShow(NeovimQt::MainWindow::DelayedShow::Maximized);
	} else {
		win->delayedShow();
	}
#endif
	return app.exec();
}

<commit_msg>GUI: Clean up positional argument handling<commit_after>#include <QApplication>
#include <QFontDatabase>
#include <QtGlobal>
#include <QFile>
#include <QCommandLineParser>
#include <QFileInfo>
#include <QDir>
#include "neovimconnector.h"
#include "mainwindow.h"
#include "app.h"

/// A log handler for Qt messages, all messages are dumped into the file
/// passed via the NVIM_QT_LOG variable. Some information is only available
/// in debug builds (e.g. qDebug is only called in debug builds).
///
/// In UNIX Qt prints messages to the console output, but in Windows this is
/// the only way to get Qt's debug/warning messages.
void logger(QtMsgType type, const QMessageLogContext& ctx, const QString& msg)
{
	QFile logFile(qgetenv("NVIM_QT_LOG"));
	if (logFile.open(QIODevice::Append | QIODevice::Text)) {
		QTextStream stream(&logFile);
		stream << msg << "\n";
	}
}

#ifdef Q_OS_MAC
bool getLoginEnvironment(const QString& path)
{
	QProcess proc;
	proc.start(path, {"-l", "-c", "env", "-i"});
	if (!proc.waitForFinished()) {
		qDebug() << "Failed to execute shell to get environemnt" << path;
		return false;
	}

	QByteArray out = proc.readAllStandardOutput();
	foreach(const QByteArray& item, out.split('\n')) {
		int index = item.indexOf('=');
		if (index > 0) {
			qputenv(item.mid(0, index), item.mid(index+1));
			qDebug() << item.mid(0, index) << item.mid(index+1);
		}
	}
	return true;
}

void loadLoginEnvironmen()
{
	QByteArray shellPath = qgetenv("SHELL");
	if (!getLoginEnvironment(shellPath)) {
		getLoginEnvironment("/bin/bash");
	}
}
#endif

int main(int argc, char **argv)
{
	NeovimQt::App app(argc, argv);
	app.setApplicationDisplayName("Neovim");
	app.setWindowIcon(QIcon(":/neovim.png"));

	if (!qgetenv("NVIM_QT_LOG").isEmpty()) {
		qInstallMessageHandler(logger);
	}

	QCommandLineParser parser;
	parser.addOption(QCommandLineOption("nvim",
		QCoreApplication::translate("main", "nvim executable path"),
		QCoreApplication::translate("main", "nvim_path"),
		"nvim"));
	parser.addOption(QCommandLineOption("geometry",
		QCoreApplication::translate("main", "Initial window geometry"),
		QCoreApplication::translate("main", "geometry")));
	parser.addOption(QCommandLineOption("maximized",
		QCoreApplication::translate("main", "Maximize the window on startup")));
	parser.addOption(QCommandLineOption("fullscreen",
		QCoreApplication::translate("main", "Open the window in fullscreen on startup")));
	parser.addHelpOption();
	parser.addOption(QCommandLineOption("embed",
		QCoreApplication::translate("main", "Communicate with Neovim over stdin/out")));
	parser.addOption(QCommandLineOption("server",
		QCoreApplication::translate("main", "Connect to existing Neovim instance"),
		QCoreApplication::translate("main", "addr")));

	parser.addPositionalArgument("file",
		QCoreApplication::translate("main", "Edit specified file(s)"), "[file...]");
	parser.addPositionalArgument("...", "Additional arguments are fowarded to Neovim", "[-- ...]");

	int positionalMarker = app.arguments().indexOf("--");
	QStringList neovimArgs;
	neovimArgs << "--cmd";
	neovimArgs << "set termguicolors";
	if (positionalMarker != -1) {
		QStringList args = app.arguments().mid(0, positionalMarker);
		neovimArgs += app.arguments().mid(positionalMarker+1);
		parser.process(args);
	} else {
		parser.process(app.arguments());
	}

	if (parser.isSet("help")) {
		parser.showHelp();
	}

	if (parser.isSet("server") && parser.isSet("embed")) {
		qWarning() << "Options --server and --embed are mutually exclusive\n";
		parser.showHelp();
	}

#ifdef Q_OS_MAC
	// In Mac OS X we can be running off a bundle in which case the user
	// shell environment variabls ($PATH, etc) are not set - try to load them
	loadLoginEnvironmen();
#endif

	NeovimQt::NeovimConnector *c;
	if (parser.isSet("embed")) {
		if (!parser.positionalArguments().isEmpty()
				|| positionalMarker != -1) {
			qWarning() << "--embed does not accept positional arguments\n";
			parser.showHelp();
		}
		c = NeovimQt::NeovimConnector::fromStdinOut();
	} else if (parser.isSet("server")) {
		if (!parser.positionalArguments().isEmpty()
				|| positionalMarker != -1) {
			qWarning() << "--server does not accept positional arguments\n";
			parser.showHelp();
		}
		QString server = parser.value("server");
		c = NeovimQt::NeovimConnector::connectToNeovim(server);
	} else {
		auto path = qgetenv("NVIM_QT_RUNTIME_PATH");
		if (QFileInfo(path).isDir()) {
			neovimArgs.insert(0, "--cmd");
			neovimArgs.insert(1, QString("set rtp+=%1")
					.arg(QString::fromLocal8Bit(path)));
		}
#ifdef NVIM_QT_RUNTIME_PATH
		else if (QFileInfo(NVIM_QT_RUNTIME_PATH).isDir()) {
			neovimArgs.insert(0, "--cmd");
			neovimArgs.insert(1, QString("set rtp+=%1")
					.arg(NVIM_QT_RUNTIME_PATH));
		} else
#endif
		{
			// Look for the runtime relative to the nvim-qt binary
			QDir d = QFileInfo(QCoreApplication::applicationDirPath()).dir();
#ifdef Q_OS_MAC
			// within the bundle at ../Resources/runtime
			d.cd("Resources");
			d.cd("runtime");
#else
			// ../share/nvim-qt/runtime
			d.cd("share");
			d.cd("nvim-qt");
			d.cd("runtime");
#endif

			if (d.exists()) {
				neovimArgs.insert(0, "--cmd");
				neovimArgs.insert(1, QString("set rtp+=%1")
						.arg(d.path()));
			}
		}

		// Pass positional file arguments to Neovim
		neovimArgs.append(parser.positionalArguments());
		c = NeovimQt::NeovimConnector::spawn(neovimArgs, parser.value("nvim"));
	}

#ifdef NEOVIMQT_GUI_WIDGET
	NeovimQt::Shell *win = new NeovimQt::Shell(c);
	win->show();
	if (parser.isSet("fullscreen")) {
		win->showFullScreen();
	} else if (parser.isSet("maximized")) {
		win->showMaximized();
	} else {
		win->show();
	}
#else
	NeovimQt::MainWindow *win = new NeovimQt::MainWindow(c);

	QObject::connect(&app, SIGNAL(openFilesTriggered(const QList<QUrl>)),
		win->shell(), SLOT(openFiles(const QList<QUrl>)));

	if (parser.isSet("fullscreen")) {
		win->delayedShow(NeovimQt::MainWindow::DelayedShow::FullScreen);
	} else if (parser.isSet("maximized")) {
		win->delayedShow(NeovimQt::MainWindow::DelayedShow::Maximized);
	} else {
		win->delayedShow();
	}
#endif
	return app.exec();
}

<|endoftext|>


<commit_before>#include "gui_main.h"

//Error reporting will be redirected to the string err_msg.
//If an error values is returned the error message will then be in err_msg,
static QString err_msg;
static void gui_err_reporter(int err, const char* msg);

int main(int argc, char** argv)
{
	set_err_reporter(gui_err_reporter);

	QApplication app(argc, argv);
	win wnd;

	return app.exec();
}

win::win(QWidget* app) :
	QWidget(app),
	grid(this),
	err_lbl(this),
	in_txtbox(this),
	calc_btn("Calculate", this),
	totmm_lbl("Total Molar Mass:", this),
	unit_lbl("g/mol", this),
	totmm_txtbox(this),
	elem_lst(this)
{
	//setup the window
	this->setWindowTitle("chemtool");
	this->resize(300, 250);
	this->setMinimumHeight(250);
	this->setMinimumWidth(250);

	//setup the grid
	grid.setRowMinimumHeight(0, 20);
	grid.setRowMinimumHeight(2, 40);

	//setup the error label
	err_lbl.setAlignment(Qt::AlignLeft | Qt::AlignBottom);
	err_lbl.setWordWrap(true);
	grid.addWidget(&err_lbl, 0, 0, 1, 3);

	//setup the input textbox
	in_txtbox.setAlignment(Qt::AlignLeft | Qt::AlignTop);
	grid.addWidget(&in_txtbox, 1, 0, 1, 3);

	//setup the button which starts the processing
	grid.addWidget(&calc_btn, 2, 0, 1, 3, Qt::AlignCenter);
	connect(&calc_btn, SIGNAL(clicked()), this, SLOT(do_process_input()));

	//setup the output for the total molar mass
	totmm_txtbox.setReadOnly(false);
	totmm_txtbox.setAlignment(Qt::AlignRight);
	grid.addWidget(&totmm_txtbox, 3, 1, 1, 1);
	grid.addWidget(&totmm_lbl, 3, 0, 1, 1);
	grid.addWidget(&unit_lbl, 3, 2, 1, 1);

	//setup the element list
	QFont font;
	font.setStyleHint(QFont::Monospace);
	elem_lst.setFont(font);
	grid.addWidget(&elem_lst, 4, 0, 1, 3);

	this->show();
}

void win::do_process_input()
{
	if (in_txtbox.text().length() < 1)
		return;

	int err = 0;
	double tot_mm = 0.0f;
	char elem_data[BUFSIZ] = {0};

	err_lbl.setText("");
	struct elem_vec* evec = create_elem_vec(
		in_txtbox.text().toUtf8().constData());
	if (!evec){
		report_mem_err();
		goto exit;
	}

	err = process_input(in_txtbox.text().toUtf8().constData(), evec);
	//handle any errors
	if (err){
		switch (err){
		case EOOMEM:
			report_mem_err();
			break;
		case EFOPEN:
		case EDBFMT:
			QMessageBox::critical(this, "Database error", err_msg);
			break;
		case EENAME:
		case EARGFMT:
			err_lbl.setText(
				QString("%1").
				arg(err_msg));
			break;
		}
		goto exit;
	}

	//if no errors occured output all the data
	for (int i = 0; i < evec->size; i++){
		tot_mm += evec->elms[i].weight * evec->elms[i].quant;
		snprintf(elem_data, BUFSIZ, "%s%6i    %10f g/mol    %s",
			evec->elms[i].sname, evec->elms[i].quant,
			evec->elms[i].weight, evec->elms[i].lname);
		elem_lst.addItem(elem_data);
	}
	totmm_txtbox.setText(QString::number(tot_mm));

exit:
	destroy_elem_vec(evec);
}

void win::report_mem_err()
{
	//A memory allocation was unsuccesful. This is critical so inform
	//the user and exit the program.
	QMessageBox::critical(this, "Memory error", err_msg);
	QApplication::quit();
}

static void gui_err_reporter(int err, const char* msg)
{
	err_msg.clear();
	err_msg += get_base_err_msg(err);
	err_msg += msg;
}<commit_msg>Made the output for individual element data<commit_after>#include "gui_main.h"

//Error reporting will be redirected to the string err_msg.
//If an error values is returned the error message will then be in err_msg,
static QString err_msg;
static void gui_err_reporter(int err, const char* msg);

int main(int argc, char** argv)
{
	set_err_reporter(gui_err_reporter);

	QApplication app(argc, argv);
	win wnd;

	return app.exec();
}

win::win(QWidget* app) :
	QWidget(app),
	grid(this),
	err_lbl(this),
	in_txtbox(this),
	calc_btn("Calculate", this),
	totmm_lbl("Total Molar Mass:", this),
	unit_lbl("g/mol", this),
	totmm_txtbox(this),
	elem_lst(this)
{
	//setup the window
	this->setWindowTitle("chemtool");
	this->resize(350, 250);
	this->setMinimumHeight(250);
	this->setMinimumWidth(250);

	//setup the grid
	grid.setRowMinimumHeight(0, 20);
	grid.setRowMinimumHeight(2, 40);

	//setup the error label
	err_lbl.setAlignment(Qt::AlignLeft | Qt::AlignBottom);
	err_lbl.setWordWrap(true);
	grid.addWidget(&err_lbl, 0, 0, 1, 3);

	//setup the input textbox
	in_txtbox.setAlignment(Qt::AlignLeft | Qt::AlignTop);
	grid.addWidget(&in_txtbox, 1, 0, 1, 3);

	//setup the button which starts the processing
	grid.addWidget(&calc_btn, 2, 0, 1, 3, Qt::AlignCenter);
	connect(&calc_btn, SIGNAL(clicked()), this, SLOT(do_process_input()));

	//setup the output for the total molar mass
	totmm_txtbox.setReadOnly(false);
	totmm_txtbox.setAlignment(Qt::AlignRight);
	grid.addWidget(&totmm_txtbox, 3, 1, 1, 1);
	grid.addWidget(&totmm_lbl, 3, 0, 1, 1);
	grid.addWidget(&unit_lbl, 3, 2, 1, 1);

	//setup the element list
	elem_lst.setFont(QFont("monospace", 10));
	grid.addWidget(&elem_lst, 4, 0, 1, 3);

	this->show();
}

void win::do_process_input()
{
	if (in_txtbox.text().length() < 1)
		return;

	int err = 0;
	double tot_mm = 0.0f;
	char elem_data[BUFSIZ] = {0};

	err_lbl.setText("");
	struct elem_vec* evec = create_elem_vec(
		in_txtbox.text().toUtf8().constData());
	if (!evec){
		report_mem_err();
		goto exit;
	}

	err = process_input(in_txtbox.text().toUtf8().constData(), evec);
	//handle any errors
	if (err){
		switch (err){
		case EOOMEM:
			report_mem_err();
			break;
		case EFOPEN:
		case EDBFMT:
			QMessageBox::critical(this, "Database error", err_msg);
			break;
		case EENAME:
		case EARGFMT:
			err_lbl.setText(
				QString("%1").
				arg(err_msg));
			break;
		}
		goto exit;
	}

	//if no errors occured output all the data
	for (int i = 0; i < evec->size; i++){
		tot_mm += evec->elms[i].weight * evec->elms[i].quant;
		snprintf(elem_data, BUFSIZ, "%s%6i    %10f g/mol    %s",
			evec->elms[i].sname, evec->elms[i].quant,
			evec->elms[i].weight, evec->elms[i].lname);
		elem_lst.addItem(elem_data);
	}
	totmm_txtbox.setText(QString::number(tot_mm));

exit:
	destroy_elem_vec(evec);
}

void win::report_mem_err()
{
	//A memory allocation was unsuccesful. This is critical so inform
	//the user and exit the program.
	QMessageBox::critical(this, "Memory error", err_msg);
	QApplication::quit();
}

static void gui_err_reporter(int err, const char* msg)
{
	err_msg.clear();
	err_msg += get_base_err_msg(err);
	err_msg += msg;
}<|endoftext|>