<commit_before>/*
** Copyright 2012-2014 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker 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 Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <QSqlError>
#include <QSqlQuery>
#include <QVariant>
#include <sstream>
#include "com/centreon/broker/exceptions/msg.hh"
#include "test/cbd.hh"
#include "test/config.hh"
#include "test/engine.hh"
#include "test/generate.hh"
#include "test/misc.hh"
#include "test/vars.hh"

using namespace com::centreon::broker;

#define DB_NAME "broker_bbdo_multiple_connections"
#define ENGINE_COUNT 3

/**
 *  Check that multiple connections to cbd work properly.
 *
 *  @return EXIT_SUCCESS on success.
 */
int main() {
  // Error flag.
  bool error(true);

  // Variables that need cleaning.
  std::list<host> hosts[ENGINE_COUNT];
  std::list<service> services[ENGINE_COUNT];
  std::string engine_config_path[ENGINE_COUNT];
  for (unsigned int i(0); i < ENGINE_COUNT; ++i)
    engine_config_path[i] = tmpnam(NULL);
  engine daemon[ENGINE_COUNT];
  cbd broker;
  test_db db;

  try {
    // Prepare database.
    db.open(DB_NAME);
    db.set_remove_db_on_close(false);

    // Prepare monitoring engine configuration parameters.
    for (unsigned int i(0); i < 3; ++i) {
      generate_hosts(hosts[i], 1);
      generate_services(services[i], hosts[i], i + 1);
      std::string cbmod_loading;
      {
        std::ostringstream oss;
        oss << "broker_module=" << CBMOD_PATH << " "
            << PROJECT_SOURCE_DIR
            << "/test/cfg/bbdo_multiple_connections_"
            << (!i ? 0 : 1) << ".xml";
        cbmod_loading = oss.str();
      }

      // Generate monitoring engine configuration files.
      config_write(
        engine_config_path[i].c_str(),
        cbmod_loading.c_str(),
        hosts + i,
        services + i);
    }

    // Start Broker daemon.
    broker.set_config_file(
      PROJECT_SOURCE_DIR "/test/cfg/bbdo_multiple_connections_2.xml");
    broker.start();
    sleep_for(2 * MONITORING_ENGINE_INTERVAL_LENGTH);
    broker.update();

    // Start engines.
    for (unsigned int i(0); i < ENGINE_COUNT; ++i) {
      std::string engine_config_file(engine_config_path[i]);
      engine_config_file.append("/nagios.cfg");
      daemon[i].set_config_file(engine_config_file);
      daemon[i].start();
      sleep_for(2 * MONITORING_ENGINE_INTERVAL_LENGTH);
    }
    sleep_for(15 * MONITORING_ENGINE_INTERVAL_LENGTH);

    // Terminate monitoring engine.
    for (int i(ENGINE_COUNT - 1); i >= 0; --i)
      daemon[i].stop();

    // Terminate Broker daemon.
    broker.stop();

    // Check host count.
    {
      std::ostringstream query;
      query << "SELECT COUNT(host_id) FROM rt_hosts";
      QSqlQuery q(*db.storage_db());
      if (!q.exec(query.str().c_str()))
        throw (exceptions::msg() << "cannot read host count from DB: "
               << q.lastError().text().toStdString().c_str());
      if (!q.next()
          || (q.value(0).toUInt() != 2)
          || q.next())
        throw (exceptions::msg() << "invalid host count: got "
               << q.value(0).toUInt() << ", expected 2");
    }

    // Check service count.
    {
      std::ostringstream query;
      query << "SELECT COUNT(service_id) FROM rt_services";
      QSqlQuery q(*db.storage_db());
      if (!q.exec(query.str().c_str()))
        throw (exceptions::msg()
               << "cannot read service count from DB: "
               << q.lastError().text().toStdString().c_str());
      if (!q.next()
          || (q.value(0).toUInt() != 5)
          || q.next())
        throw (exceptions::msg() << "invalid service count: got "
               << q.value(0).toUInt() << ", expected 5");
    }

    // Success.
    error = false;
  }
  catch (std::exception const& e) {
    std::cerr << e.what() << std::endl;
  }
  catch (...) {
    std::cerr << "unknown exception" << std::endl;
  }

  // Cleanup.
  for (int i(ENGINE_COUNT - 1); i >= 0; --i)
  daemon[i].stop();
  broker.stop();
  for (unsigned int i(0); i < ENGINE_COUNT; ++i)
    config_remove(engine_config_path[i].c_str());
  for (unsigned int i(0); i < ENGINE_COUNT; ++i) {
    free_hosts(hosts[i]);
    free_services(services[i]);
  }

  return (error ? EXIT_FAILURE : EXIT_SUCCESS);
}
<commit_msg>Test: Fix bbdo_multiple_connections unit test.<commit_after>/*
** Copyright 2012-2014 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker 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 Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <QSqlError>
#include <QSqlQuery>
#include <QVariant>
#include <sstream>
#include "com/centreon/broker/exceptions/msg.hh"
#include "test/cbd.hh"
#include "test/config.hh"
#include "test/engine.hh"
#include "test/generate.hh"
#include "test/misc.hh"
#include "test/vars.hh"

using namespace com::centreon::broker;

#define DB_NAME "broker_bbdo_multiple_connections"
#define ENGINE_COUNT 3

/**
 *  Check that multiple connections to cbd work properly.
 *
 *  @return EXIT_SUCCESS on success.
 */
int main() {
  // Error flag.
  bool error(true);

  // Variables that need cleaning.
  std::list<host> hosts[ENGINE_COUNT];
  std::list<service> services[ENGINE_COUNT];
  std::string engine_config_path[ENGINE_COUNT];
  for (unsigned int i(0); i < ENGINE_COUNT; ++i)
    engine_config_path[i] = tmpnam(NULL);
  engine daemon[ENGINE_COUNT];
  cbd broker;
  test_db db;

  try {
    // Prepare database.
    db.open(DB_NAME);
    db.set_remove_db_on_close(false);

    // Prepare monitoring engine configuration parameters.
    for (unsigned int i(0); i < 3; ++i) {
      generate_hosts(hosts[i], 1);
      generate_services(services[i], hosts[i], i + 1);
      std::string cbmod_loading;
      {
        std::ostringstream oss;
        oss << "broker_module=" << CBMOD_PATH << " "
            << PROJECT_SOURCE_DIR
            << "/test/cfg/bbdo_multiple_connections_"
            << (!i ? 0 : 1) << ".xml";
        cbmod_loading = oss.str();
      }

      // Generate monitoring engine configuration files.
      config_write(
        engine_config_path[i].c_str(),
        cbmod_loading.c_str(),
        hosts + i,
        services + i);
    }

    // Start Broker daemon.
    broker.set_config_file(
      PROJECT_SOURCE_DIR "/test/cfg/bbdo_multiple_connections_2.xml");
    broker.start();
    sleep_for(2 * MONITORING_ENGINE_INTERVAL_LENGTH);
    broker.update();

    // Start engines.
    for (unsigned int i(0); i < ENGINE_COUNT; ++i) {
      std::string engine_config_file(engine_config_path[i]);
      engine_config_file.append("/nagios.cfg");
      daemon[i].set_config_file(engine_config_file);
      daemon[i].start();
      sleep_for(2 * MONITORING_ENGINE_INTERVAL_LENGTH);
    }
    sleep_for(15 * MONITORING_ENGINE_INTERVAL_LENGTH);

    // Terminate monitoring engine.
    for (int i(ENGINE_COUNT - 1); i >= 0; --i)
      daemon[i].stop();

    // Terminate Broker daemon.
    broker.stop();

    // Check host count.
    {
      std::ostringstream query;
      query << "SELECT COUNT(host_id) FROM rt_hosts";
      QSqlQuery q(*db.storage_db());
      if (!q.exec(query.str().c_str()))
        throw (exceptions::msg() << "cannot read host count from DB: "
               << q.lastError().text().toStdString().c_str());
      if (!q.next()
          || (q.value(0).toUInt() != 3)
          || q.next())
        throw (exceptions::msg() << "invalid host count: got "
               << q.value(0).toUInt() << ", expected 3");
    }

    // Check service count.
    {
      std::ostringstream query;
      query << "SELECT COUNT(service_id) FROM rt_services";
      QSqlQuery q(*db.storage_db());
      if (!q.exec(query.str().c_str()))
        throw (exceptions::msg()
               << "cannot read service count from DB: "
               << q.lastError().text().toStdString().c_str());
      if (!q.next()
          || (q.value(0).toUInt() != 6)
          || q.next())
        throw (exceptions::msg() << "invalid service count: got "
               << q.value(0).toUInt() << ", expected 6");
    }

    // Success.
    error = false;
  }
  catch (std::exception const& e) {
    std::cerr << e.what() << std::endl;
  }
  catch (...) {
    std::cerr << "unknown exception" << std::endl;
  }

  // Cleanup.
  for (int i(ENGINE_COUNT - 1); i >= 0; --i)
  daemon[i].stop();
  broker.stop();
  for (unsigned int i(0); i < ENGINE_COUNT; ++i)
    config_remove(engine_config_path[i].c_str());
  for (unsigned int i(0); i < ENGINE_COUNT; ++i) {
    free_hosts(hosts[i]);
    free_services(services[i]);
  }

  return (error ? EXIT_FAILURE : EXIT_SUCCESS);
}
<|endoftext|>


<commit_before>#include <limits.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <assert.h>
#include <string>
using namespace std;
typedef vector<int> VI;
typedef vector<long long> VLL;
typedef vector<bool> VB;
typedef vector<string> VS;
typedef pair<int,int> PI;
typedef vector<PI> VPI;
typedef long long int lint;

#define FOR0(i, n) for(int i = 0; i < n; i++)

#define Class_Name TheKingsFactorization
#define FuncName getVector
class Class_Name
{
   class Prime
   {
      public:
         long long prime;
         int power;
         Prime(long long int p, int pwr) : prime(p), power(pwr) {}
   };

   vector<Prime> factorize(long long n)
   {
      long long r = n;
      vector<Prime> res;
      long long sqrtn = sqrtl(n);
      for(long long int p = 2; p <= sqrtn; p++){
         int c = 0;
         while ( r % p == 0){
            c++;
            r = r / p;
         }
         if(c){
            res.push_back(Prime(p, c));
         }
         if(r == 1){
            break;
         }
      }
      if(r > 1){
         res.push_back(Prime(r,1));
      }
      return res;
   }
	public:
   vector<long long> getVector(long long N, vector<long long> p)
   {
      FOR0(i, p.size()){
         N = N/p[i];
      }
      vector<Prime> rp = factorize(N);
      FOR0(i, rp.size()){
         FOR0(j, rp[i].power){
            p.push_back(rp[i].prime);
         }
      }
      sort(p.begin(), p.end());
      return p;
   }
};

#include "../utils.cpp"
int main(int argc, char **argv)
{
	Class_Name g;
	if(argc == 2 && strstr(argv[1],".txt")){
		filename = argv[1];
	}
#if 1
	VLL a;
	lint n;
	while((n = parseLL()) != -1){
		a = parseV<lint>();
		pv( g.FuncName(n, a));
	}
#else
	VI a;
	int n;
	while((a = parseVI(),a.size()) != 0){
		n = parseInt();
		cout << g.FuncName(a,n) << "\n";
	}
#endif
	return 0;
}
<commit_msg>Fixed 643-1 1<commit_after>//passed
#include <limits.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <assert.h>
#include <string>
using namespace std;
typedef vector<int> VI;
typedef vector<long long> VLL;
typedef vector<bool> VB;
typedef vector<string> VS;
typedef pair<int,int> PI;
typedef vector<PI> VPI;
typedef long long int lint;

#define FOR0(i, n) for(int i = 0; i < n; i++)

#define Class_Name TheKingsFactorization
#define FuncName getVector
class Class_Name
{
   class Prime
   {
      public:
         long long prime;
         int power;
         Prime(long long int p, int pwr) : prime(p), power(pwr) {}
   };

/* we know that there are at max maxf factors */
   vector<Prime> factorize(long long n, int maxf)
   {
      long long r = n;
      vector<Prime> res;
      long long sqrtn = sqrtl(n);
      for(long long int p = 2; p <= sqrtn; p++){
         if(maxf == 1){ //r must be prime
            break;
         }
         int c = 0;
         while ( r % p == 0){
            c++;
            maxf--;
            r = r / p;
         }
         if(c){
            res.push_back(Prime(p, c));
         }
         if(r == 1){
            break;
         }
      }
      if(r > 1){
         res.push_back(Prime(r,1));
      }
      return res;
   }
	public:
   vector<long long> getVector(long long N, vector<long long> p)
   {
      FOR0(i, p.size()){
         N = N/p[i];
      }
      vector<Prime> rp = factorize(N, p.size());
      FOR0(i, rp.size()){
         FOR0(j, rp[i].power){
            p.push_back(rp[i].prime);
         }
      }
      sort(p.begin(), p.end());
      return p;
   }
};

#include "../utils.cpp"
int main(int argc, char **argv)
{
	Class_Name g;
	if(argc == 2 && strstr(argv[1],".txt")){
		filename = argv[1];
	}
#if 1
	VLL a;
	lint n;
	while((n = parseLL()) != -1){
		a = parseV<lint>();
		pv( g.FuncName(n, a));
	}
#else
	VI a;
	int n;
	while((a = parseVI(),a.size()) != 0){
		n = parseInt();
		cout << g.FuncName(a,n) << "\n";
	}
#endif
	return 0;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016, https://github.com/zhatalk
 *  All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "dal/user_sequence_dao_impl.h"

UserSequenceDAO& UserSequenceDAO::GetInstance() {
  static UserSequenceDAOImpl impl;
  return impl;
}

int64_t UserSequenceDAOImpl::Create(UserSequenceDO& user_sequence) {
  return DoStorageInsertID("nebula_engine",
                           [&](std::string& query_string) {
                             db::QueryParam p;
                             p.AddParam(user_sequence.user_id.c_str());
                             p.AddParam(&user_sequence.seq);
                             p.AddParam(&user_sequence.header);
                             // p.AddParamEsc(user_sequence.data.c_str());
                             p.AddParam(&user_sequence.created_at);

                             db::MakeQueryString("INSERT INTO user_sequence"
                                                 "(user_id,seq,header,data,created_at)"
                                                 " VALUES "
                                                 "(:1,:2,:3,'testing',:4)",
                                                 &p,
                                                 &query_string);
                           });
}
<commit_msg>benqi: user_sequence表data字段修改为blob类型<commit_after>/*
 *  Copyright (c) 2016, https://github.com/zhatalk
 *  All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "dal/user_sequence_dao_impl.h"

UserSequenceDAO& UserSequenceDAO::GetInstance() {
  static UserSequenceDAOImpl impl;
  return impl;
}

int64_t UserSequenceDAOImpl::Create(UserSequenceDO& user_sequence) {
  return DoStorageInsertID("nebula_engine",
                           [&](std::string& query_string) {
                             db::QueryParam p;
                             p.AddParam(user_sequence.user_id.c_str());
                             p.AddParam(&user_sequence.seq);
                             p.AddParam(&user_sequence.header);
                             p.AddParamEsc(user_sequence.data.c_str());
                             p.AddParam(&user_sequence.created_at);

                             db::MakeQueryString("INSERT INTO user_sequence"
                                                 "(user_id,seq,header,data,created_at)"
                                                 " VALUES "
                                                 "(:1,:2,:3,:4,:5)",
                                                 &p,
                                                 &query_string);
                           });
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
**      following disclaimer in the documentation and/or other materials provided with the distribution.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "nodes/Reference.h"
#include "commands/FieldSet.h"
#include "model/Model.h"
#include "ModelException.h"
#include "NameText.h"

#include "ModelBase/src/nodes/TypedListDefinition.h"
DEFINE_TYPED_LIST(Model::Reference)

namespace Model {

NODE_DEFINE_TYPE_REGISTRATION_METHODS(Reference)

QSet<Reference*> Reference::pendingResolution_;

Reference::Reference(Node *parent) : Super(parent)
{
	if (parent && parent->model()) pendingResolution_.insert(this);
}

Reference::Reference(Node *parent, PersistentStore &store, bool) : Super(parent)
{
	name_ = store.loadReferenceValue(this);
	if (state_ == ReferenceNeedsToBeResolved && parent && parent->model())
		pendingResolution_.insert(this);
}

Reference::~Reference()
{
	pendingResolution_.remove(this);
}

void Reference::setName(const QString &name)
{
	if (name != name_)
	{
		execute(new FieldSet<QString> (this, name_, name));
		target_ = nullptr;
		setResolutionNeeded();
	}
}

Node* Reference::computeTarget() const
{
	Q_ASSERT(false && "Should not call Reference::computeTarget()");
	return nullptr;
}

bool Reference::resolveHelper(bool indirect)
{
	// TODO this is not multithread friendly.
	if (state_ != ReferenceNeedsToBeResolved) return isResolved();
	state_ = ReferenceIsBeingResolved;

	auto newTarget = computeTarget();

	Q_ASSERT(!newTarget || (newTarget->definesSymbol() && newTarget->symbolName() == name_));

	auto oldTarget = target_;
	target_ = newTarget;

	if (target_ || !indirect)
	{
		// This is needed because of the following situation.
		// We are resolving a reference A, and during the process we explore reference B, needed for the resolution of A,
		// and reference C, which is not needed for the resolution of A. All references but A will be explored indirectly.
		// It could happen that to resolve C properly we need to resolve A first. Therefore when failing to resolve a
		// reference that is explored indirectly, we shouldn't assume that resolution will fail.
		pendingResolution_.remove(this);
		state_ = ReferenceEstablished;
	}
	else state_ = ReferenceNeedsToBeResolved;

	if (oldTarget != target_) targetChanged(oldTarget);

	return isResolved();
}

void Reference::targetChanged(Node*){}

void Reference::save(PersistentStore &store) const
{
	store.saveReferenceValue(name_, target_);
}

void Reference::load(PersistentStore &store)
{
	// TODO: Implement reference loading properly.
	throw ModelException("Loading references outside a Reference constructor is not properly implemented yet");

	if (store.currentNodeType() != typeName())
		throw ModelException("Trying to load a Reference node from an incompatible node type " + store.currentNodeType());

	setName( store.loadReferenceValue(this) );
}

Node* Reference::target()
{
	if (state_ == ReferenceNeedsToBeResolved) resolveHelper(true);
	return state_ == ReferenceEstablished ? target_ : nullptr;
}

void Reference::setResolutionNeeded()
{
	state_ = ReferenceNeedsToBeResolved;
	pendingResolution_.insert(this);
}

template<class NodeType>
void Reference::forAll(Node* subTree, Node* avoid, std::function<void (NodeType*)> function)
{
	if (subTree)
	{
		QList<Node*> stack;
		stack << subTree;
		while (!stack.isEmpty())
		{
			auto top = stack.takeLast();
			if (top == avoid) continue;

			if (auto node = DCast<NodeType>(top) ) function(node);
			else stack.append(top->children());
		}
	}
}

void Reference::unresolveAll(Node* subTree, bool markForResolution)
{
	if (markForResolution)
		forAll<Reference>(subTree, nullptr, [](Reference* ref) { ref->setResolutionNeeded();});
	else
		forAll<Reference>(subTree, nullptr, [](Reference* ref) { ref->state_ = ReferenceNeedsToBeResolved; });
}

void Reference::unresolveNames(Node* subTree, bool markForResolution, const QSet<QString>& names)
{
	if (markForResolution)
		forAll<Reference>(subTree, nullptr, [=](Reference* ref)
				{ if (names.contains(ref->name())) ref->setResolutionNeeded();});
	else
		forAll<Reference>(subTree, nullptr, [=](Reference* ref)
				{ if (names.contains(ref->name())) ref->state_ = ReferenceNeedsToBeResolved; });
}

void Reference::unresolveIfNameIntroduced(Node* subTreeToUnresolve, bool markForResolution,
		Node* subTreeToLookForNewNames)
{
	QSet<QString> names;
	forAll<NameText>(subTreeToLookForNewNames, nullptr, [&names](NameText* name){ names.insert(name->get());});

	if (markForResolution)
		forAll<Reference>(subTreeToUnresolve, subTreeToLookForNewNames, [=](Reference* ref)
				{ if (names.contains(ref->name())) ref->setResolutionNeeded();});
	else
		forAll<Reference>(subTreeToUnresolve, subTreeToLookForNewNames, [=](Reference* ref)
				{ if (names.contains(ref->name())) ref->state_ = ReferenceNeedsToBeResolved; });
}

void Reference::resolvePending()
{
	log.debug("Resolving references");

	int i = 0;
	int round = 0;
	int resolved = 0;
	auto pending = pendingResolution_;

	while(!pending.isEmpty())
	{
		log.debug("resolution round " + QString::number(round) + ", "
					 + QString::number(pendingResolution_.size()) + " references pending.");
		++round;

		for (auto r : pending)
		{
			if ( r->resolve() ) ++resolved;
			if (++i % 10000 == 0)	log.debug("Processed " + QString::number(i) + " references.");
		}

		// As a result of resolution of some references, some other references could have become invalid.
		pending = pendingResolution_;
	}

	log.debug("Resolved a total of " + QString::number(resolved) + " references in "
				 + QString::number(round) + (round > 1 ? " rounds." : " round."));
}

}
<commit_msg>Skip reference exploration when there is nothing to resolve.<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
**      following disclaimer in the documentation and/or other materials provided with the distribution.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "nodes/Reference.h"
#include "commands/FieldSet.h"
#include "model/Model.h"
#include "ModelException.h"
#include "NameText.h"

#include "ModelBase/src/nodes/TypedListDefinition.h"
DEFINE_TYPED_LIST(Model::Reference)

namespace Model {

NODE_DEFINE_TYPE_REGISTRATION_METHODS(Reference)

QSet<Reference*> Reference::pendingResolution_;

Reference::Reference(Node *parent) : Super(parent)
{
	if (parent && parent->model()) pendingResolution_.insert(this);
}

Reference::Reference(Node *parent, PersistentStore &store, bool) : Super(parent)
{
	name_ = store.loadReferenceValue(this);
	if (state_ == ReferenceNeedsToBeResolved && parent && parent->model())
		pendingResolution_.insert(this);
}

Reference::~Reference()
{
	pendingResolution_.remove(this);
}

void Reference::setName(const QString &name)
{
	if (name != name_)
	{
		execute(new FieldSet<QString> (this, name_, name));
		target_ = nullptr;
		setResolutionNeeded();
	}
}

Node* Reference::computeTarget() const
{
	Q_ASSERT(false && "Should not call Reference::computeTarget()");
	return nullptr;
}

bool Reference::resolveHelper(bool indirect)
{
	// TODO this is not multithread friendly.
	if (state_ != ReferenceNeedsToBeResolved) return isResolved();
	state_ = ReferenceIsBeingResolved;

	auto newTarget = computeTarget();

	Q_ASSERT(!newTarget || (newTarget->definesSymbol() && newTarget->symbolName() == name_));

	auto oldTarget = target_;
	target_ = newTarget;

	if (target_ || !indirect)
	{
		// This is needed because of the following situation.
		// We are resolving a reference A, and during the process we explore reference B, needed for the resolution of A,
		// and reference C, which is not needed for the resolution of A. All references but A will be explored indirectly.
		// It could happen that to resolve C properly we need to resolve A first. Therefore when failing to resolve a
		// reference that is explored indirectly, we shouldn't assume that resolution will fail.
		pendingResolution_.remove(this);
		state_ = ReferenceEstablished;
	}
	else state_ = ReferenceNeedsToBeResolved;

	if (oldTarget != target_) targetChanged(oldTarget);

	return isResolved();
}

void Reference::targetChanged(Node*){}

void Reference::save(PersistentStore &store) const
{
	store.saveReferenceValue(name_, target_);
}

void Reference::load(PersistentStore &store)
{
	// TODO: Implement reference loading properly.
	throw ModelException("Loading references outside a Reference constructor is not properly implemented yet");

	if (store.currentNodeType() != typeName())
		throw ModelException("Trying to load a Reference node from an incompatible node type " + store.currentNodeType());

	setName( store.loadReferenceValue(this) );
}

Node* Reference::target()
{
	if (state_ == ReferenceNeedsToBeResolved) resolveHelper(true);
	return state_ == ReferenceEstablished ? target_ : nullptr;
}

void Reference::setResolutionNeeded()
{
	state_ = ReferenceNeedsToBeResolved;
	pendingResolution_.insert(this);
}

template<class NodeType>
void Reference::forAll(Node* subTree, Node* avoid, std::function<void (NodeType*)> function)
{
	if (subTree)
	{
		QList<Node*> stack;
		stack << subTree;
		while (!stack.isEmpty())
		{
			auto top = stack.takeLast();
			if (top == avoid) continue;

			if (auto node = DCast<NodeType>(top) ) function(node);
			else stack.append(top->children());
		}
	}
}

void Reference::unresolveAll(Node* subTree, bool markForResolution)
{
	if (markForResolution)
		forAll<Reference>(subTree, nullptr, [](Reference* ref) { ref->setResolutionNeeded();});
	else
		forAll<Reference>(subTree, nullptr, [](Reference* ref) { ref->state_ = ReferenceNeedsToBeResolved; });
}

void Reference::unresolveNames(Node* subTree, bool markForResolution, const QSet<QString>& names)
{
	if (markForResolution)
		forAll<Reference>(subTree, nullptr, [=](Reference* ref)
				{ if (names.contains(ref->name())) ref->setResolutionNeeded();});
	else
		forAll<Reference>(subTree, nullptr, [=](Reference* ref)
				{ if (names.contains(ref->name())) ref->state_ = ReferenceNeedsToBeResolved; });
}

void Reference::unresolveIfNameIntroduced(Node* subTreeToUnresolve, bool markForResolution,
		Node* subTreeToLookForNewNames)
{
	QSet<QString> names;
	forAll<NameText>(subTreeToLookForNewNames, nullptr, [&names](NameText* name){ names.insert(name->get());});
	if (names.isEmpty()) return;

	if (markForResolution)
		forAll<Reference>(subTreeToUnresolve, subTreeToLookForNewNames, [=](Reference* ref)
				{ if (names.contains(ref->name())) ref->setResolutionNeeded();});
	else
		forAll<Reference>(subTreeToUnresolve, subTreeToLookForNewNames, [=](Reference* ref)
				{ if (names.contains(ref->name())) ref->state_ = ReferenceNeedsToBeResolved; });
}

void Reference::resolvePending()
{
	log.debug("Resolving references");

	int i = 0;
	int round = 0;
	int resolved = 0;
	auto pending = pendingResolution_;

	while(!pending.isEmpty())
	{
		log.debug("resolution round " + QString::number(round) + ", "
					 + QString::number(pendingResolution_.size()) + " references pending.");
		++round;

		for (auto r : pending)
		{
			if ( r->resolve() ) ++resolved;
			if (++i % 10000 == 0)	log.debug("Processed " + QString::number(i) + " references.");
		}

		// As a result of resolution of some references, some other references could have become invalid.
		pending = pendingResolution_;
	}

	log.debug("Resolved a total of " + QString::number(resolved) + " references in "
				 + QString::number(round) + (round > 1 ? " rounds." : " round."));
}

}
<|endoftext|>


<commit_before>#include <ncurses.h>
#include <iostream>
#include <unistd.h>
#include <algorithm>

#include "interface/Display.h"
#include "map/Level.h"
#include "map/filters/DrunkardsWalkFilter.h"
#include "core/Rand.h"

#include "entity/ecs.h"

void pause_curses(Display& display)
{
	display.pause();

	std::cout << "Paused ncurses..." << std::endl;

	sleep(4);

	std::cout << "Resuming..." << std::endl;

	sleep(1);
	display.resume();
}

bool move_pc(Level& level, PositionComponent& pc_pos, int dx, int dy)
{
	int new_x = pc_pos.x + dx;
	int new_y = pc_pos.y + dy;

	//Make sure it's in bounds
	if(0 <= new_x && new_x < level.getWidth() && 0 <= new_y && new_y < level.getHeight())
	{
		//Make sure it's passable terrain
		if(level[new_x][new_y].isPassable())
		{
			//Adjust PC's x,y coordinates
			pc_pos.x += dx;
			pc_pos.y += dy;

			return true;
		}
	}
	return false;
}

void spawn_npc(Level& level, PositionComponent& npc_pos, PositionComponent& pc_pos, int max_dist = 15)
{
	static Rand rand(time(NULL));

	int min_x = std::max(0, pc_pos.x - max_dist);
	int max_x = std::min(level.getWidth()-1, pc_pos.x + max_dist);

	int min_y = std::max(0, pc_pos.y - max_dist);
	int max_y = std::min(level.getHeight()-1, pc_pos.y + max_dist);

	do {
		npc_pos.x = rand.randInt(min_x, max_x);
		npc_pos.y = rand.randInt(min_y, max_y);
	} while(level[npc_pos.x][npc_pos.y] != FloorTile);
}

int main()
{
	Display display;
	EntityManager em;

	//Set up our ComponentManagers
	PositionManager pos_mgr;
	SpriteManager sprite_mgr;
	SkillManager skill_mgr;
	AttackManager attack_mgr;
	em.addComponentManager(&pos_mgr);
	em.addComponentManager(&sprite_mgr);
	em.addComponentManager(&skill_mgr);
	em.addComponentManager(&attack_mgr);

	//We'll also need an AttackSystem, though no setup is necessary
	AttackSystem sys_attack;

	XYPair screen = display.getScreenSize();

	//Make a map double the screen size
	int map_y = screen.y * 2;
	int map_x = screen.x * 2;
	//Generate a map
	Level cave(map_x, map_y);
	DrunkardsWalkFilter walk;
	walk.setSeed(time(NULL));
	walk.apply(cave);

	//Find a random FloorTile to put our PC on
	Entity pc = em.createEntity();
	PositionComponent pc_pos;
	SpriteComponent pc_sprite = { '@', 0, 0 };
	Rand rand(time(NULL));
	do {
		pc_pos.x = rand.randInt(0, cave.getWidth()-1);
		pc_pos.y = rand.randInt(0, cave.getHeight()-1);
	} while(cave[pc_pos.x][pc_pos.y] != FloorTile);
	pos_mgr.setComponent(pc, pc_pos);
	sprite_mgr.setComponent(pc, pc_sprite);

	//Now create a Window and viewport for our level
	WindowGeometry map_geometry = { {20,3}, {AUTO_SIZE, AUTO_SIZE} };
	Window map = display.addWindow(cave, map_geometry);

	//Geometries for our top and left Windows
	WindowGeometry top_geometry = { {0,0}, {AUTO_SIZE, 3} };
	WindowGeometry left_geometry = { { 0, 3 }, {20, AUTO_SIZE} };
	//And now create them
	Window top = display.addWindow(top_geometry);
	Window left = display.addWindow(left_geometry);

	//top.addBorder();
	//left.addBorder();

	//New set up our RenderSystem
	RenderSystem render(&display, map);

	display.add(top, mkXYPair(1,0), "Message Panel");
	display.add(left, mkXYPair(1,0), "Stat Panel");

	//Center the map viewport on the PC
	//map.center(pc_pos.x, pc_pos.y);

	//Let's display some map display stats
	//Display our view's X and Y coordinates
	//wm.getWindow(1)->add(1, 2, "View Position:");
	//wm.getWindow(1)->add(1, 3, "X:     ");
	//wm.getWindow(1)->addInt(4, 3, map.getViewX());
	//wm.getWindow(1)->add(1, 4, "Y:     ");
	//wm.getWindow(1)->addInt(4, 4, map.getViewY());

	//Display map size
	//wm.getWindow(1)->add(1, 6, "Map Size:");
	//wm.getWindow(1)->add(1, 7, "W:");
	//wm.getWindow(1)->addInt(4, 7, cave.getWidth());
	//wm.getWindow(1)->add(1, 8, "H:");
	//wm.getWindow(1)->addInt(4, 8, cave.getHeight());

	//Display viewport size
	//wm.getWindow(1)->add(1, 9, "View Size:");
	//wm.getWindow(1)->add(1, 10, "W:");
	//wm.getWindow(1)->addInt(4, 10, map.getViewWidth());
	//wm.getWindow(1)->add(1, 11, "H:");
	//wm.getWindow(1)->addInt(4, 11, map.getViewHeight());

	//Display PC's location
	//wm.getWindow(1)->add(1, 12, "PC Position:");
	//wm.getWindow(1)->add(1, 13, "X:     ");
	//wm.getWindow(1)->addInt(4, 13, pc_pos.x);
	//wm.getWindow(1)->add(1, 14, "Y:     ");
	//wm.getWindow(1)->addInt(4, 14, pc_pos.y);

	//Find a random FloorTile to put our kobold on
	Entity kobold = em.createEntity();
	PositionComponent npc_pos;
	SpriteComponent npc_sprite = { 'k', 0, 0 };
	spawn_npc(cave, npc_pos, pc_pos, 15);
	pos_mgr.setComponent(kobold, npc_pos);
	sprite_mgr.setComponent(kobold, npc_sprite);

	//just another entity
	Entity goblin = em.createEntity();
	PositionComponent npc2_pos;
	SpriteComponent npc2_sprite = { 'g', 0, 0 };
	spawn_npc(cave, npc2_pos, pc_pos, 15);
	pos_mgr.setComponent(goblin, npc2_pos);
	sprite_mgr.setComponent(goblin, npc2_sprite);

	//Attack skills
	SkillComponent pc_atk = { 13, 0 };
	skill_mgr.setComponent(pc, BastardSword, pc_atk);

	//Defense skills
	SkillComponent npc_dodge = { 10, 0 };
	skill_mgr.setComponent(kobold, Dodge, npc_dodge);
	SkillComponent npc2_dodge = { 10, 0 };
	skill_mgr.setComponent(goblin, Dodge, npc2_dodge);

	//Now display everything
	render.execute(em);
	display.refresh();

	//Now we enter the "game loop"
	int ch;
	int key_pos = 8;
	int last_key_pos;
	int dx, dy;
	int pc_dx, pc_dy;
	bool run = true;

	sleep(2);

	while(run)
	{
		ch = getch();

		//Display the key code
		//wm.getWindow(0)->add(key_pos, 1, "                                    ");
		//wm.getWindow(0)->addInt(key_pos, 1, ch);

		dx = 0;
		dy = 0;
		pc_dx = 0;
		pc_dy = 0;

		//wm.getWindow(0)->add(1, 1, "     ");
		last_key_pos = key_pos;
		key_pos = 8;
		switch(ch)
		{
			//Viewport movement
			case KEY_UP:
				//wm.getWindow(0)->add(1, 1, "Up");
				dy = -1;
				break;
			case KEY_DOWN:
				//wm.getWindow(0)->add(1, 1, "Down");
				dy = 1;
				break;
			case KEY_LEFT:
				//wm.getWindow(0)->add(1, 1, "Left");
				dx = -1;
				break;
			case KEY_RIGHT:
				//wm.getWindow(0)->add(1, 1, "Right");
				dx = 1;
				break;
			//Orthogonal movement
			case '8':
			case 'k':
				pc_dx = 0;
				pc_dy = -1;
				break;
			case '2':
			case 'j':
				pc_dx = 0;
				pc_dy = 1;
				break;
			case '4':
			case 'h':
				pc_dx = -1;
				pc_dy = 0;
				break;
			case '6':
			case 'l':
				pc_dx = 1;
				pc_dy = 0;
				break;
			//Diagonal movement
			case '7':
			case 'y':
				pc_dx = -1;
				pc_dy = -1;
				break;
			case '9':
			case 'u':
				pc_dx = 1;
				pc_dy = -1;
				break;
			case '1':
			case 'b':
				pc_dx = -1;
				pc_dy = 1;
				break;
			case '3':
			case 'n':
				pc_dx = 1;
				pc_dy = 1;
				break;
			//Other commands
			case 'c':
			case 'C':
				//Center the view on the PC
				//wm.getWindow(2)->center(pc_pos.x, pc_pos.y);
				break;
			case 'p':
			case 'P':
				//Pause ncurses (just a useless demo of the ability)
				pause_curses(display);
				break;
			case 'q':
			case 'Q':
				//Quit
				run = false;
				break;
			default:
				key_pos = last_key_pos + 4;
				if(key_pos > display.getScreenSize().x)
				{
					key_pos = 8;
				}
				break;
		}

		if(pc_dx != 0 || pc_dy != 0)
		{
			//Test if the NPC is there
			if(pos_mgr.isPositionOccupied(pc_pos.x + pc_dx, pc_pos.y + pc_dy))
			{
				//There will be a fight!
				AttackComponent atk = { pos_mgr.getEntityAtPosition(pc_pos.x + pc_dx, pc_pos.y + pc_dy), BastardSword };
				attack_mgr.setComponent(pc, atk);
			} else {
				//Move the PC
				move_pc(cave, pc_pos, pc_dx, pc_dy);
				pos_mgr.setComponent(pc, pc_pos);
			}
		}

		//Process systems in order
		sys_attack.execute(em);
		render.execute(em);

		//Respawn a fresh kobold if we need to
		if(!em.isEntityAlive(kobold))
		{
			kobold = em.createEntity();
			spawn_npc(cave, npc_pos, pc_pos, 15);
			pos_mgr.setComponent(kobold, npc_pos);
			sprite_mgr.setComponent(kobold, npc_sprite);
		}
		//Respawn a fresh goblin if we need to
		if(!em.isEntityAlive(goblin))
		{
			goblin = em.createEntity();
			spawn_npc(cave, npc2_pos, pc_pos, 15);
			pos_mgr.setComponent(goblin, npc2_pos);
			sprite_mgr.setComponent(goblin, npc2_sprite);
		}

		//Move the viewport
		//map.moveBy(dx, dy);

		//Display our view's X and Y coordinates
		//wm.getWindow(1)->add(1, 3, "X:     ");
		//wm.getWindow(1)->addInt(4, 3, map.getViewX());
		//wm.getWindow(1)->add(1, 4, "Y:     ");
		//wm.getWindow(1)->addInt(4, 4, map.getViewY());

		//Re-display PC's position
		//wm.getWindow(1)->add(1, 13, "X:     ");
		//wm.getWindow(1)->addInt(4, 13, pc_pos.x);
		//wm.getWindow(1)->add(1, 14, "Y:     ");
		//wm.getWindow(1)->addInt(4, 14, pc_pos.y);

		//Display NPC's position
		//wm.getWindow(1)->add(1, 15, "NPC Position:");
		//wm.getWindow(1)->add(1, 16, "X:     ");
		//wm.getWindow(1)->addInt(4, 16, npc_pos.x);
		//wm.getWindow(1)->add(1, 17, "Y:     ");
		//wm.getWindow(1)->addInt(4, 17, npc_pos.y);

		//wm.getWindow(1)->addInt(1, 19, pc);
		//wm.getWindow(1)->addInt(5, 19, sprite_mgr.getComponent(pc).c);
		//wm.getWindow(1)->addInt(1, 20, kobold);
		//wm.getWindow(1)->addInt(5, 20, sprite_mgr.getComponent(kobold).c);
		//wm.getWindow(1)->addInt(1, 21, goblin);
		//wm.getWindow(1)->addInt(5, 21, sprite_mgr.getComponent(goblin).c);

		//Refresh the display
		display.refresh();
	}
}
<commit_msg>InterfaceTest now centers viewport on the PC on startup<commit_after>#include <ncurses.h>
#include <iostream>
#include <unistd.h>
#include <algorithm>

#include "interface/Display.h"
#include "map/Level.h"
#include "map/filters/DrunkardsWalkFilter.h"
#include "core/Rand.h"

#include "entity/ecs.h"

void pause_curses(Display& display)
{
	display.pause();

	std::cout << "Paused ncurses..." << std::endl;

	sleep(4);

	std::cout << "Resuming..." << std::endl;

	sleep(1);
	display.resume();
}

bool move_pc(Level& level, PositionComponent& pc_pos, int dx, int dy)
{
	int new_x = pc_pos.x + dx;
	int new_y = pc_pos.y + dy;

	//Make sure it's in bounds
	if(0 <= new_x && new_x < level.getWidth() && 0 <= new_y && new_y < level.getHeight())
	{
		//Make sure it's passable terrain
		if(level[new_x][new_y].isPassable())
		{
			//Adjust PC's x,y coordinates
			pc_pos.x += dx;
			pc_pos.y += dy;

			return true;
		}
	}
	return false;
}

void spawn_npc(Level& level, PositionComponent& npc_pos, PositionComponent& pc_pos, int max_dist = 15)
{
	static Rand rand(time(NULL));

	int min_x = std::max(0, pc_pos.x - max_dist);
	int max_x = std::min(level.getWidth()-1, pc_pos.x + max_dist);

	int min_y = std::max(0, pc_pos.y - max_dist);
	int max_y = std::min(level.getHeight()-1, pc_pos.y + max_dist);

	do {
		npc_pos.x = rand.randInt(min_x, max_x);
		npc_pos.y = rand.randInt(min_y, max_y);
	} while(level[npc_pos.x][npc_pos.y] != FloorTile);
}

int main()
{
	Display display;
	EntityManager em;

	//Set up our ComponentManagers
	PositionManager pos_mgr;
	SpriteManager sprite_mgr;
	SkillManager skill_mgr;
	AttackManager attack_mgr;
	em.addComponentManager(&pos_mgr);
	em.addComponentManager(&sprite_mgr);
	em.addComponentManager(&skill_mgr);
	em.addComponentManager(&attack_mgr);

	//We'll also need an AttackSystem, though no setup is necessary
	AttackSystem sys_attack;

	XYPair screen = display.getScreenSize();

	//Make a map double the screen size
	int map_y = screen.y * 2;
	int map_x = screen.x * 2;
	//Generate a map
	Level cave(map_x, map_y);
	DrunkardsWalkFilter walk;
	walk.setSeed(time(NULL));
	walk.apply(cave);

	//Find a random FloorTile to put our PC on
	Entity pc = em.createEntity();
	PositionComponent pc_pos;
	SpriteComponent pc_sprite = { '@', 0, 0 };
	Rand rand(time(NULL));
	do {
		pc_pos.x = rand.randInt(0, cave.getWidth()-1);
		pc_pos.y = rand.randInt(0, cave.getHeight()-1);
	} while(cave[pc_pos.x][pc_pos.y] != FloorTile);
	pos_mgr.setComponent(pc, pc_pos);
	sprite_mgr.setComponent(pc, pc_sprite);

	//Now create a Window and viewport for our level
	WindowGeometry map_geometry = { {20,3}, {AUTO_SIZE, AUTO_SIZE} };
	Window map = display.addWindow(cave, map_geometry);

	//Geometries for our top and left Windows
	WindowGeometry top_geometry = { {0,0}, {AUTO_SIZE, 3} };
	WindowGeometry left_geometry = { { 0, 3 }, {20, AUTO_SIZE} };
	//And now create them
	Window top = display.addWindow(top_geometry);
	Window left = display.addWindow(left_geometry);

	//top.addBorder();
	//left.addBorder();

	//New set up our RenderSystem
	RenderSystem render(&display, map);

	display.add(top, mkXYPair(1,0), "Message Panel");
	display.add(left, mkXYPair(1,0), "Stat Panel");

	//Center the map viewport on the PC
	display.center(map, pc_pos);

	//Let's display some map display stats
	//Display our view's X and Y coordinates
	//wm.getWindow(1)->add(1, 2, "View Position:");
	//wm.getWindow(1)->add(1, 3, "X:     ");
	//wm.getWindow(1)->addInt(4, 3, map.getViewX());
	//wm.getWindow(1)->add(1, 4, "Y:     ");
	//wm.getWindow(1)->addInt(4, 4, map.getViewY());

	//Display map size
	//wm.getWindow(1)->add(1, 6, "Map Size:");
	//wm.getWindow(1)->add(1, 7, "W:");
	//wm.getWindow(1)->addInt(4, 7, cave.getWidth());
	//wm.getWindow(1)->add(1, 8, "H:");
	//wm.getWindow(1)->addInt(4, 8, cave.getHeight());

	//Display viewport size
	//wm.getWindow(1)->add(1, 9, "View Size:");
	//wm.getWindow(1)->add(1, 10, "W:");
	//wm.getWindow(1)->addInt(4, 10, map.getViewWidth());
	//wm.getWindow(1)->add(1, 11, "H:");
	//wm.getWindow(1)->addInt(4, 11, map.getViewHeight());

	//Display PC's location
	//wm.getWindow(1)->add(1, 12, "PC Position:");
	//wm.getWindow(1)->add(1, 13, "X:     ");
	//wm.getWindow(1)->addInt(4, 13, pc_pos.x);
	//wm.getWindow(1)->add(1, 14, "Y:     ");
	//wm.getWindow(1)->addInt(4, 14, pc_pos.y);

	//Find a random FloorTile to put our kobold on
	Entity kobold = em.createEntity();
	PositionComponent npc_pos;
	SpriteComponent npc_sprite = { 'k', 0, 0 };
	spawn_npc(cave, npc_pos, pc_pos, 15);
	pos_mgr.setComponent(kobold, npc_pos);
	sprite_mgr.setComponent(kobold, npc_sprite);

	//just another entity
	Entity goblin = em.createEntity();
	PositionComponent npc2_pos;
	SpriteComponent npc2_sprite = { 'g', 0, 0 };
	spawn_npc(cave, npc2_pos, pc_pos, 15);
	pos_mgr.setComponent(goblin, npc2_pos);
	sprite_mgr.setComponent(goblin, npc2_sprite);

	//Attack skills
	SkillComponent pc_atk = { 13, 0 };
	skill_mgr.setComponent(pc, BastardSword, pc_atk);

	//Defense skills
	SkillComponent npc_dodge = { 10, 0 };
	skill_mgr.setComponent(kobold, Dodge, npc_dodge);
	SkillComponent npc2_dodge = { 10, 0 };
	skill_mgr.setComponent(goblin, Dodge, npc2_dodge);

	//Now display everything
	render.execute(em);
	display.refresh();

	//Now we enter the "game loop"
	int ch;
	int key_pos = 8;
	int last_key_pos;
	int dx, dy;
	int pc_dx, pc_dy;
	bool run = true;

	sleep(2);

	while(run)
	{
		ch = getch();

		//Display the key code
		//wm.getWindow(0)->add(key_pos, 1, "                                    ");
		//wm.getWindow(0)->addInt(key_pos, 1, ch);

		dx = 0;
		dy = 0;
		pc_dx = 0;
		pc_dy = 0;

		//wm.getWindow(0)->add(1, 1, "     ");
		last_key_pos = key_pos;
		key_pos = 8;
		switch(ch)
		{
			//Viewport movement
			case KEY_UP:
				//wm.getWindow(0)->add(1, 1, "Up");
				dy = -1;
				break;
			case KEY_DOWN:
				//wm.getWindow(0)->add(1, 1, "Down");
				dy = 1;
				break;
			case KEY_LEFT:
				//wm.getWindow(0)->add(1, 1, "Left");
				dx = -1;
				break;
			case KEY_RIGHT:
				//wm.getWindow(0)->add(1, 1, "Right");
				dx = 1;
				break;
			//Orthogonal movement
			case '8':
			case 'k':
				pc_dx = 0;
				pc_dy = -1;
				break;
			case '2':
			case 'j':
				pc_dx = 0;
				pc_dy = 1;
				break;
			case '4':
			case 'h':
				pc_dx = -1;
				pc_dy = 0;
				break;
			case '6':
			case 'l':
				pc_dx = 1;
				pc_dy = 0;
				break;
			//Diagonal movement
			case '7':
			case 'y':
				pc_dx = -1;
				pc_dy = -1;
				break;
			case '9':
			case 'u':
				pc_dx = 1;
				pc_dy = -1;
				break;
			case '1':
			case 'b':
				pc_dx = -1;
				pc_dy = 1;
				break;
			case '3':
			case 'n':
				pc_dx = 1;
				pc_dy = 1;
				break;
			//Other commands
			case 'c':
			case 'C':
				//Center the view on the PC
				//wm.getWindow(2)->center(pc_pos.x, pc_pos.y);
				break;
			case 'p':
			case 'P':
				//Pause ncurses (just a useless demo of the ability)
				pause_curses(display);
				break;
			case 'q':
			case 'Q':
				//Quit
				run = false;
				break;
			default:
				key_pos = last_key_pos + 4;
				if(key_pos > display.getScreenSize().x)
				{
					key_pos = 8;
				}
				break;
		}

		if(pc_dx != 0 || pc_dy != 0)
		{
			//Test if the NPC is there
			if(pos_mgr.isPositionOccupied(pc_pos.x + pc_dx, pc_pos.y + pc_dy))
			{
				//There will be a fight!
				AttackComponent atk = { pos_mgr.getEntityAtPosition(pc_pos.x + pc_dx, pc_pos.y + pc_dy), BastardSword };
				attack_mgr.setComponent(pc, atk);
			} else {
				//Move the PC
				move_pc(cave, pc_pos, pc_dx, pc_dy);
				pos_mgr.setComponent(pc, pc_pos);
			}
		}

		//Process systems in order
		sys_attack.execute(em);
		render.execute(em);

		//Respawn a fresh kobold if we need to
		if(!em.isEntityAlive(kobold))
		{
			kobold = em.createEntity();
			spawn_npc(cave, npc_pos, pc_pos, 15);
			pos_mgr.setComponent(kobold, npc_pos);
			sprite_mgr.setComponent(kobold, npc_sprite);
		}
		//Respawn a fresh goblin if we need to
		if(!em.isEntityAlive(goblin))
		{
			goblin = em.createEntity();
			spawn_npc(cave, npc2_pos, pc_pos, 15);
			pos_mgr.setComponent(goblin, npc2_pos);
			sprite_mgr.setComponent(goblin, npc2_sprite);
		}

		//Move the viewport
		//map.moveBy(dx, dy);

		//Display our view's X and Y coordinates
		//wm.getWindow(1)->add(1, 3, "X:     ");
		//wm.getWindow(1)->addInt(4, 3, map.getViewX());
		//wm.getWindow(1)->add(1, 4, "Y:     ");
		//wm.getWindow(1)->addInt(4, 4, map.getViewY());

		//Re-display PC's position
		//wm.getWindow(1)->add(1, 13, "X:     ");
		//wm.getWindow(1)->addInt(4, 13, pc_pos.x);
		//wm.getWindow(1)->add(1, 14, "Y:     ");
		//wm.getWindow(1)->addInt(4, 14, pc_pos.y);

		//Display NPC's position
		//wm.getWindow(1)->add(1, 15, "NPC Position:");
		//wm.getWindow(1)->add(1, 16, "X:     ");
		//wm.getWindow(1)->addInt(4, 16, npc_pos.x);
		//wm.getWindow(1)->add(1, 17, "Y:     ");
		//wm.getWindow(1)->addInt(4, 17, npc_pos.y);

		//wm.getWindow(1)->addInt(1, 19, pc);
		//wm.getWindow(1)->addInt(5, 19, sprite_mgr.getComponent(pc).c);
		//wm.getWindow(1)->addInt(1, 20, kobold);
		//wm.getWindow(1)->addInt(5, 20, sprite_mgr.getComponent(kobold).c);
		//wm.getWindow(1)->addInt(1, 21, goblin);
		//wm.getWindow(1)->addInt(5, 21, sprite_mgr.getComponent(goblin).c);

		//Refresh the display
		display.refresh();
	}
}
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "SoundSystem.h"
#include "OpenALAudioModule.h"
#include "WavLoader.h"
#include "VorbisDecoder.h"
#include "RexTypes.h"
#include "AssetServiceInterface.h"
#include "AssetEvents.h"

#include <boost/thread/mutex.hpp>

namespace OpenALAudio
{
    const Core::uint DEFAULT_SOUND_CACHE_SIZE = 32 * 1024 * 1024;
    const Core::f64 CACHE_CHECK_INTERVAL = 1.0;

    SoundSystem::SoundSystem(Foundation::Framework *framework) :
        framework_(framework),
        initialized_(false),
        context_(0),
        device_(0),
        next_channel_id_(0),
        sound_cache_size_(DEFAULT_SOUND_CACHE_SIZE),
        update_time_(0),
        listener_position_(0.0, 0.0, 0.0)
    {
        sound_cache_size_ = framework_->GetDefaultConfig().DeclareSetting("SoundSystem", "sound_cache_size", DEFAULT_SOUND_CACHE_SIZE);

        Initialize();

        // Create vorbis decoder thread task and let the framework thread task manager handle it
        VorbisDecoder* decoder = new VorbisDecoder();
        framework_->GetThreadTaskManager()->AddThreadTask(Foundation::ThreadTaskPtr(decoder));
    }

    SoundSystem::~SoundSystem()
    {
        Uninitialize();
    }

    void SoundSystem::Initialize()
    {
        if (initialized_)
            return;

        device_ = alcOpenDevice(NULL);
        if (!device_)
        {
            OpenALAudioModule::LogWarning("Could not open OpenAL sound device");
            return;
        }

        context_ = alcCreateContext(device_, NULL);
        if (!context_)
        {
            OpenALAudioModule::LogWarning("Could not create OpenAL sound context");
            return;
        }

        alcMakeContextCurrent(context_);
        initialized_ = true;

        mutex.initialize();
    }

    void SoundSystem::Uninitialize()
    {
        if (context_)
        {
            alcMakeContextCurrent(0);
            alcDestroyContext(context_);
            context_ = 0;
        }
        if (device_)
        {
            alcCloseDevice(device_);
            device_ = 0;
        }

        initialized_ = false;
    }

    Foundation::SoundServiceInterface::SoundState SoundSystem::GetSoundState(Core::sound_id_t id) const
    {
        SoundChannelMap::const_iterator i = channels_.find(id);
        if (i == channels_.end())
            return Foundation::SoundServiceInterface::Stopped;
        return i->second->GetState();
    }

    std::vector<Core::sound_id_t> SoundSystem::GetActiveSounds() const
    {
        std::vector<Core::sound_id_t> ret;

        SoundChannelMap::const_iterator i = channels_.begin();
        while (i != channels_.end())
        {
            if (i->second->GetState() != Foundation::SoundServiceInterface::Stopped)
                ret.push_back(i->first);
            ++i;
        }

        return ret;
    }

    const std::string& SoundSystem::GetSoundName(Core::sound_id_t id) const
    {
        static std::string empty;

        SoundChannelMap::const_iterator i = channels_.find(id);
        if (i == channels_.end())
            return empty;
        return i->second->GetSoundName();
    }

    void SoundSystem::Update(Core::f64 frametime)
    {
        mutex.lock();
        std::vector<SoundChannelMap::iterator> channels_to_delete;

        // Update listener position/orientation to sound device
        ALfloat pos[] = {listener_position_.x, listener_position_.y, listener_position_.z};
        alListenerfv(AL_POSITION, pos);
        Core::Vector3df front = listener_orientation_ * Core::Vector3df(0.0f, -1.0f, 0.0f);
        Core::Vector3df up = listener_orientation_ * Core::Vector3df(0.0f, 0.0f, -1.0f);
        ALfloat orient[] = {front.x, front.y, front.z, up.x, up.y, up.z};
        alListenerfv(AL_ORIENTATION, orient);

        // Update channel attenuations, check which have stopped
        SoundChannelMap::iterator i = channels_.begin();
        while (i != channels_.end())
        {
            i->second->Update(listener_position_);
            if (i->second->GetState() == Foundation::SoundServiceInterface::Stopped)
                channels_to_delete.push_back(i);
            ++i;
        }

        // Remove stopped channels
        for (Core::uint j = 0; j < channels_to_delete.size(); ++j)
            channels_.erase(channels_to_delete[j]);

        mutex.unlock();

        // Age the sound cache
        UpdateCache(frametime);
    }

    void SoundSystem::SetListener(const Core::Vector3df& position, const Core::Quaternion& orientation)
    {
        if (!initialized_)
            return;

        listener_position_ = position;
        listener_orientation_ = orientation;
    }

    Core::sound_id_t SoundSystem::PlaySound(const std::string& name, bool local, Core::sound_id_t channel)
    {
        SoundPtr sound = GetSound(name, local);
        if (!sound)
            return 0;

        SoundChannelMap::iterator i = channels_.find(channel);
        if (i == channels_.end())
        {
            i = channels_.insert(
                std::pair<Core::sound_id_t, SoundChannelPtr>(GetNextSoundChannelID(), SoundChannelPtr(new SoundChannel()))).first;
        }

        i->second->SetPositional(false);
        i->second->Play(sound);

        return i->first;
    }

    Core::sound_id_t SoundSystem::PlaySound3D(const std::string& name, bool local, Core::Vector3df position, Core::sound_id_t channel)
    {
        SoundPtr sound = GetSound(name, local);
        if (!sound)
            return 0;

        SoundChannelMap::iterator i = channels_.find(channel);
        if (i == channels_.end())
        {
            i = channels_.insert(
                std::pair<Core::sound_id_t, SoundChannelPtr>(GetNextSoundChannelID(), SoundChannelPtr(new SoundChannel()))).first;
        }

        i->second->SetPositional(true);
        i->second->SetPosition(position);
        i->second->Play(sound);

        return i->first;
    }

    Core::sound_id_t SoundSystem::PlayAudioData(Core::u8 * buffer, int buffer_size, int sample_rate, int sample_width, bool stereo, Core::sound_id_t channel)
    {
        if (!mutex.try_lock())
        {
            int i = (int)((buffer_size*8000 / sample_rate) / sample_width);
            std::string s_int = boost::lexical_cast<std::string>(i);
            OpenALAudioModule::LogDebug("Dropped " + s_int + " ms");
            return 0;
        }

        SoundPtr sound = SoundPtr(new OpenALAudio::Sound("audiobuffer"));
        if (!sound)
            return 0;

        bool sample_width_16bit = true;
        switch(sample_width)
        {
            case 8: sample_width_16bit = false; break;
            case 16: sample_width_16bit = true; break;
            default:
                return 0; // todo: Write log entry
        }
        sound->LoadFromBuffer(buffer, buffer_size, sample_rate, sample_width_16bit, stereo);

        SoundChannelMap::iterator i = channels_.find(channel);
        if (i == channels_.end())
        {
            SoundChannel* s = new SoundChannel();
            if (!s)
                return 0;
            i = channels_.insert(std::pair<Core::sound_id_t, SoundChannelPtr>(GetNextSoundChannelID(), SoundChannelPtr(s))).first;
        }

        if (!i->second.get())
            return 0;
        i->second->Play(sound);

        Core::sound_id_t this_channel_id =  i->first;
        mutex.unlock();
        return this_channel_id;
    }

    void SoundSystem::StopSound(Core::sound_id_t id)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->Stop();
    }

    void SoundSystem::SetPitch(Core::sound_id_t id, Core::Real pitch)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetPitch(pitch);
    }

    void SoundSystem::SetGain(Core::sound_id_t id, Core::Real gain)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetGain(gain);
    }

    void SoundSystem::SetLooped(Core::sound_id_t id, bool looped)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetLooped(looped);
    }

    void SoundSystem::SetPositional(Core::sound_id_t id, bool positional)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetPositional(positional);
    }

    void SoundSystem::SetPosition(Core::sound_id_t id, Core::Vector3df position)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetPosition(position);
    }

    void SoundSystem::SetRange(Core::sound_id_t id, Core::Real inner_radius, Core::Real outer_radius, Core::Real rolloff)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetRange(inner_radius, outer_radius, rolloff);
    }

    Core::sound_id_t SoundSystem::GetNextSoundChannelID()
    {
        for (;;)
        {
            next_channel_id_++;
            if (!next_channel_id_)
                next_channel_id_ = 1;
            // Must be currently unused
            if (channels_.find(next_channel_id_) == channels_.end())
                break;
        }

        return next_channel_id_;
    }

    SoundPtr SoundSystem::GetSound(const std::string& name, bool local)
    {
        SoundMap::iterator i = sounds_.find(name);
        if (i != sounds_.end())
        {
            i->second->ResetAge();
            return i->second;
        }

        if (local)
        {
            // Loading of local wav sound
            std::string name_lower = name;
            boost::algorithm::to_lower(name_lower);
            if (name_lower.find(".wav") != std::string::npos)
            {
                SoundPtr new_sound(new Sound(name));
                if (WavLoader::LoadFromFile(new_sound.get(), name))
                {
                    sounds_[name] = new_sound;
                    return new_sound;
                }
            }

            // Loading of local ogg sound
            if (name_lower.find(".ogg") != std::string::npos)
            {
                SoundPtr new_sound(new Sound(name));

                // See if the file exists. If it does, read it and post a decode request
                if (DecodeLocalOggFile(new_sound.get(), name))
                {
                    // Now the sound exists in cache with no data yet. We'll fill in later
                    sounds_[name] = new_sound;
                    return new_sound;
                }
            }
        }
        else
        {
            // Loading of sound from assetdata, assumed to be vorbis compressed stream
            boost::shared_ptr<Foundation::AssetServiceInterface> asset_service = framework_->GetServiceManager()->GetService<Foundation::AssetServiceInterface>(Foundation::Service::ST_Asset).lock();
            if (asset_service)
            {
                SoundPtr new_sound(new Sound(name));
                sounds_[name] = new_sound;

                // The sound will be filled with data later
                asset_service->RequestAsset(name, RexTypes::ASSETTYPENAME_SOUNDVORBIS);
                return new_sound;
            }
        }

        return SoundPtr();
    }

    void SoundSystem::UpdateCache(Core::f64 frametime)
    {

        update_time_ += frametime;
        if (update_time_ < CACHE_CHECK_INTERVAL)
            return;

        Core::uint total_size = 0;
        SoundMap::iterator oldest_sound = sounds_.end();
        Core::f64 oldest_age = 0.0;

        SoundMap::iterator i = sounds_.begin();
        while (i != sounds_.end())
        {
            i->second->AddAge(update_time_);
            total_size += i->second->GetSize();
            // Don't erase zero size sounds, because they haven't been created yet and are probably waiting for assetdata
            if ((i->second->GetAge() >= oldest_age) && (i->second->GetSize()))
            {
                oldest_age = i->second->GetAge();
                oldest_sound = i;
            }
            ++i;
        }

        if (total_size > sound_cache_size_)
        {
            if (oldest_sound != sounds_.end())
                sounds_.erase(oldest_sound);
        }

        update_time_ = 0.0;
    }

    bool SoundSystem::DecodeLocalOggFile(Sound* sound, const std::string& name)
    {
        boost::filesystem::path file_path(name);
        std::ifstream file(file_path.native_directory_string().c_str(), std::ios::in | std::ios::binary);
        if (!file.is_open())
        {
            OpenALAudioModule::LogError("Could not open file: " + name + ".");
            return false;
        }

        VorbisDecodeRequestPtr new_request(new VorbisDecodeRequest());
        new_request->name_ = name;

        std::filebuf *pbuf = file.rdbuf();
        size_t size = pbuf->pubseekoff(0, std::ios::end, std::ios::in);
        new_request->buffer_.resize(size);
        pbuf->pubseekpos(0, std::ios::in);
        pbuf->sgetn((char *)&new_request->buffer_[0], size);
        file.close();

        framework_->GetThreadTaskManager()->AddRequest("VorbisDecoder", new_request);
        return true;
    }

    bool SoundSystem::HandleTaskEvent(Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        if (event_id != Task::Events::REQUEST_COMPLETED)
            return false;
        VorbisDecodeResult* result = dynamic_cast<VorbisDecodeResult*>(data);
        if (!result || result->task_description_ != "VorbisDecoder")
            return false;

        // If we can find the sound from our cache, and the result contains data, stuff the data into the sound
        SoundMap::iterator i = sounds_.find(result->name_);
        if (i == sounds_.end())
            return false;

        if (!result->buffer_.size())
            return true;

        i->second->LoadFromBuffer(&result->buffer_[0], result->buffer_.size(), result->frequency_, true, result->stereo_);
        return true;
    }

    bool SoundSystem::HandleAssetEvent(Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        if (event_id != Asset::Events::ASSET_READY)
            return false;

        Asset::Events::AssetReady *event_data = checked_static_cast<Asset::Events::AssetReady*>(data);
        if (event_data->asset_type_ == RexTypes::ASSETTYPENAME_SOUNDVORBIS)
        {
            if (!event_data->asset_)
                return false;
            // Find the sound from our cache
            SoundMap::iterator i = sounds_.find(event_data->asset_id_);
            if (i == sounds_.end())
                return false;
            // If sound already has data, do not queue another decode request
            if (i->second->GetSize() != 0)
                return false;
            VorbisDecodeRequestPtr new_request(new VorbisDecodeRequest());
            new_request->name_ = event_data->asset_id_;
            new_request->buffer_.resize(event_data->asset_->GetSize());
            //! \todo use asset data directly instead of copying to decode request buffer
            memcpy(&new_request->buffer_[0], event_data->asset_->GetData(), event_data->asset_->GetSize());
            framework_->GetThreadTaskManager()->AddRequest("VorbisDecoder", new_request);
        }

        return false;
    }
}
<commit_msg>take out boost mutex initialize() call (doesn't exist on posix and doesn't seem part of public interface)<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "SoundSystem.h"
#include "OpenALAudioModule.h"
#include "WavLoader.h"
#include "VorbisDecoder.h"
#include "RexTypes.h"
#include "AssetServiceInterface.h"
#include "AssetEvents.h"

#include <boost/thread/mutex.hpp>

namespace OpenALAudio
{
    const Core::uint DEFAULT_SOUND_CACHE_SIZE = 32 * 1024 * 1024;
    const Core::f64 CACHE_CHECK_INTERVAL = 1.0;

    SoundSystem::SoundSystem(Foundation::Framework *framework) :
        framework_(framework),
        initialized_(false),
        context_(0),
        device_(0),
        next_channel_id_(0),
        sound_cache_size_(DEFAULT_SOUND_CACHE_SIZE),
        update_time_(0),
        listener_position_(0.0, 0.0, 0.0)
    {
        sound_cache_size_ = framework_->GetDefaultConfig().DeclareSetting("SoundSystem", "sound_cache_size", DEFAULT_SOUND_CACHE_SIZE);

        Initialize();

        // Create vorbis decoder thread task and let the framework thread task manager handle it
        VorbisDecoder* decoder = new VorbisDecoder();
        framework_->GetThreadTaskManager()->AddThreadTask(Foundation::ThreadTaskPtr(decoder));
    }

    SoundSystem::~SoundSystem()
    {
        Uninitialize();
    }

    void SoundSystem::Initialize()
    {
        if (initialized_)
            return;

        device_ = alcOpenDevice(NULL);
        if (!device_)
        {
            OpenALAudioModule::LogWarning("Could not open OpenAL sound device");
            return;
        }

        context_ = alcCreateContext(device_, NULL);
        if (!context_)
        {
            OpenALAudioModule::LogWarning("Could not create OpenAL sound context");
            return;
        }

        alcMakeContextCurrent(context_);
        initialized_ = true;

    }

    void SoundSystem::Uninitialize()
    {
        if (context_)
        {
            alcMakeContextCurrent(0);
            alcDestroyContext(context_);
            context_ = 0;
        }
        if (device_)
        {
            alcCloseDevice(device_);
            device_ = 0;
        }

        initialized_ = false;
    }

    Foundation::SoundServiceInterface::SoundState SoundSystem::GetSoundState(Core::sound_id_t id) const
    {
        SoundChannelMap::const_iterator i = channels_.find(id);
        if (i == channels_.end())
            return Foundation::SoundServiceInterface::Stopped;
        return i->second->GetState();
    }

    std::vector<Core::sound_id_t> SoundSystem::GetActiveSounds() const
    {
        std::vector<Core::sound_id_t> ret;

        SoundChannelMap::const_iterator i = channels_.begin();
        while (i != channels_.end())
        {
            if (i->second->GetState() != Foundation::SoundServiceInterface::Stopped)
                ret.push_back(i->first);
            ++i;
        }

        return ret;
    }

    const std::string& SoundSystem::GetSoundName(Core::sound_id_t id) const
    {
        static std::string empty;

        SoundChannelMap::const_iterator i = channels_.find(id);
        if (i == channels_.end())
            return empty;
        return i->second->GetSoundName();
    }

    void SoundSystem::Update(Core::f64 frametime)
    {
        mutex.lock();
        std::vector<SoundChannelMap::iterator> channels_to_delete;

        // Update listener position/orientation to sound device
        ALfloat pos[] = {listener_position_.x, listener_position_.y, listener_position_.z};
        alListenerfv(AL_POSITION, pos);
        Core::Vector3df front = listener_orientation_ * Core::Vector3df(0.0f, -1.0f, 0.0f);
        Core::Vector3df up = listener_orientation_ * Core::Vector3df(0.0f, 0.0f, -1.0f);
        ALfloat orient[] = {front.x, front.y, front.z, up.x, up.y, up.z};
        alListenerfv(AL_ORIENTATION, orient);

        // Update channel attenuations, check which have stopped
        SoundChannelMap::iterator i = channels_.begin();
        while (i != channels_.end())
        {
            i->second->Update(listener_position_);
            if (i->second->GetState() == Foundation::SoundServiceInterface::Stopped)
                channels_to_delete.push_back(i);
            ++i;
        }

        // Remove stopped channels
        for (Core::uint j = 0; j < channels_to_delete.size(); ++j)
            channels_.erase(channels_to_delete[j]);

        mutex.unlock();

        // Age the sound cache
        UpdateCache(frametime);
    }

    void SoundSystem::SetListener(const Core::Vector3df& position, const Core::Quaternion& orientation)
    {
        if (!initialized_)
            return;

        listener_position_ = position;
        listener_orientation_ = orientation;
    }

    Core::sound_id_t SoundSystem::PlaySound(const std::string& name, bool local, Core::sound_id_t channel)
    {
        SoundPtr sound = GetSound(name, local);
        if (!sound)
            return 0;

        SoundChannelMap::iterator i = channels_.find(channel);
        if (i == channels_.end())
        {
            i = channels_.insert(
                std::pair<Core::sound_id_t, SoundChannelPtr>(GetNextSoundChannelID(), SoundChannelPtr(new SoundChannel()))).first;
        }

        i->second->SetPositional(false);
        i->second->Play(sound);

        return i->first;
    }

    Core::sound_id_t SoundSystem::PlaySound3D(const std::string& name, bool local, Core::Vector3df position, Core::sound_id_t channel)
    {
        SoundPtr sound = GetSound(name, local);
        if (!sound)
            return 0;

        SoundChannelMap::iterator i = channels_.find(channel);
        if (i == channels_.end())
        {
            i = channels_.insert(
                std::pair<Core::sound_id_t, SoundChannelPtr>(GetNextSoundChannelID(), SoundChannelPtr(new SoundChannel()))).first;
        }

        i->second->SetPositional(true);
        i->second->SetPosition(position);
        i->second->Play(sound);

        return i->first;
    }

    Core::sound_id_t SoundSystem::PlayAudioData(Core::u8 * buffer, int buffer_size, int sample_rate, int sample_width, bool stereo, Core::sound_id_t channel)
    {
        if (!mutex.try_lock())
        {
            int i = (int)((buffer_size*8000 / sample_rate) / sample_width);
            std::string s_int = boost::lexical_cast<std::string>(i);
            OpenALAudioModule::LogDebug("Dropped " + s_int + " ms");
            return 0;
        }

        SoundPtr sound = SoundPtr(new OpenALAudio::Sound("audiobuffer"));
        if (!sound)
            return 0;

        bool sample_width_16bit = true;
        switch(sample_width)
        {
            case 8: sample_width_16bit = false; break;
            case 16: sample_width_16bit = true; break;
            default:
                return 0; // todo: Write log entry
        }
        sound->LoadFromBuffer(buffer, buffer_size, sample_rate, sample_width_16bit, stereo);

        SoundChannelMap::iterator i = channels_.find(channel);
        if (i == channels_.end())
        {
            SoundChannel* s = new SoundChannel();
            if (!s)
                return 0;
            i = channels_.insert(std::pair<Core::sound_id_t, SoundChannelPtr>(GetNextSoundChannelID(), SoundChannelPtr(s))).first;
        }

        if (!i->second.get())
            return 0;
        i->second->Play(sound);

        Core::sound_id_t this_channel_id =  i->first;
        mutex.unlock();
        return this_channel_id;
    }

    void SoundSystem::StopSound(Core::sound_id_t id)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->Stop();
    }

    void SoundSystem::SetPitch(Core::sound_id_t id, Core::Real pitch)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetPitch(pitch);
    }

    void SoundSystem::SetGain(Core::sound_id_t id, Core::Real gain)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetGain(gain);
    }

    void SoundSystem::SetLooped(Core::sound_id_t id, bool looped)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetLooped(looped);
    }

    void SoundSystem::SetPositional(Core::sound_id_t id, bool positional)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetPositional(positional);
    }

    void SoundSystem::SetPosition(Core::sound_id_t id, Core::Vector3df position)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetPosition(position);
    }

    void SoundSystem::SetRange(Core::sound_id_t id, Core::Real inner_radius, Core::Real outer_radius, Core::Real rolloff)
    {
        SoundChannelMap::iterator i = channels_.find(id);
        if (i == channels_.end())
            return;

        i->second->SetRange(inner_radius, outer_radius, rolloff);
    }

    Core::sound_id_t SoundSystem::GetNextSoundChannelID()
    {
        for (;;)
        {
            next_channel_id_++;
            if (!next_channel_id_)
                next_channel_id_ = 1;
            // Must be currently unused
            if (channels_.find(next_channel_id_) == channels_.end())
                break;
        }

        return next_channel_id_;
    }

    SoundPtr SoundSystem::GetSound(const std::string& name, bool local)
    {
        SoundMap::iterator i = sounds_.find(name);
        if (i != sounds_.end())
        {
            i->second->ResetAge();
            return i->second;
        }

        if (local)
        {
            // Loading of local wav sound
            std::string name_lower = name;
            boost::algorithm::to_lower(name_lower);
            if (name_lower.find(".wav") != std::string::npos)
            {
                SoundPtr new_sound(new Sound(name));
                if (WavLoader::LoadFromFile(new_sound.get(), name))
                {
                    sounds_[name] = new_sound;
                    return new_sound;
                }
            }

            // Loading of local ogg sound
            if (name_lower.find(".ogg") != std::string::npos)
            {
                SoundPtr new_sound(new Sound(name));

                // See if the file exists. If it does, read it and post a decode request
                if (DecodeLocalOggFile(new_sound.get(), name))
                {
                    // Now the sound exists in cache with no data yet. We'll fill in later
                    sounds_[name] = new_sound;
                    return new_sound;
                }
            }
        }
        else
        {
            // Loading of sound from assetdata, assumed to be vorbis compressed stream
            boost::shared_ptr<Foundation::AssetServiceInterface> asset_service = framework_->GetServiceManager()->GetService<Foundation::AssetServiceInterface>(Foundation::Service::ST_Asset).lock();
            if (asset_service)
            {
                SoundPtr new_sound(new Sound(name));
                sounds_[name] = new_sound;

                // The sound will be filled with data later
                asset_service->RequestAsset(name, RexTypes::ASSETTYPENAME_SOUNDVORBIS);
                return new_sound;
            }
        }

        return SoundPtr();
    }

    void SoundSystem::UpdateCache(Core::f64 frametime)
    {

        update_time_ += frametime;
        if (update_time_ < CACHE_CHECK_INTERVAL)
            return;

        Core::uint total_size = 0;
        SoundMap::iterator oldest_sound = sounds_.end();
        Core::f64 oldest_age = 0.0;

        SoundMap::iterator i = sounds_.begin();
        while (i != sounds_.end())
        {
            i->second->AddAge(update_time_);
            total_size += i->second->GetSize();
            // Don't erase zero size sounds, because they haven't been created yet and are probably waiting for assetdata
            if ((i->second->GetAge() >= oldest_age) && (i->second->GetSize()))
            {
                oldest_age = i->second->GetAge();
                oldest_sound = i;
            }
            ++i;
        }

        if (total_size > sound_cache_size_)
        {
            if (oldest_sound != sounds_.end())
                sounds_.erase(oldest_sound);
        }

        update_time_ = 0.0;
    }

    bool SoundSystem::DecodeLocalOggFile(Sound* sound, const std::string& name)
    {
        boost::filesystem::path file_path(name);
        std::ifstream file(file_path.native_directory_string().c_str(), std::ios::in | std::ios::binary);
        if (!file.is_open())
        {
            OpenALAudioModule::LogError("Could not open file: " + name + ".");
            return false;
        }

        VorbisDecodeRequestPtr new_request(new VorbisDecodeRequest());
        new_request->name_ = name;

        std::filebuf *pbuf = file.rdbuf();
        size_t size = pbuf->pubseekoff(0, std::ios::end, std::ios::in);
        new_request->buffer_.resize(size);
        pbuf->pubseekpos(0, std::ios::in);
        pbuf->sgetn((char *)&new_request->buffer_[0], size);
        file.close();

        framework_->GetThreadTaskManager()->AddRequest("VorbisDecoder", new_request);
        return true;
    }

    bool SoundSystem::HandleTaskEvent(Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        if (event_id != Task::Events::REQUEST_COMPLETED)
            return false;
        VorbisDecodeResult* result = dynamic_cast<VorbisDecodeResult*>(data);
        if (!result || result->task_description_ != "VorbisDecoder")
            return false;

        // If we can find the sound from our cache, and the result contains data, stuff the data into the sound
        SoundMap::iterator i = sounds_.find(result->name_);
        if (i == sounds_.end())
            return false;

        if (!result->buffer_.size())
            return true;

        i->second->LoadFromBuffer(&result->buffer_[0], result->buffer_.size(), result->frequency_, true, result->stereo_);
        return true;
    }

    bool SoundSystem::HandleAssetEvent(Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        if (event_id != Asset::Events::ASSET_READY)
            return false;

        Asset::Events::AssetReady *event_data = checked_static_cast<Asset::Events::AssetReady*>(data);
        if (event_data->asset_type_ == RexTypes::ASSETTYPENAME_SOUNDVORBIS)
        {
            if (!event_data->asset_)
                return false;
            // Find the sound from our cache
            SoundMap::iterator i = sounds_.find(event_data->asset_id_);
            if (i == sounds_.end())
                return false;
            // If sound already has data, do not queue another decode request
            if (i->second->GetSize() != 0)
                return false;
            VorbisDecodeRequestPtr new_request(new VorbisDecodeRequest());
            new_request->name_ = event_data->asset_id_;
            new_request->buffer_.resize(event_data->asset_->GetSize());
            //! \todo use asset data directly instead of copying to decode request buffer
            memcpy(&new_request->buffer_[0], event_data->asset_->GetData(), event_data->asset_->GetSize());
            framework_->GetThreadTaskManager()->AddRequest("VorbisDecoder", new_request);
        }

        return false;
    }
}
<|endoftext|>


<commit_before>#include <QDebug>
#include <memory>
#include "kernel.h"
#include "ilwisdata.h"
#include "mastercatalog.h"
#include "iooptions.h"
#include "uicontextmodel.h"
#include "coveragelayermodel.h"
#include "coverage.h"
#include "visualizationmanager.h"

using namespace Ilwis;

LayerManager::LayerManager(QObject *parent) :
    QObject(parent)
{
}

LayerManager::LayerManager(QObject *parent, UIContextModel *context) : QObject(parent), _uicontext(context)
{
    IlwisTypes metatype = itCOLLECTION | itCATALOGVIEW;
    Resource res("Global Layer", metatype);
    CoverageLayerModel * model = new CoverageLayerModel(_layers.size(), res,0, this);
    model->iconPath("layers.png");
    _layers.append(model);
}
void LayerManager::addVisualizationModel(CoverageLayerModel *newmodel)
{
    _layers.insert(1,newmodel);
}

void LayerManager::addDataSource(const QUrl &url, IlwisTypes tp, Ilwis::Geodrawer::DrawerInterface *drawer)
{
    try{
        if ( tp == itUNKNOWN)
            return;
        Resource resource = mastercatalog()->name2Resource(url.toString(),tp);
        if ( !resource.isValid())
            return;
        //IIlwisObject obj(resource);
        auto layer = new CoverageLayerModel(_layers.size(), resource, drawer, this);
        if  ( _layers.size() == 1)
            _layers.push_back(layer);
        else
            _layers.insert(1,new CoverageLayerModel(_layers.size(), resource, drawer, this));
        emit layerChanged();
    }
    catch(const ErrorObject& ){
    }
    catch(const std::exception& ex){
        kernel()->issues()->log(ex.what());
    }
}

bool LayerManager::zoomInMode() const
{
    return _zoomInMode;
}

void LayerManager::setZoomInMode(bool yesno)
{
    _zoomInMode = yesno;
}

bool LayerManager::hasSelectionDrawer() const
{
    return _hasSelectionDrawer;
}

void LayerManager::setHasSelectionDrawer(bool yesno)
{
    _hasSelectionDrawer = yesno;
}

void LayerManager::layersView(LayersViewCommandInterface *view)
{
    _layersView = view;
}

QQmlListProperty<CoverageLayerModel> LayerManager::layers()
{
    return QQmlListProperty<CoverageLayerModel>(this, _layers);
}

CoverageLayerModel *LayerManager::layer(quint32 layerIndex){
    if ( layerIndex < _layers.size())
        return _layers[layerIndex];
    return 0;
}

QString LayerManager::layerInfo(const Coordinate &crd, const QString& attrName) const
{
    std::vector<QString> texts;
    for(CoverageLayerModel *layer : _layers){
        if ( layer->object().isValid() && hasType(layer->object()->ilwisType(), itCOVERAGE)){
            ICoverage cov = layer->object().as<Coverage>();
            QVariant value = cov->coord2value(crd);
            if ( value.isValid()){
                texts.push_back(value.toString());
            }
        }

    }
    QString outtext;
    for(auto txt : texts){
        if ( outtext.size() != 0)
            outtext += "; ";
        outtext += txt;
    }
    if ( outtext == "")
        outtext = "?";
    return outtext;
}

void LayerManager::init()
{

}
<commit_msg>passes the correct attribute to coord2value in layerinfo<commit_after>#include <QDebug>
#include <memory>
#include "kernel.h"
#include "ilwisdata.h"
#include "mastercatalog.h"
#include "iooptions.h"
#include "uicontextmodel.h"
#include "coveragelayermodel.h"
#include "coverage.h"
#include "visualizationmanager.h"

using namespace Ilwis;

LayerManager::LayerManager(QObject *parent) :
    QObject(parent)
{
}

LayerManager::LayerManager(QObject *parent, UIContextModel *context) : QObject(parent), _uicontext(context)
{
    IlwisTypes metatype = itCOLLECTION | itCATALOGVIEW;
    Resource res("Global Layer", metatype);
    CoverageLayerModel * model = new CoverageLayerModel(_layers.size(), res,0, this);
    model->iconPath("layers.png");
    _layers.append(model);
}
void LayerManager::addVisualizationModel(CoverageLayerModel *newmodel)
{
    _layers.insert(1,newmodel);
}

void LayerManager::addDataSource(const QUrl &url, IlwisTypes tp, Ilwis::Geodrawer::DrawerInterface *drawer)
{
    try{
        if ( tp == itUNKNOWN)
            return;
        Resource resource = mastercatalog()->name2Resource(url.toString(),tp);
        if ( !resource.isValid())
            return;
        //IIlwisObject obj(resource);
        auto layer = new CoverageLayerModel(_layers.size(), resource, drawer, this);
        if  ( _layers.size() == 1)
            _layers.push_back(layer);
        else
            _layers.insert(1,new CoverageLayerModel(_layers.size(), resource, drawer, this));
        emit layerChanged();
    }
    catch(const ErrorObject& ){
    }
    catch(const std::exception& ex){
        kernel()->issues()->log(ex.what());
    }
}

bool LayerManager::zoomInMode() const
{
    return _zoomInMode;
}

void LayerManager::setZoomInMode(bool yesno)
{
    _zoomInMode = yesno;
}

bool LayerManager::hasSelectionDrawer() const
{
    return _hasSelectionDrawer;
}

void LayerManager::setHasSelectionDrawer(bool yesno)
{
    _hasSelectionDrawer = yesno;
}

void LayerManager::layersView(LayersViewCommandInterface *view)
{
    _layersView = view;
}

QQmlListProperty<CoverageLayerModel> LayerManager::layers()
{
    return QQmlListProperty<CoverageLayerModel>(this, _layers);
}

CoverageLayerModel *LayerManager::layer(quint32 layerIndex){
    if ( layerIndex < _layers.size())
        return _layers[layerIndex];
    return 0;
}

QString LayerManager::layerInfo(const Coordinate &crd, const QString& attrName) const
{
    std::vector<QString> texts;
    for(CoverageLayerModel *layer : _layers){
        if ( layer->object().isValid() && hasType(layer->object()->ilwisType(), itCOVERAGE)){
            ICoverage cov = layer->object().as<Coverage>();
            QVariant value = cov->coord2value(crd,layer->activeAttribute());
            if ( value.isValid()){
                texts.push_back(value.toString());
            }
        }

    }
    QString outtext;
    for(auto txt : texts){
        if ( outtext.size() != 0)
            outtext += "; ";
        outtext += txt;
    }
    if ( outtext == "")
        outtext = "?";
    return outtext;
}

void LayerManager::init()
{

}
<|endoftext|>


<commit_before>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialogopen.h"
#include "dialognew.h"

#include <QDirModel>
#include <QFileDialog>

#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    folderHistory(new QStack<QString>),
    folderForwardHistory(new QStack<QString>)
{
    // Setup the UI
    ui->setupUi(this);

    // Create the partition safe instance
    psInstance = new PartitionSafe();

    // Temporary
    initializeVault("/tmp/marc.vault", "/tmp/marc.keystore");

    // Show path in status bar
    this->setPath();
}

MainWindow::~MainWindow()
{
    delete ui;
    delete folderHistory;
    delete folderForwardHistory;
    delete model;
    delete modelDirs;
}

void MainWindow::on_treeViewExplorer_doubleClicked(const QModelIndex &index)
{
    // We should get the selected item
    Entry* item = model->getFile(index);

    // Only continue if it's a directory
    if(!item->isDirectory()) return;

    // Get the path
    QString path = QString(item->getFullPath().c_str());

    // Add history to stack
    folderHistory->append(model->getCurrentDirectory());

    // Set directory
    model->setCurrentDirectory(path);

    // clear forward if it doesn't contain dir
    // else pop from ForwardHistory
    if (!folderForwardHistory->contains(path)) folderForwardHistory->clear();
    else folderForwardHistory->pop();

    // Show path in status bar
    this->setPath();
}

void MainWindow::on_treeViewFiles_clicked(const QModelIndex &index)
{
//    this->on_treeViewExplorer_doubleClicked(index);
}

void MainWindow::on_buttonBack_clicked()
{
    // More than only the home item
    if(folderHistory->size() > 0)
    {
        // Get the first item of the stack
        QString dir = folderHistory->pop();

        // Add to folderForwardHistory
        folderForwardHistory->append(model->getCurrentDirectory());

        // Set directory
        model->setCurrentDirectory(dir);
    }

    // Show path in status bar
    this->setPath();
}

void MainWindow::on_buttonForward_clicked()
{
    // If there is a Forward
    if(folderForwardHistory->size() > 0)
    {
        // Get first item of the forward stack
        QString dir = folderForwardHistory->pop();

        // Append dir to folderHistory
        folderHistory->append(model->getCurrentDirectory());

        // Set directory
        model->setCurrentDirectory(dir);
    }

    // Show path in status bar
    this->setPath();
}

void MainWindow::on_actionOpen_triggered()
{
    DialogOpen *open = new DialogOpen(this);

    open->exec();
}

void MainWindow::on_actionNew_triggered()
{
    DialogNew *newDialog = new DialogNew(this);

    newDialog->exec();
}

void MainWindow::on_buttonExport_clicked()
{
    exportFiles();
}

void MainWindow::on_buttonImport_clicked()
{
    importFiles();
}

void MainWindow::on_actionFolder_triggered()
{
    importFolder();
}

void MainWindow::on_actionFile_triggered()
{
    importFiles();
}

void MainWindow::on_actionExport_triggered()
{
    exportFiles();
}

void MainWindow::importFiles()
{
    QFileDialog qFile;
    // Allow selecting of multiple files
    qFile.setFileMode(QFileDialog::Directory);
    // Open File dialog
    qFile.exec();

    qDebug() << qFile.directory().entryList();
    foreach (QString filePath, qFile.selectedFiles()) {
        qDebug() << filePath;

        // TODO: import file from filePath
    }
}

void MainWindow::importFolder(){
        qDebug() << "importFolder() called";
}

void MainWindow::exportFiles()
{
    QModelIndexList selectedRowsList = ui->treeViewExplorer->selectionModel()->selectedRows();
    foreach (QModelIndex index, selectedRowsList)
    {
//        qDebug() << modelDirs->filePath(index);

        // TODO: Export selected file.
    }
}

void MainWindow::initializeVault(const QString vaultPath, const QString keyStorePath)
{
    // Convert names
    const char *cVaultPath = vaultPath.toStdString().c_str();
    const char *cKeyStorePath = keyStorePath.toStdString().c_str();

    // Setup vault
    psInstance->init(cVaultPath, cKeyStorePath);
    psInstance->open();

    // Create file system models
    model = new PSFileSystemModel(this, psInstance);
    modelDirs = new PSFileSystemModel(this, psInstance);

    // Set models in views
    ui->treeViewExplorer->setModel(model);
    ui->treeViewFiles->setModel(modelDirs);
}

void MainWindow::setPath()
{
    // Show message
    ui->statusBar->showMessage(model->getCurrentDirectory());

    // At last item? Disable back button.
    ui->buttonBack->setEnabled(folderHistory->size() > 0);

    // At last forward item? Disable forward button.
    ui->buttonForward->setEnabled(folderForwardHistory->size() > 0);
}
<commit_msg>changed file paths to latin1<commit_after>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialogopen.h"
#include "dialognew.h"

#include <QDirModel>
#include <QFileDialog>

#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    folderHistory(new QStack<QString>),
    folderForwardHistory(new QStack<QString>)
{
    // Setup the UI
    ui->setupUi(this);

    // Create the partition safe instance
    psInstance = new PartitionSafe();

    // Temporary
    initializeVault("/tmp/marc.vault", "/tmp/marc.keystore");

    // Show path in status bar
    this->setPath();
}

MainWindow::~MainWindow()
{
    delete ui;
    delete folderHistory;
    delete folderForwardHistory;
    delete model;
    delete modelDirs;
}

void MainWindow::on_treeViewExplorer_doubleClicked(const QModelIndex &index)
{
    // We should get the selected item
    Entry* item = model->getFile(index);

    // Only continue if it's a directory
    if(!item->isDirectory()) return;

    // Get the path
    QString path = QString(item->getFullPath().c_str());

    // Add history to stack
    folderHistory->append(model->getCurrentDirectory());

    // Set directory
    model->setCurrentDirectory(path);

    // clear forward if it doesn't contain dir
    // else pop from ForwardHistory
    if (!folderForwardHistory->contains(path)) folderForwardHistory->clear();
    else folderForwardHistory->pop();

    // Show path in status bar
    this->setPath();
}

void MainWindow::on_treeViewFiles_clicked(const QModelIndex &index)
{
//    this->on_treeViewExplorer_doubleClicked(index);
}

void MainWindow::on_buttonBack_clicked()
{
    // More than only the home item
    if(folderHistory->size() > 0)
    {
        // Get the first item of the stack
        QString dir = folderHistory->pop();

        // Add to folderForwardHistory
        folderForwardHistory->append(model->getCurrentDirectory());

        // Set directory
        model->setCurrentDirectory(dir);
    }

    // Show path in status bar
    this->setPath();
}

void MainWindow::on_buttonForward_clicked()
{
    // If there is a Forward
    if(folderForwardHistory->size() > 0)
    {
        // Get first item of the forward stack
        QString dir = folderForwardHistory->pop();

        // Append dir to folderHistory
        folderHistory->append(model->getCurrentDirectory());

        // Set directory
        model->setCurrentDirectory(dir);
    }

    // Show path in status bar
    this->setPath();
}

void MainWindow::on_actionOpen_triggered()
{
    DialogOpen *open = new DialogOpen(this);

    open->exec();
}

void MainWindow::on_actionNew_triggered()
{
    DialogNew *newDialog = new DialogNew(this);

    newDialog->exec();
}

void MainWindow::on_buttonExport_clicked()
{
    exportFiles();
}

void MainWindow::on_buttonImport_clicked()
{
    importFiles();
}

void MainWindow::on_actionFolder_triggered()
{
    importFolder();
}

void MainWindow::on_actionFile_triggered()
{
    importFiles();
}

void MainWindow::on_actionExport_triggered()
{
    exportFiles();
}

void MainWindow::importFiles()
{
    QFileDialog qFile;
    // Allow selecting of multiple files
    qFile.setFileMode(QFileDialog::Directory);
    // Open File dialog
    qFile.exec();

    qDebug() << qFile.directory().entryList();
    foreach (QString filePath, qFile.selectedFiles()) {
        qDebug() << filePath;

        // TODO: import file from filePath
    }
}

void MainWindow::importFolder(){
        qDebug() << "importFolder() called";
}

void MainWindow::exportFiles()
{
    QModelIndexList selectedRowsList = ui->treeViewExplorer->selectionModel()->selectedRows();
    foreach (QModelIndex index, selectedRowsList)
    {
//        qDebug() << modelDirs->filePath(index);

        // TODO: Export selected file.
    }
}

void MainWindow::initializeVault(const QString vaultPath, const QString keyStorePath)
{
    // Convert names
    const char *cVaultPath = vaultPath.toLatin1().data();
    const char *cKeyStorePath = keyStorePath.toLatin1().data();

    // Setup vault
    psInstance->init(cVaultPath, cKeyStorePath);
    psInstance->open();

    // Create file system models
    model = new PSFileSystemModel(this, psInstance);
    modelDirs = new PSFileSystemModel(this, psInstance);

    // Set models in views
    ui->treeViewExplorer->setModel(model);
    ui->treeViewFiles->setModel(modelDirs);
}

void MainWindow::setPath()
{
    // Show message
    ui->statusBar->showMessage(model->getCurrentDirectory());

    // At last item? Disable back button.
    ui->buttonBack->setEnabled(folderHistory->size() > 0);

    // At last forward item? Disable forward button.
    ui->buttonForward->setEnabled(folderForwardHistory->size() > 0);
}
<|endoftext|>