<commit_before>/*  Copyright (C) 2009  Adenilson Cavalcanti <savagobr@yahoo.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; by version 2 of the License or (at your
 *  choice) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

/* TODO:
 * - store user account details somewhere (KWallet seems a safer approach)
 * - delete/edit: test further, seems to fail from time to time (maybe related
 * with previous)
 * - support more fields: address, fax, photo, etc. This will require new
 * code in libgcal
 * - test with special characters (unicode > 256)
 * - test with lots of contacts (blocking retrieve of contacts can mess with
 * akonadi)
 * - proxy support (already implemented in libgcal): show an advanced option
 * in configuration dialog so user can setup its proxy
 * - code cleanup
 * - unit tests: not sure if really required, libgcal already has lots
 * of tests
 */
#include "googledataresource.h"

#include "settings.h"
#include "settingsadaptor.h"

#include <QtDBus/QDBusConnection>
#include <kabc/addressee.h>
#include <kabc/phonenumber.h>
#include <kabc/key.h>
#include <kabc/errorhandler.h>
#include <qstring.h>
#include <KWindowSystem>
#include <akonadi/changerecorder.h>
#include <akonadi/itemfetchscope.h>
#include <KUrl>

extern "C" {
#include <gcalendar.h>
#include <gcontact.h>
#include <gcal_status.h>
}

/** FIXME: for some reason the 'retrieveItem' functions is not being called.
 * this makes the entries to lack its contents (name, email, etc).
 * I should investigate why and fix, for while this is a workaround:
 * I report the payload in the 'retrieveItems' function.
 */
#define ITEM_BUG_WTF

using namespace Akonadi;

GoogleDataResource::GoogleDataResource( const QString &id )
	: ResourceBase(id), dlgConf(0), authenticated(false)
{
	new SettingsAdaptor( Settings::self() );
	QDBusConnection::sessionBus().registerObject(
		QLatin1String( "/Settings" ), Settings::self(),
		QDBusConnection::ExportAdaptors );

	changeRecorder()->itemFetchScope().fetchFullPayload();

	if (!(gcal = gcal_new(GCONTACT)))
		exit(1);
	gcal_set_store_xml(gcal, 1);
	all_contacts.length = 0;
	all_contacts.entries = NULL;
}

GoogleDataResource::~GoogleDataResource()
{
	gcal_delete(gcal);
	gcal_cleanup_contacts(&all_contacts);
	if (dlgConf)
		delete dlgConf;
}

void GoogleDataResource::retrieveCollections()
{
	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	Collection c;
	c.setParent(Collection::root());
	c.setRemoteId("google-contacts");
	c.setName(name());

	QStringList mimeTypes;
	mimeTypes << "text/directory";
	c.setContentMimeTypes(mimeTypes);

	Collection::List list;
	list << c;
	collectionsRetrieved(list);

}

void GoogleDataResource::retrieveItems( const Akonadi::Collection &collection )
{
	Q_UNUSED( collection );

	Item::List items;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	/* Downloading the contacts can be slow and it is blocking. Will
	 * it mess up with akonadi?
	 */
	if ((result = gcal_get_contacts(gcal, &all_contacts)))
		exit(1);

	/* Each google entry has a unique ID and edit_url */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		Item item(QLatin1String("text/directory"));
		gcal_contact_t contact = gcal_contact_element(&all_contacts, i);

#ifdef ITEM_BUG_WTF
		KABC::Addressee addressee;
		KABC::PhoneNumber number;
		QString temp;

		/* name */
		temp = gcal_contact_get_title(contact);
		addressee.setNameFromString(temp);
		/* email */
		temp = gcal_contact_get_email(contact);
		addressee.insertEmail(temp, true);
		/* TODO: telefone, address, etc */

		item.setPayload<KABC::Addressee>(addressee);

		/* remoteID: etag+edit_url */
		KUrl urlEtag(gcal_contact_get_url(contact));
		urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));

#endif

		item.setRemoteId(urlEtag.url());

		items << item;
	}

	itemsRetrieved(items);
}

bool GoogleDataResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED( parts );
	const QString entry_id = item.remoteId();
	QString temp;
	Item newItem(item);
	gcal_contact_t contact;
	KABC::Addressee addressee;
	KABC::PhoneNumber number;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return false;
	}

	/*
	 * And another question, are the requests in the same sequence that
	 * I informed in 'retrieveItems'? For while, I try to locate the entry...
	 */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		contact = gcal_contact_element(&all_contacts, i);
		/* FIXME: remoteID == edit_url + ETag */
		if (entry_id == gcal_contact_get_id(contact)) {
			/* name */
			temp = gcal_contact_get_title(contact);
			addressee.setNameFromString(temp);

			/* email */
			temp = gcal_contact_get_email(contact);
			addressee.insertEmail(temp, true);

			/* TODO: telefone, address, etc */

			/* remoteID: etag+edit_url */
			KUrl urlEtag(gcal_contact_get_url(contact));
			urlEtag.addQueryItem("etag",
					     gcal_contact_get_etag(contact));

			newItem.setPayload<KABC::Addressee>(addressee);
			newItem.setRemoteId(urlEtag.url());
                        itemRetrieved(newItem);
			return true;
		}

	}

	return false;
}

void GoogleDataResource::aboutToQuit()
{
	// TODO: any cleanup you need to do while there is still an active
	// event loop. The resource will terminate after this method returns
}

void GoogleDataResource::configure( WId windowId )
{
	Q_UNUSED( windowId );
	char *user, *pass;
	int result = -1;
	QByteArray byteUser, bytePass;

	if (!dlgConf)
		dlgConf = new dlgGoogleDataConf;

	if (windowId && dlgConf)
		KWindowSystem::setMainWindow(dlgConf, windowId);

	dlgConf->exec();

	byteUser = dlgConf->eAccount->text().toLocal8Bit();
	bytePass = dlgConf->ePass->text().toLocal8Bit();
	user = const_cast<char *>(byteUser.constData());
	pass = const_cast<char *>(bytePass.constData());
	if (user)
		if (pass)
			result = gcal_get_authentication(gcal, user, pass);

	/* TODO: in case of authentication error, display an error
	 * message.
	 */
	if (!result)
		authenticated = true;

	synchronize();
}

void GoogleDataResource::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
{

	Q_UNUSED(collection);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	temp = addressee.realName();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_title(contact, t_byte.data());

	temp = addressee.fullEmail();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_email(contact, t_byte.data());

	/* TODO: add remaining fields */

	if ((result = gcal_add_contact(gcal, contact))) {
		kError() << "Failed adding new contact"
			 << "name: " << addressee.realName()
			 << "email: " << addressee.fullEmail();
		const QString message = i18nc("@info:status",
					      "Failed adding new contact");
		emit error(message);
		emit status(Broken, message);

	}

	/* remoteID: etag+edit_url */
	KUrl urlEtag(gcal_contact_get_url(contact));
	urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));

	Item newItem(item);
	newItem.setPayload<KABC::Addressee>(addressee);
	newItem.setRemoteId(urlEtag.url());
	itemRetrieved(newItem);

	/* cleanup */
	gcal_contact_delete(contact);

}

void GoogleDataResource::itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED(parts);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	QByteArray t_byte;
	QString temp;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL))) {
		kError() << "Memory allocation error!";
		const QString message = i18nc("@info:status",
					      "Failed to create gcal_contact");
		emit error(message);
		emit status(Broken, message);
		return;
	}

	temp = addressee.realName();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_title(contact, t_byte.data());

	temp = addressee.fullEmail();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_email(contact, t_byte.data());

	/* TODO: add remaining fields */

	KUrl url(item.remoteId());
	temp = url.queryItem("etag");
	t_byte = temp.toAscii();
	gcal_contact_set_etag(contact, t_byte.data());

	url.removeQueryItem("etag");
	temp = url.url();
	t_byte = temp.toAscii();
	gcal_contact_set_url(contact, t_byte.data());

	if ((result = gcal_update_contact(gcal, contact))) {
		kError() << "Failed editing contact";
		const QString message = i18nc("@info:status",
					      "Failed editing new contact");
		emit error(message);
		emit status(Broken, message);

	}

	/* remoteID: etag+edit_url */
	KUrl urlEtag(gcal_contact_get_url(contact));
	urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));

	Item newItem(item);
	newItem.setPayload<KABC::Addressee>(addressee);
	newItem.setRemoteId(urlEtag.url());
	itemRetrieved(newItem);

	gcal_contact_delete(contact);
}

void GoogleDataResource::itemRemoved( const Akonadi::Item &item )
{
	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);
		emit status(Broken, message);
		return;
	}

	if (!(contact = gcal_contact_new(NULL))) {
		kError() << "Memory allocation error!";
		const QString message = i18nc("@info:status",
					      "Failed to create gcal_contact");
		emit error(message);
		emit status(Broken, message);
		return;
	}

	KUrl url(item.remoteId());
	temp = url.queryItem("etag");
	t_byte = temp.toAscii();
	gcal_contact_set_etag(contact, t_byte.data());

	url.removeQueryItem("etag");
	temp = url.url();
	t_byte = temp.toAscii();
	gcal_contact_set_url(contact, t_byte.data());

	if ((result = gcal_erase_contact(gcal, contact))) {
		kError() << "Failed deleting contact";
		const QString message = i18nc("@info:status",
					      "Failed deleting new contact");
		emit error(message);
		emit status(Broken, message);

	}

	gcal_contact_delete(contact);
}

AKONADI_RESOURCE_MAIN( GoogleDataResource )

#include "googledataresource.moc"
<commit_msg>Some more todos.<commit_after>/*  Copyright (C) 2009  Adenilson Cavalcanti <savagobr@yahoo.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; by version 2 of the License or (at your
 *  choice) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

/* TODO:
 * - store user account details somewhere (KWallet seems a safer approach)
 * - make libgcal function parameters 'const'
 * - delete/edit: test further, seems to fail from time to time (maybe related
 * with previous)
 * - support more fields: address, fax, photo, etc. This will require new
 * code in libgcal
 * - test with special characters (unicode > 256)
 * - test with lots of contacts (blocking retrieve of contacts can mess with
 * akonadi)
 * - proxy support (already implemented in libgcal): show an advanced option
 * in configuration dialog so user can setup its proxy
 * - code cleanup
 * - unit tests: not sure if really required, libgcal already has lots
 * of tests
 * - nice to have: a libqcal (using Qt for both networking and XML/XPath parsing)
 */
#include "googledataresource.h"

#include "settings.h"
#include "settingsadaptor.h"

#include <QtDBus/QDBusConnection>
#include <kabc/addressee.h>
#include <kabc/phonenumber.h>
#include <kabc/key.h>
#include <kabc/errorhandler.h>
#include <qstring.h>
#include <KWindowSystem>
#include <akonadi/changerecorder.h>
#include <akonadi/itemfetchscope.h>
#include <KUrl>

extern "C" {
#include <gcalendar.h>
#include <gcontact.h>
#include <gcal_status.h>
}

/** FIXME: for some reason the 'retrieveItem' functions is not being called.
 * this makes the entries to lack its contents (name, email, etc).
 * I should investigate why and fix, for while this is a workaround:
 * I report the payload in the 'retrieveItems' function.
 */
#define ITEM_BUG_WTF

using namespace Akonadi;

GoogleDataResource::GoogleDataResource( const QString &id )
	: ResourceBase(id), dlgConf(0), authenticated(false)
{
	new SettingsAdaptor( Settings::self() );
	QDBusConnection::sessionBus().registerObject(
		QLatin1String( "/Settings" ), Settings::self(),
		QDBusConnection::ExportAdaptors );

	changeRecorder()->itemFetchScope().fetchFullPayload();

	if (!(gcal = gcal_new(GCONTACT)))
		exit(1);
	gcal_set_store_xml(gcal, 1);
	all_contacts.length = 0;
	all_contacts.entries = NULL;
}

GoogleDataResource::~GoogleDataResource()
{
	gcal_delete(gcal);
	gcal_cleanup_contacts(&all_contacts);
	if (dlgConf)
		delete dlgConf;
}

void GoogleDataResource::retrieveCollections()
{
	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	Collection c;
	c.setParent(Collection::root());
	c.setRemoteId("google-contacts");
	c.setName(name());

	QStringList mimeTypes;
	mimeTypes << "text/directory";
	c.setContentMimeTypes(mimeTypes);

	Collection::List list;
	list << c;
	collectionsRetrieved(list);

}

void GoogleDataResource::retrieveItems( const Akonadi::Collection &collection )
{
	Q_UNUSED( collection );

	Item::List items;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	/* Downloading the contacts can be slow and it is blocking. Will
	 * it mess up with akonadi?
	 */
	if ((result = gcal_get_contacts(gcal, &all_contacts)))
		exit(1);

	/* Each google entry has a unique ID and edit_url */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		Item item(QLatin1String("text/directory"));
		gcal_contact_t contact = gcal_contact_element(&all_contacts, i);

#ifdef ITEM_BUG_WTF
		KABC::Addressee addressee;
		KABC::PhoneNumber number;
		QString temp;

		/* name */
		temp = gcal_contact_get_title(contact);
		addressee.setNameFromString(temp);
		/* email */
		temp = gcal_contact_get_email(contact);
		addressee.insertEmail(temp, true);
		/* TODO: telefone, address, etc */

		item.setPayload<KABC::Addressee>(addressee);

		/* remoteID: etag+edit_url */
		KUrl urlEtag(gcal_contact_get_url(contact));
		urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));

#endif

		item.setRemoteId(urlEtag.url());

		items << item;
	}

	itemsRetrieved(items);
}

bool GoogleDataResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED( parts );
	const QString entry_id = item.remoteId();
	QString temp;
	Item newItem(item);
	gcal_contact_t contact;
	KABC::Addressee addressee;
	KABC::PhoneNumber number;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return false;
	}

	/*
	 * And another question, are the requests in the same sequence that
	 * I informed in 'retrieveItems'? For while, I try to locate the entry...
	 */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		contact = gcal_contact_element(&all_contacts, i);
		/* FIXME: remoteID == edit_url + ETag */
		if (entry_id == gcal_contact_get_id(contact)) {
			/* name */
			temp = gcal_contact_get_title(contact);
			addressee.setNameFromString(temp);

			/* email */
			temp = gcal_contact_get_email(contact);
			addressee.insertEmail(temp, true);

			/* TODO: telefone, address, etc */

			/* remoteID: etag+edit_url */
			KUrl urlEtag(gcal_contact_get_url(contact));
			urlEtag.addQueryItem("etag",
					     gcal_contact_get_etag(contact));

			newItem.setPayload<KABC::Addressee>(addressee);
			newItem.setRemoteId(urlEtag.url());
                        itemRetrieved(newItem);
			return true;
		}

	}

	return false;
}

void GoogleDataResource::aboutToQuit()
{
	// TODO: any cleanup you need to do while there is still an active
	// event loop. The resource will terminate after this method returns
}

void GoogleDataResource::configure( WId windowId )
{
	Q_UNUSED( windowId );
	char *user, *pass;
	int result = -1;
	QByteArray byteUser, bytePass;

	if (!dlgConf)
		dlgConf = new dlgGoogleDataConf;

	if (windowId && dlgConf)
		KWindowSystem::setMainWindow(dlgConf, windowId);

	dlgConf->exec();

	byteUser = dlgConf->eAccount->text().toLocal8Bit();
	bytePass = dlgConf->ePass->text().toLocal8Bit();
	user = const_cast<char *>(byteUser.constData());
	pass = const_cast<char *>(bytePass.constData());
	if (user)
		if (pass)
			result = gcal_get_authentication(gcal, user, pass);

	/* TODO: in case of authentication error, display an error
	 * message.
	 */
	if (!result)
		authenticated = true;

	synchronize();
}

void GoogleDataResource::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
{

	Q_UNUSED(collection);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	temp = addressee.realName();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_title(contact, t_byte.data());

	temp = addressee.fullEmail();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_email(contact, t_byte.data());

	/* TODO: add remaining fields */

	if ((result = gcal_add_contact(gcal, contact))) {
		kError() << "Failed adding new contact"
			 << "name: " << addressee.realName()
			 << "email: " << addressee.fullEmail();
		const QString message = i18nc("@info:status",
					      "Failed adding new contact");
		emit error(message);
		emit status(Broken, message);

	}

	/* remoteID: etag+edit_url */
	KUrl urlEtag(gcal_contact_get_url(contact));
	urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));

	Item newItem(item);
	newItem.setPayload<KABC::Addressee>(addressee);
	newItem.setRemoteId(urlEtag.url());
	itemRetrieved(newItem);

	/* cleanup */
	gcal_contact_delete(contact);

}

void GoogleDataResource::itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED(parts);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	QByteArray t_byte;
	QString temp;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL))) {
		kError() << "Memory allocation error!";
		const QString message = i18nc("@info:status",
					      "Failed to create gcal_contact");
		emit error(message);
		emit status(Broken, message);
		return;
	}

	temp = addressee.realName();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_title(contact, t_byte.data());

	temp = addressee.fullEmail();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_email(contact, t_byte.data());

	/* TODO: add remaining fields */

	KUrl url(item.remoteId());
	temp = url.queryItem("etag");
	t_byte = temp.toAscii();
	gcal_contact_set_etag(contact, t_byte.data());

	url.removeQueryItem("etag");
	temp = url.url();
	t_byte = temp.toAscii();
	gcal_contact_set_url(contact, t_byte.data());

	if ((result = gcal_update_contact(gcal, contact))) {
		kError() << "Failed editing contact";
		const QString message = i18nc("@info:status",
					      "Failed editing new contact");
		emit error(message);
		emit status(Broken, message);

	}

	/* remoteID: etag+edit_url */
	KUrl urlEtag(gcal_contact_get_url(contact));
	urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));

	Item newItem(item);
	newItem.setPayload<KABC::Addressee>(addressee);
	newItem.setRemoteId(urlEtag.url());
	itemRetrieved(newItem);

	gcal_contact_delete(contact);
}

void GoogleDataResource::itemRemoved( const Akonadi::Item &item )
{
	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);
		emit status(Broken, message);
		return;
	}

	if (!(contact = gcal_contact_new(NULL))) {
		kError() << "Memory allocation error!";
		const QString message = i18nc("@info:status",
					      "Failed to create gcal_contact");
		emit error(message);
		emit status(Broken, message);
		return;
	}

	KUrl url(item.remoteId());
	temp = url.queryItem("etag");
	t_byte = temp.toAscii();
	gcal_contact_set_etag(contact, t_byte.data());

	url.removeQueryItem("etag");
	temp = url.url();
	t_byte = temp.toAscii();
	gcal_contact_set_url(contact, t_byte.data());

	if ((result = gcal_erase_contact(gcal, contact))) {
		kError() << "Failed deleting contact";
		const QString message = i18nc("@info:status",
					      "Failed deleting new contact");
		emit error(message);
		emit status(Broken, message);

	}

	gcal_contact_delete(contact);
}

AKONADI_RESOURCE_MAIN( GoogleDataResource )

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


<commit_before>#include <world.h>

#define getWidth() (lineCount*HLINE)

#define GEN_INC 10
#define GRASS_HEIGHT 4

World::World(unsigned int width){
	unsigned int i;
	float inc;
	lineCount=width+GEN_INC;
	line=(struct line_t *)calloc(lineCount,sizeof(struct line_t));	// allocate space for the array of lines
	line[0].y=80;
	for(i=GEN_INC;i<lineCount;i+=GEN_INC){
		line[i].y=rand()%8-4+line[i-GEN_INC].y;
		if(line[i].y<60)line[i].y=60;
		if(line[i].y>110)line[i].y=110;
	}
	for(i=0;i<lineCount-GEN_INC;i++){
		if(!i||!(i%GEN_INC)){
			inc=(line[i+GEN_INC].y-line[i].y)/(float)GEN_INC;
		}else{
			line[i].y=line[i-1].y+inc;
		}
		line[i].color=rand()%20+130;
	}
	/*line[0].y=50;
	for(i=1;i<lineCount-20;i++){
		line[i].y=rand()%5-2+line[i-1].y;
		if(line[i].y<30)line[i].y=30;
	}*/
}

World::~World(void){
	free(line);
}

void World::draw(vec2 *vec){
	int i,ie,v_offset;
	x_start=0-getWidth()/2+GEN_INC/2*HLINE;
	v_offset=(vec->x-x_start)/HLINE;
	i=v_offset-SCREEN_WIDTH/2;
	if(i<0)i=0;
	ie=v_offset+SCREEN_WIDTH/2;
	if(ie>lineCount)ie=lineCount;
	glBegin(GL_QUADS);
		for(i=i;i<ie;i++){
			glColor3ub(0,200,0);
			glVertex2i(x_start+i*HLINE      ,line[i].y);
			glVertex2i(x_start+i*HLINE+HLINE,line[i].y);
			glVertex2i(x_start+i*HLINE+HLINE,line[i].y-GRASS_HEIGHT);
			glVertex2i(x_start+i*HLINE		,line[i].y-GRASS_HEIGHT);
			glColor3ub(line[i].color,line[i].color-50,line[i].color-100);
			glVertex2i(x_start+i*HLINE      ,line[i].y-GRASS_HEIGHT);
			glVertex2i(x_start+i*HLINE+HLINE,line[i].y-GRASS_HEIGHT);
			glVertex2i(x_start+i*HLINE+HLINE,0);
			glVertex2i(x_start+i*HLINE		,0);
		}
	glEnd();
}

void World::detect(vec2 *v,vec2 *vel,const float width){
	unsigned int i;
	i=(v->x+width/2-x_start)/HLINE;
	if(v->y<=line[i].y){
		vel->y=0;
		v->y=line[i].y+HLINE/2;
		return;
	}else{
		vel->y-=.05;
		return;
	}
}
<commit_msg>world bound checks<commit_after>#include <world.h>

#define getWidth() (lineCount*HLINE)

#define GEN_INC 10
#define GRASS_HEIGHT 4

World::World(unsigned int width){
	unsigned int i;
	float inc;
	lineCount=width+GEN_INC;
	line=(struct line_t *)calloc(lineCount,sizeof(struct line_t));	// allocate space for the array of lines
	line[0].y=80;
	for(i=GEN_INC;i<lineCount;i+=GEN_INC){
		line[i].y=rand()%8-4+line[i-GEN_INC].y;
		if(line[i].y<60)line[i].y=60;
		if(line[i].y>110)line[i].y=110;
	}
	for(i=0;i<lineCount-GEN_INC;i++){
		if(!i||!(i%GEN_INC)){
			inc=(line[i+GEN_INC].y-line[i].y)/(float)GEN_INC;
		}else{
			line[i].y=line[i-1].y+inc;
		}
		line[i].color=rand()%20+130;
	}
	/*line[0].y=50;
	for(i=1;i<lineCount-20;i++){
		line[i].y=rand()%5-2+line[i-1].y;
		if(line[i].y<30)line[i].y=30;
	}*/
}

World::~World(void){
	free(line);
}

void World::draw(vec2 *vec){
	int i,ie,v_offset;
	x_start=0-getWidth()/2+GEN_INC/2*HLINE;
	v_offset=(vec->x-x_start)/HLINE;
	i=v_offset-SCREEN_WIDTH/2;
	if(i<0)i=0;
	ie=v_offset+SCREEN_WIDTH/2;
	if(ie>lineCount)ie=lineCount;
	glBegin(GL_QUADS);
		for(i=i;i<ie;i++){
			glColor3ub(0,200,0);
			glVertex2i(x_start+i*HLINE      ,line[i].y);
			glVertex2i(x_start+i*HLINE+HLINE,line[i].y);
			glVertex2i(x_start+i*HLINE+HLINE,line[i].y-GRASS_HEIGHT);
			glVertex2i(x_start+i*HLINE		,line[i].y-GRASS_HEIGHT);
			glColor3ub(line[i].color,line[i].color-50,line[i].color-100);
			glVertex2i(x_start+i*HLINE      ,line[i].y-GRASS_HEIGHT);
			glVertex2i(x_start+i*HLINE+HLINE,line[i].y-GRASS_HEIGHT);
			glVertex2i(x_start+i*HLINE+HLINE,0);
			glVertex2i(x_start+i*HLINE		,0);
		}
	glEnd();
}

void World::detect(vec2 *v,vec2 *vel,const float width){
	unsigned int i;
	// Vertical checks
	i=(v->x+width/2-x_start)/HLINE;
	if(v->y<=line[i].y){
		vel->y=0;
		v->y=line[i].y+HLINE/2;
	}else{
		vel->y-=.05;
	}
	// Horizontal checks
	if(v->x<x_start){
		vel->x=0;
		v->x=x_start+HLINE/2;
	}else if(v->x>x_start+getWidth()){
		vel->x=0;
		v->x=x_start+getWidth()-width-HLINE/2;
	}
}
<|endoftext|>


<commit_before>#include <fstream>
#include <variant>
#include <boost/hana/functional/overload.hpp>
#include <tmxpp.hpp>
#include <tmxpp/exceptions.hpp>
#include <tmxpp/impl/Xml.hpp>
#include <tmxpp/impl/tmx_info.hpp>
#include <tmxpp/impl/to_string_color.hpp>
#include <tmxpp/impl/write_utility.hpp>

namespace tmxpp {

namespace impl {
namespace {

using namespace tmx_info;

void write(iSize sz, Xml::Element elem)
{
    add(elem, size_width, to_string(sz.w));
    add(elem, size_height, to_string(sz.h));
}

void write_tile(pxSize sz, Xml::Element elem)
{
    add(elem, tile_size_width, to_string(sz.w));
    add(elem, tile_size_height, to_string(sz.h));
}

// Map -------------------------------------------------------------------------

void write(Map::Render_order ro, Xml::Element map)
{
    map.add(map_render_order, [ro] {
        switch (ro) {
        case Map::Render_order::right_down: return map_render_order_right_down;
        case Map::Render_order::right_up: return map_render_order_right_up;
        case Map::Render_order::left_down: return map_render_order_left_down;
        case Map::Render_order::left_up: return map_render_order_left_up;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered::Axis a, Xml::Element map)
{
    map.add(map_staggered_axis, [a] {
        switch (a) {
        case Map::Staggered::Axis::x: return map_staggered_axis_x;
        case Map::Staggered::Axis::y: return map_staggered_axis_y;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered::Index i, Xml::Element map)
{
    map.add(map_staggered_index, [i] {
        switch (i) {
        case Map::Staggered::Index::even: return map_staggered_index_even;
        case Map::Staggered::Index::odd: return map_staggered_index_odd;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered s, Xml::Element map)
{
    write(s.axis, map);
    write(s.index, map);
}

void write(Map::Hexagonal h, Xml::Element map)
{
    add(map, map_hexagonal_side_legth, to_string(h.side_length));
    write(static_cast<Map::Staggered>(h), map);
}

void write(
    Map::Orientation orient, Map::Render_order render_order, Xml::Element map)
{
    auto add = [=](Xml::Attribute::Value orient) {
        map.add(map_orientation, orient);

        write(render_order, map);
    };

    std::visit(
        boost::hana::overload(
            [=](Map::Orthogonal) { add(map_orthogonal); },
            [=](Map::Isometric) { add(map_isometric); },
            [=](Map::Staggered s) {
                add(map_staggered);
                write(s, map);
            },
            [=](Map::Hexagonal h) {
                add(map_hexagonal);
                write(h, map);
            }),
        orient);
}

void write(const Map& map, Xml::Element elem)
{
    add(elem, map_version, map.version);
    write(map.orientation, map.render_order, elem);
    write(map.size, elem);
    write_tile(map.general_tile_size, elem);
    if (auto bg{map.background})
        add(elem, map_background, to_string(*bg));
    add(elem, map_next_unique_id, to_string(map.next_unique_id));
}

} // namespace
} // namespace impl

void write(const Map& map, gsl::not_null<gsl::czstring<>> path)
{
    impl::Xml tmx{impl::tmx_info::map};

    impl::write(map, tmx.root());

    std::ofstream{path} << tmx;
}

void write(const Map::Tile_set&);
void write(const Tile_set&);
void write(const Image_collection&);

} // namespace tmxpp
<commit_msg>Write Property and Properties elements<commit_after>#include <fstream>
#include <string>
#include <string_view>
#include <variant>
#include <boost/hana/functional/overload.hpp>
#include <tmxpp.hpp>
#include <tmxpp/exceptions.hpp>
#include <tmxpp/impl/Xml.hpp>
#include <tmxpp/impl/tmx_info.hpp>
#include <tmxpp/impl/to_string_color.hpp>
#include <tmxpp/impl/write_utility.hpp>

namespace tmxpp {

namespace impl {
namespace {

using namespace tmx_info;

void write(iSize sz, Xml::Element elem)
{
    add(elem, size_width, to_string(sz.w));
    add(elem, size_height, to_string(sz.h));
}

void write_tile(pxSize sz, Xml::Element elem)
{
    add(elem, tile_size_width, to_string(sz.w));
    add(elem, tile_size_height, to_string(sz.h));
}

// Properties ------------------------------------------------------------------

void write(const Property::Value& value, Xml::Element prop)
{
    auto add = [=](Xml::Attribute::Value alternative, std::string_view value) {
        prop.add(property_alternative, alternative);
        impl::add(prop, property_value, value);
    };

    std::visit(
        boost::hana::overload(
            [=](int i) { add(property_alternative_int, to_string(i)); },
            [=](double d) { add(property_alternative_double, to_string(d)); },
            [=](bool b) {
                add(property_alternative_bool,
                    get(b ? property_value_true : property_value_false));
            },
            [=](Color c) { add(property_alternative_color, to_string(c)); },
            [=](File f) { add(property_alternative_file, f.string()); },
            [=](const std::string& s) {
                prop.add(property_alternative, property_alternative_string);

                if (bool is_multiline{s.find('\n') != std::string::npos})
                    prop.value(Xml::Element::Value{s});
                else
                    impl::add(prop, property_value, s);
            }),
        value);
}

void write(const Property& p, Xml::Element elem)
{
    add(elem, property_name, p.name);
    write(p.value, elem);
}

void write(const Properties& ps, Xml::Element parent)
{
    auto elem{parent.add(properties)};

    for (const auto& p : ps)
        write(p, elem.add(property));
}

// Map -------------------------------------------------------------------------

void write(Map::Render_order ro, Xml::Element map)
{
    map.add(map_render_order, [ro] {
        switch (ro) {
        case Map::Render_order::right_down: return map_render_order_right_down;
        case Map::Render_order::right_up: return map_render_order_right_up;
        case Map::Render_order::left_down: return map_render_order_left_down;
        case Map::Render_order::left_up: return map_render_order_left_up;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered::Axis a, Xml::Element map)
{
    map.add(map_staggered_axis, [a] {
        switch (a) {
        case Map::Staggered::Axis::x: return map_staggered_axis_x;
        case Map::Staggered::Axis::y: return map_staggered_axis_y;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered::Index i, Xml::Element map)
{
    map.add(map_staggered_index, [i] {
        switch (i) {
        case Map::Staggered::Index::even: return map_staggered_index_even;
        case Map::Staggered::Index::odd: return map_staggered_index_odd;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered s, Xml::Element map)
{
    write(s.axis, map);
    write(s.index, map);
}

void write(Map::Hexagonal h, Xml::Element map)
{
    add(map, map_hexagonal_side_legth, to_string(h.side_length));
    write(static_cast<Map::Staggered>(h), map);
}

void write(
    Map::Orientation orient, Map::Render_order render_order, Xml::Element map)
{
    auto add = [=](Xml::Attribute::Value orient) {
        map.add(map_orientation, orient);

        write(render_order, map);
    };

    std::visit(
        boost::hana::overload(
            [=](Map::Orthogonal) { add(map_orthogonal); },
            [=](Map::Isometric) { add(map_isometric); },
            [=](Map::Staggered s) {
                add(map_staggered);
                write(s, map);
            },
            [=](Map::Hexagonal h) {
                add(map_hexagonal);
                write(h, map);
            }),
        orient);
}

void write(const Map& map, Xml::Element elem)
{
    add(elem, map_version, map.version);
    write(map.orientation, map.render_order, elem);
    write(map.size, elem);
    write_tile(map.general_tile_size, elem);
    if (auto bg{map.background})
        add(elem, map_background, to_string(*bg));
    add(elem, map_next_unique_id, to_string(map.next_unique_id));
    write(map.properties, elem);
}

} // namespace
} // namespace impl

void write(const Map& map, gsl::not_null<gsl::czstring<>> path)
{
    impl::Xml tmx{impl::tmx_info::map};

    impl::write(map, tmx.root());

    std::ofstream{path} << tmx;
}

void write(const Map::Tile_set&);
void write(const Tile_set&);
void write(const Image_collection&);

} // namespace tmxpp
<|endoftext|>


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

#include <EASTL/sort.h>

#include "../Core/CoreEvents.h"
#include "../Core/StringUtils.h"
#include "../Engine/PluginApplication.h"
#include "../Graphics/Camera.h"
#include "../Graphics/Graphics.h"
#include "../Graphics/RenderPath.h"
#include "../IO/FileSystem.h"
#include "../IO/Log.h"
#include "../Resource/ResourceCache.h"
#include "../Resource/XMLFile.h"
#include "../Scene/CameraViewport.h"
#include "../Scene/Node.h"
#include "../Scene/Scene.h"
#include "../Scene/SceneEvents.h"

namespace Urho3D
{

static ResourceRef defaultRenderPath{XMLFile::GetTypeStatic(), "RenderPaths/Forward.xml"};

CameraViewport::CameraViewport(Context* context)
    : Component(context)
    , viewport_(context->CreateObject<Viewport>())
    , rect_(fullScreenViewport)
    , renderPath_(defaultRenderPath)
    , screenRect_{0, 0, 1920, 1080}
{
    if (Graphics* graphics = context_->GetSubsystem<Graphics>())
        screenRect_ = {0, 0, graphics->GetWidth(), graphics->GetHeight()};
}

void CameraViewport::SetNormalizedRect(const Rect& rect)
{
    rect_ = rect;
    IntRect screenRect = GetScreenRect();
    IntRect viewportRect(static_cast<int>(rect.Left() * screenRect.Left()), static_cast<int>(rect.Top() * screenRect.Top()),
        static_cast<int>(rect.Right() * screenRect.Right()), static_cast<int>(rect.Bottom() * screenRect.Bottom()));
    viewport_->SetRect(viewportRect);

    using namespace CameraViewportResized;
    VariantMap args{};
    args[P_VIEWPORT] = GetViewport();
    args[P_CAMERA] = GetViewport()->GetCamera();
    args[P_SIZE] = viewportRect;
    args[P_SIZENORM] = rect;
    SendEvent(E_CAMERAVIEWPORTRESIZED, args);
}

void CameraViewport::RegisterObject(Context* context)
{
    context->RegisterFactory<CameraViewport>("Scene");
}

void CameraViewport::OnNodeSet(Node* node)
{
    if (node == nullptr)
        viewport_->SetCamera(nullptr);
    else
    {
        SubscribeToEvent(node, E_COMPONENTADDED, [this](StringHash, VariantMap& args) {
            using namespace ComponentAdded;
            if (Component* component = static_cast<Component*>(args[P_COMPONENT].GetPtr()))
            {
                if (Camera* camera = component->Cast<Camera>())
                {
                    viewport_->SetCamera(camera);
                    camera->SetViewMask(camera->GetViewMask() & ~(1U << 31U));   // Do not render last layer.
                }
            }
        });
        SubscribeToEvent(node, E_COMPONENTREMOVED, [this](StringHash, VariantMap& args) {
            using namespace ComponentRemoved;
            if (Component* component = static_cast<Component*>(args[P_COMPONENT].GetPtr()))
            {
                if (component->GetType() == Camera::GetTypeStatic())
                    viewport_->SetCamera(nullptr);
            }
        });

        if (Camera* camera = node->GetComponent<Camera>())
        {
            viewport_->SetCamera(camera);
            camera->SetViewMask(camera->GetViewMask() & ~(1U << 31U));   // Do not render last layer.
        }
        else
        {
            // If this node does not have a camera - get or create it on next frame. This is required because Camera may
            // be created later when deserializing node.
            SubscribeToEvent(E_BEGINFRAME, [this](StringHash, VariantMap& args) {
                if (Node* node = GetNode())
                {
                    if (Camera* camera = node->GetOrCreateComponent<Camera>())
                    {
                        viewport_->SetCamera(camera);
                        camera->SetViewMask(camera->GetViewMask() & ~(1U << 31U));   // Do not render last layer.
                    }
                }
                UnsubscribeFromEvent(E_BEGINFRAME);
            });
        }
    }
}

void CameraViewport::OnSceneSet(Scene* scene)
{
    viewport_->SetScene(scene);
}

IntRect CameraViewport::GetScreenRect() const
{
    return screenRect_;
}

const ea::vector<AttributeInfo>* CameraViewport::GetAttributes() const
{
    if (attributesDirty_)
        const_cast<CameraViewport*>(this)->RebuildAttributes();
    return &attributes_;
}

template<typename T>
AttributeInfo& CameraViewport::RegisterAttribute(const AttributeInfo& attr)
{
    attributes_.push_back(attr);
    return attributes_.back();
}

void CameraViewport::RebuildAttributes()
{
    auto* context = this;
    // Normal attributes.
    URHO3D_ACCESSOR_ATTRIBUTE("Viewport", GetNormalizedRect, SetNormalizedRect, Rect, fullScreenViewport, AM_DEFAULT);
    URHO3D_ACCESSOR_ATTRIBUTE("RenderPath", GetLastRenderPath, SetRenderPath, ResourceRef, defaultRenderPath, AM_DEFAULT);

    // PostProcess effects are special. One file may contain multiple effects that can be enabled or disabled.
    {
        effects_.clear();
        for (const auto& dir: context_->GetSubsystem<ResourceCache>()->GetResourceDirs())
        {
            ea::vector<ea::string> effects;
            ea::string resourcePath = "PostProcess/";
            ea::string scanDir = AddTrailingSlash(dir) + resourcePath;
            context_->GetSubsystem<FileSystem>()->ScanDir(effects, scanDir, "*.xml", SCAN_FILES, false);

            for (const auto& effectFileName: effects)
            {
                auto effectPath = resourcePath + effectFileName;
                auto* effect = context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(effectPath);

                auto root = effect->GetRoot();
                ea::string tag;
                for (auto command = root.GetChild("command"); command.NotNull(); command = command.GetNext("command"))
                {
                    tag = command.GetAttribute("tag");

                    if (tag.empty())
                    {
                        URHO3D_LOGWARNING("Invalid PostProcess effect with empty tag");
                        continue;
                    }

                    if (effects_.find(tag) != effects_.end())
                        continue;

                    effects_[tag] = resourcePath + effectFileName;
                }
            }
        }

        StringVector tags = effects_.keys();
        ea::quick_sort(tags.begin(), tags.end());

        for (auto& effect : effects_)
        {
            auto getter = [this, &effect](const CameraViewport&, Variant& value) {
                if (RenderPath* renderPath = viewport_->GetRenderPath())
                    value = renderPath->IsEnabled(effect.first);
                else
                    value = false;
            };

            auto setter = [this, &effect](const CameraViewport&, const Variant& value) {
                RenderPath* path = viewport_->GetRenderPath();
                if (!path)
                    return;
                if (!path->IsAdded(effect.first))
                    path->Append(context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(effect.second));
                path->SetEnabled(effect.first, value.GetBool());
            };
            URHO3D_CUSTOM_ACCESSOR_ATTRIBUTE(effect.first.c_str(), getter, setter, bool, false, AM_DEFAULT);
        }
    }

    attributesDirty_ = false;
}

RenderPath* CameraViewport::RebuildRenderPath()
{
    if (!viewport_)
        return nullptr;

    SharedPtr<RenderPath> oldRenderPath(viewport_->GetRenderPath());

    if (XMLFile* renderPathFile = context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(renderPath_.name_))
    {
        viewport_->SetRenderPath(renderPathFile);
        RenderPath* newRenderPath = viewport_->GetRenderPath();

        for (const auto& effect : effects_)
        {
            if (oldRenderPath->IsEnabled(effect.first))
            {
                if (!newRenderPath->IsAdded(effect.first))
                    newRenderPath->Append(context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(effect.second));
                newRenderPath->SetEnabled(effect.first, true);
            }
        }

        return newRenderPath;
    }

    return nullptr;
}

void CameraViewport::SetRenderPath(const ResourceRef& renderPathResource)
{
    if (!viewport_ || !context_->GetSubsystem<Graphics>())
        return;

    if (!renderPathResource.name_.empty() && renderPathResource.type_ != XMLFile::GetTypeStatic())
    {
        URHO3D_LOGWARNINGF("Incorrect RenderPath file '%s' type.", renderPathResource.name_.c_str());
        return;
    }

    SharedPtr<RenderPath> oldRenderPath(viewport_->GetRenderPath());

    const ea::string& renderPathFileName = renderPathResource.name_.empty() ? defaultRenderPath.name_ : renderPathResource.name_;
    if (XMLFile* renderPathFile = context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(renderPathFileName))
    {
        if (!viewport_->SetRenderPath(renderPathFile))
        {
            URHO3D_LOGERRORF("Loading renderpath from %s failed. File probably is not a renderpath.",
                renderPathFileName.c_str());
            return;
        }
        RenderPath* newRenderPath = viewport_->GetRenderPath();

        for (const auto& effect : effects_)
        {
            if (oldRenderPath->IsEnabled(effect.first))
            {
                if (!newRenderPath->IsAdded(effect.first))
                    newRenderPath->Append(context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(effect.second));
                newRenderPath->SetEnabled(effect.first, true);
            }
        }

        renderPath_.name_ = renderPathFileName;
    }
    else
    {
        URHO3D_LOGERRORF("Loading renderpath from %s failed. File is missing or you have no permissions to read it.",
                         renderPathFileName.c_str());
    }
}

void CameraViewport::UpdateViewport()
{
    SetNormalizedRect(GetNormalizedRect());
}

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

#include <EASTL/sort.h>

#include "../Core/CoreEvents.h"
#include "../Core/StringUtils.h"
#include "../Engine/PluginApplication.h"
#include "../Graphics/Camera.h"
#include "../Graphics/Graphics.h"
#include "../Graphics/RenderPath.h"
#include "../IO/FileSystem.h"
#include "../IO/Log.h"
#include "../Resource/ResourceCache.h"
#include "../Resource/XMLFile.h"
#include "../Scene/CameraViewport.h"
#include "../Scene/Node.h"
#include "../Scene/Scene.h"
#include "../Scene/SceneEvents.h"

namespace Urho3D
{

static ResourceRef defaultRenderPath{XMLFile::GetTypeStatic(), "RenderPaths/Forward.xml"};

CameraViewport::CameraViewport(Context* context)
    : Component(context)
    , viewport_(context->CreateObject<Viewport>())
    , rect_(fullScreenViewport)
    , renderPath_(defaultRenderPath)
    , screenRect_{0, 0, 1920, 1080}
{
    if (Graphics* graphics = context_->GetSubsystem<Graphics>())
        screenRect_ = {0, 0, graphics->GetWidth(), graphics->GetHeight()};
}

void CameraViewport::SetNormalizedRect(const Rect& rect)
{
    rect_ = rect;
    IntRect viewportRect(
        static_cast<int>(screenRect_.Left() + screenRect_.Width() * rect.Left()),
        static_cast<int>(screenRect_.Top() + screenRect_.Height() * rect.Top()),
        static_cast<int>(screenRect_.Left() + screenRect_.Width() * rect.Right()),
        static_cast<int>(screenRect_.Top() + screenRect_.Height() * rect.Bottom())
    );
    viewport_->SetRect(viewportRect);

    using namespace CameraViewportResized;
    VariantMap args{};
    args[P_VIEWPORT] = GetViewport();
    args[P_CAMERA] = GetViewport()->GetCamera();
    args[P_SIZE] = viewportRect;
    args[P_SIZENORM] = rect;
    SendEvent(E_CAMERAVIEWPORTRESIZED, args);
}

void CameraViewport::RegisterObject(Context* context)
{
    context->RegisterFactory<CameraViewport>("Scene");
}

void CameraViewport::OnNodeSet(Node* node)
{
    if (node == nullptr)
        viewport_->SetCamera(nullptr);
    else
    {
        SubscribeToEvent(node, E_COMPONENTADDED, [this](StringHash, VariantMap& args) {
            using namespace ComponentAdded;
            if (Component* component = static_cast<Component*>(args[P_COMPONENT].GetPtr()))
            {
                if (Camera* camera = component->Cast<Camera>())
                {
                    viewport_->SetCamera(camera);
                    camera->SetViewMask(camera->GetViewMask() & ~(1U << 31U));   // Do not render last layer.
                }
            }
        });
        SubscribeToEvent(node, E_COMPONENTREMOVED, [this](StringHash, VariantMap& args) {
            using namespace ComponentRemoved;
            if (Component* component = static_cast<Component*>(args[P_COMPONENT].GetPtr()))
            {
                if (component->GetType() == Camera::GetTypeStatic())
                    viewport_->SetCamera(nullptr);
            }
        });

        if (Camera* camera = node->GetComponent<Camera>())
        {
            viewport_->SetCamera(camera);
            camera->SetViewMask(camera->GetViewMask() & ~(1U << 31U));   // Do not render last layer.
        }
        else
        {
            // If this node does not have a camera - get or create it on next frame. This is required because Camera may
            // be created later when deserializing node.
            SubscribeToEvent(E_BEGINFRAME, [this](StringHash, VariantMap& args) {
                if (Node* node = GetNode())
                {
                    if (Camera* camera = node->GetOrCreateComponent<Camera>())
                    {
                        viewport_->SetCamera(camera);
                        camera->SetViewMask(camera->GetViewMask() & ~(1U << 31U));   // Do not render last layer.
                    }
                }
                UnsubscribeFromEvent(E_BEGINFRAME);
            });
        }
    }
}

void CameraViewport::OnSceneSet(Scene* scene)
{
    viewport_->SetScene(scene);
}

IntRect CameraViewport::GetScreenRect() const
{
    return screenRect_;
}

const ea::vector<AttributeInfo>* CameraViewport::GetAttributes() const
{
    if (attributesDirty_)
        const_cast<CameraViewport*>(this)->RebuildAttributes();
    return &attributes_;
}

template<typename T>
AttributeInfo& CameraViewport::RegisterAttribute(const AttributeInfo& attr)
{
    attributes_.push_back(attr);
    return attributes_.back();
}

void CameraViewport::RebuildAttributes()
{
    auto* context = this;
    // Normal attributes.
    URHO3D_ACCESSOR_ATTRIBUTE("Viewport", GetNormalizedRect, SetNormalizedRect, Rect, fullScreenViewport, AM_DEFAULT);
    URHO3D_ACCESSOR_ATTRIBUTE("RenderPath", GetLastRenderPath, SetRenderPath, ResourceRef, defaultRenderPath, AM_DEFAULT);

    // PostProcess effects are special. One file may contain multiple effects that can be enabled or disabled.
    {
        effects_.clear();
        for (const auto& dir: context_->GetSubsystem<ResourceCache>()->GetResourceDirs())
        {
            ea::vector<ea::string> effects;
            ea::string resourcePath = "PostProcess/";
            ea::string scanDir = AddTrailingSlash(dir) + resourcePath;
            context_->GetSubsystem<FileSystem>()->ScanDir(effects, scanDir, "*.xml", SCAN_FILES, false);

            for (const auto& effectFileName: effects)
            {
                auto effectPath = resourcePath + effectFileName;
                auto* effect = context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(effectPath);

                auto root = effect->GetRoot();
                ea::string tag;
                for (auto command = root.GetChild("command"); command.NotNull(); command = command.GetNext("command"))
                {
                    tag = command.GetAttribute("tag");

                    if (tag.empty())
                    {
                        URHO3D_LOGWARNING("Invalid PostProcess effect with empty tag");
                        continue;
                    }

                    if (effects_.find(tag) != effects_.end())
                        continue;

                    effects_[tag] = resourcePath + effectFileName;
                }
            }
        }

        StringVector tags = effects_.keys();
        ea::quick_sort(tags.begin(), tags.end());

        for (auto& effect : effects_)
        {
            auto getter = [this, &effect](const CameraViewport&, Variant& value) {
                if (RenderPath* renderPath = viewport_->GetRenderPath())
                    value = renderPath->IsEnabled(effect.first);
                else
                    value = false;
            };

            auto setter = [this, &effect](const CameraViewport&, const Variant& value) {
                RenderPath* path = viewport_->GetRenderPath();
                if (!path)
                    return;
                if (!path->IsAdded(effect.first))
                    path->Append(context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(effect.second));
                path->SetEnabled(effect.first, value.GetBool());
            };
            URHO3D_CUSTOM_ACCESSOR_ATTRIBUTE(effect.first.c_str(), getter, setter, bool, false, AM_DEFAULT);
        }
    }

    attributesDirty_ = false;
}

RenderPath* CameraViewport::RebuildRenderPath()
{
    if (!viewport_)
        return nullptr;

    SharedPtr<RenderPath> oldRenderPath(viewport_->GetRenderPath());

    if (XMLFile* renderPathFile = context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(renderPath_.name_))
    {
        viewport_->SetRenderPath(renderPathFile);
        RenderPath* newRenderPath = viewport_->GetRenderPath();

        for (const auto& effect : effects_)
        {
            if (oldRenderPath->IsEnabled(effect.first))
            {
                if (!newRenderPath->IsAdded(effect.first))
                    newRenderPath->Append(context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(effect.second));
                newRenderPath->SetEnabled(effect.first, true);
            }
        }

        return newRenderPath;
    }

    return nullptr;
}

void CameraViewport::SetRenderPath(const ResourceRef& renderPathResource)
{
    if (!viewport_ || !context_->GetSubsystem<Graphics>())
        return;

    if (!renderPathResource.name_.empty() && renderPathResource.type_ != XMLFile::GetTypeStatic())
    {
        URHO3D_LOGWARNINGF("Incorrect RenderPath file '%s' type.", renderPathResource.name_.c_str());
        return;
    }

    SharedPtr<RenderPath> oldRenderPath(viewport_->GetRenderPath());

    const ea::string& renderPathFileName = renderPathResource.name_.empty() ? defaultRenderPath.name_ : renderPathResource.name_;
    if (XMLFile* renderPathFile = context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(renderPathFileName))
    {
        if (!viewport_->SetRenderPath(renderPathFile))
        {
            URHO3D_LOGERRORF("Loading renderpath from %s failed. File probably is not a renderpath.",
                renderPathFileName.c_str());
            return;
        }
        RenderPath* newRenderPath = viewport_->GetRenderPath();

        for (const auto& effect : effects_)
        {
            if (oldRenderPath->IsEnabled(effect.first))
            {
                if (!newRenderPath->IsAdded(effect.first))
                    newRenderPath->Append(context_->GetSubsystem<ResourceCache>()->GetResource<XMLFile>(effect.second));
                newRenderPath->SetEnabled(effect.first, true);
            }
        }

        renderPath_.name_ = renderPathFileName;
    }
    else
    {
        URHO3D_LOGERRORF("Loading renderpath from %s failed. File is missing or you have no permissions to read it.",
                         renderPathFileName.c_str());
    }
}

void CameraViewport::UpdateViewport()
{
    SetNormalizedRect(GetNormalizedRect());
}

}
<|endoftext|>


<commit_before>#include "Vu1Vm.h"
#include "../../Ps2Const.h"
#include "../../VIF.h"
#include "../../Log.h"

#define LOG_NAME "Vu1Vm"

CVu1Vm::CVu1Vm()
: m_vu1(MEMORYMAP_ENDIAN_LSBF)
, m_vu1Executor(m_vu1)
, m_vuMem1(new uint8[PS2::VUMEM1SIZE])
, m_microMem1(new uint8[PS2::MICROMEM1SIZE])
, m_status(PAUSED)
//, m_threadDone(false)
, m_vpu1_TOP(0)
, m_vpu1_ITOP(0)
{
	//Vector Unit 1 context setup
	{
		m_vu1.m_pMemoryMap->InsertReadMap(0x00000000, 0x00003FFF, m_vuMem1,																		0x00);
		m_vu1.m_pMemoryMap->InsertReadMap(0x00008000, 0x00008FFF, [&] (uint32 address, uint32 value) { return Vu1IoPortReadHandler(address); },	0x01);

		m_vu1.m_pMemoryMap->InsertWriteMap(0x00000000, 0x00003FFF, m_vuMem1,																				0x00);
		m_vu1.m_pMemoryMap->InsertWriteMap(0x00008000, 0x00008FFF, [&] (uint32 address, uint32 value) { return Vu1IoPortWriteHandler(address, value); },	0x01);

		m_vu1.m_pMemoryMap->InsertInstructionMap(0x00000000, 0x00003FFF, m_microMem1, 0x01);

		m_vu1.m_pArch			= &m_maVu1;
		m_vu1.m_pAddrTranslator	= CMIPS::TranslateAddress64;
	}

	Reset();
}

CVu1Vm::~CVu1Vm()
{
	delete [] m_vuMem1;
	delete [] m_microMem1;
}

void CVu1Vm::Pause()
{

}

void CVu1Vm::Resume()
{

}

void CVu1Vm::Reset()
{
	m_vu1.Reset();
	memset(m_vuMem1, 0, PS2::VUMEM1SIZE);
	memset(m_microMem1, 0, PS2::MICROMEM1SIZE);
}

CVirtualMachine::STATUS CVu1Vm::GetStatus() const
{
	return m_status;
}

void CVu1Vm::StepVu1()
{
	m_vu1Executor.Execute(1);
	OnMachineStateChange();
}

CMIPS* CVu1Vm::GetVu1Context()
{
	return &m_vu1;
}

uint8* CVu1Vm::GetMicroMem1()
{
	return m_microMem1;
}

uint8* CVu1Vm::GetVuMem1()
{
	return m_vuMem1;
}

void CVu1Vm::SetVpu1Top(uint32 vpu1Top)
{
	m_vpu1_TOP = vpu1Top;
}

void CVu1Vm::SetVpu1Itop(uint32 vpu1Itop)
{
	m_vpu1_ITOP = vpu1Itop;
}

uint32 CVu1Vm::Vu1IoPortReadHandler(uint32 address)
{
	uint32 result = 0xCCCCCCCC;
	switch(address)
	{
	case CVIF::VU_ITOP:
		result = m_vpu1_ITOP;
		break;
	case CVIF::VU_TOP:
		result = m_vpu1_TOP;
		break;
	default:
		CLog::GetInstance().Print(LOG_NAME, "Read an unhandled VU1 IO port (0x%0.8X).\r\n", address);
		break;
	}
	return result;
}

uint32 CVu1Vm::Vu1IoPortWriteHandler(uint32 address, uint32 value)
{
	switch(address)
	{
	case CVIF::VU_XGKICK:
		break;
	default:
		CLog::GetInstance().Print(LOG_NAME, "Wrote an unhandled VU1 IO port (0x%0.8X, 0x%0.8X).\r\n",
			address, value);
		break;
	}
	return 0;
}
<commit_msg>Fixed VU debugging not working in the frame debugger.<commit_after>#include "Vu1Vm.h"
#include "../../Ps2Const.h"
#include "../../VIF.h"
#include "../../Log.h"

#define LOG_NAME "Vu1Vm"

CVu1Vm::CVu1Vm()
: m_vu1(MEMORYMAP_ENDIAN_LSBF)
, m_vu1Executor(m_vu1)
, m_vuMem1(new uint8[PS2::VUMEM1SIZE])
, m_microMem1(new uint8[PS2::MICROMEM1SIZE])
, m_status(PAUSED)
//, m_threadDone(false)
, m_vpu1_TOP(0)
, m_vpu1_ITOP(0)
{
	//Vector Unit 1 context setup
	{
		m_vu1.m_pMemoryMap->InsertReadMap(0x00000000, 0x00003FFF, m_vuMem1,																		0x00);
		m_vu1.m_pMemoryMap->InsertReadMap(0x00008000, 0x00008FFF, [&] (uint32 address, uint32 value) { return Vu1IoPortReadHandler(address); },	0x01);

		m_vu1.m_pMemoryMap->InsertWriteMap(0x00000000, 0x00003FFF, m_vuMem1,																				0x00);
		m_vu1.m_pMemoryMap->InsertWriteMap(0x00008000, 0x00008FFF, [&] (uint32 address, uint32 value) { return Vu1IoPortWriteHandler(address, value); },	0x01);

		m_vu1.m_pMemoryMap->InsertInstructionMap(0x00000000, 0x00003FFF, m_microMem1, 0x01);

		m_vu1.m_pArch			= &m_maVu1;
		m_vu1.m_pAddrTranslator	= CMIPS::TranslateAddress64;

		m_vu1.m_vuMem = m_vuMem1;
	}

	Reset();
}

CVu1Vm::~CVu1Vm()
{
	delete [] m_vuMem1;
	delete [] m_microMem1;
}

void CVu1Vm::Pause()
{

}

void CVu1Vm::Resume()
{

}

void CVu1Vm::Reset()
{
	m_vu1.Reset();
	memset(m_vuMem1, 0, PS2::VUMEM1SIZE);
	memset(m_microMem1, 0, PS2::MICROMEM1SIZE);
}

CVirtualMachine::STATUS CVu1Vm::GetStatus() const
{
	return m_status;
}

void CVu1Vm::StepVu1()
{
	m_vu1Executor.Execute(1);
	OnMachineStateChange();
}

CMIPS* CVu1Vm::GetVu1Context()
{
	return &m_vu1;
}

uint8* CVu1Vm::GetMicroMem1()
{
	return m_microMem1;
}

uint8* CVu1Vm::GetVuMem1()
{
	return m_vuMem1;
}

void CVu1Vm::SetVpu1Top(uint32 vpu1Top)
{
	m_vpu1_TOP = vpu1Top;
}

void CVu1Vm::SetVpu1Itop(uint32 vpu1Itop)
{
	m_vpu1_ITOP = vpu1Itop;
}

uint32 CVu1Vm::Vu1IoPortReadHandler(uint32 address)
{
	uint32 result = 0xCCCCCCCC;
	switch(address)
	{
	case CVIF::VU_ITOP:
		result = m_vpu1_ITOP;
		break;
	case CVIF::VU_TOP:
		result = m_vpu1_TOP;
		break;
	default:
		CLog::GetInstance().Print(LOG_NAME, "Read an unhandled VU1 IO port (0x%0.8X).\r\n", address);
		break;
	}
	return result;
}

uint32 CVu1Vm::Vu1IoPortWriteHandler(uint32 address, uint32 value)
{
	switch(address)
	{
	case CVIF::VU_XGKICK:
		break;
	default:
		CLog::GetInstance().Print(LOG_NAME, "Wrote an unhandled VU1 IO port (0x%0.8X, 0x%0.8X).\r\n",
			address, value);
		break;
	}
	return 0;
}
<|endoftext|>


<commit_before>/*
 *  Author(s):
 *  - Cedric Gestes <gestes@aldebaran-robotics.com>
 *  - Chris  Kilner <ckilner@aldebaran-robotics.com>
 *
 *  Copyright (C) 2010, 2011 Aldebaran Robotics
 */

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <qi/os.hpp>
#include <qi/log.hpp>
#include <qi/log/consoleloghandler.hpp>

#ifdef _WIN32
# include <windows.h>
# include <io.h>
# define isatty _isatty
#else
# include <unistd.h>
#endif

#define CATSIZEMAX 16

namespace qi {
  namespace log {

    class PrivateConsoleLogHandler
    {
    public:
      enum ConsoleAttr {
#ifndef _WIN32
        reset      = 0,
        bright,
        dim,
        blink,
        underline,
        reverse    = 7,
        hidden
#else
        reset      = 0,
        dim        = 0,
        reverse    = 7,
        bright,
        hidden
#endif
      };

      enum ConsoleColor {
#ifdef _WIN32
        black   = 0,
        darkblue,
        green,
        bluegray,
        brown,
        purple,
        whitegray = 7,
        gray,
        whiteblue,
        whitegreen,
        cyan,
        red,
        magenta,
        yellow,
        white
#else
        black   = 0,
        red,
        green,
        yellow,
        blue,
        magenta,
        cyan,
        white,
        gray
#endif
      };

      void textColor(char fg, char bg = -1, char attr = -1) const;
      void textColorBG(char bg) const;
      void textColorAttr(char attr) const;
      void header(const LogLevel verb) const;

      bool _color;

#ifdef _WIN32
      void* _winScreenHandle;
#endif
    };

    void PrivateConsoleLogHandler::textColor(char fg, char bg, char attr) const
    {
      if (!_color)
        return;
#ifdef _WIN32
      if (fg == reset)
      {
        SetConsoleTextAttribute(_winScreenHandle, whitegray);
      }
      else
      {
        SetConsoleTextAttribute(_winScreenHandle, fg);
      }
      return;
#endif
      if (attr != -1 && bg != -1)
        printf("%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40);
      else if (bg != -1)
        printf("%c[%d;%dm", 0x1B, fg + 30, bg + 40);
      else
        printf("%c[%dm", 0x1B, fg + 30);
    }

    void PrivateConsoleLogHandler::textColorBG(char bg) const
    {
      if (!_color)
        return;
#ifdef _WIN32
      return;
#endif
      printf("%c[%dm", 0x1B, bg + 40);
    }

    void PrivateConsoleLogHandler::textColorAttr(char attr) const
    {
      if (!_color)
        return;

#ifdef _WIN32
      if (attr == reset)
      {
        SetConsoleTextAttribute(_winScreenHandle, whitegray);
      }
      else
      {
        SetConsoleTextAttribute(_winScreenHandle, attr);
      }
      return;
#endif
      printf("%c[%dm", 0x1B, attr);
    }

    void PrivateConsoleLogHandler::header(const LogLevel verb) const
    {
      //display log level
      textColorAttr(bright);
      if (verb == fatal)
        textColor(magenta);
      if (verb == error)
        textColor(red);
      if (verb == warning)
        textColor(yellow);
      if (verb == info)
        textColor(white);
      if (verb == verbose)
        textColorAttr(dim);
      if (verb == debug)
        textColorAttr(dim);
      printf("%s ", logLevelToString(verb));
      textColorAttr(reset);
      textColor(reset);
    }

    ConsoleLogHandler::ConsoleLogHandler(const ConsoleLogHandler &rhs)
      : _private(new PrivateConsoleLogHandler)
    {
      *_private = *rhs._private;
    }

    const ConsoleLogHandler & ConsoleLogHandler::operator=(const ConsoleLogHandler &rhs)
    {
      *_private = *rhs._private;
      return *this;
    }

    ConsoleLogHandler::ConsoleLogHandler()
      : _private(new PrivateConsoleLogHandler)
    {
      const char *verbose = std::getenv("VERBOSE");
      const char *context = std::getenv("CONTEXT");
      const char *color   = std::getenv("CLICOLOR");

      if (verbose)
        qi::log::setVerbosity((LogLevel)atoi(verbose));
      if (context)
        qi::log::setContext(atoi(context) > 0 ? true: false);

#ifdef _WIN32
      _private->_winScreenHandle = GetStdHandle(STD_OUTPUT_HANDLE);
#endif
      _private->_color = 1;

      if (color)
        _private->_color = atoi(color) > 0 ? true: false;
      if (!isatty(1))
        _private->_color = 0;
    }

    void cutCat(const char* category, char* res)
    {
      int categorySize = strlen(category);
      if (categorySize < CATSIZEMAX)
      {
        memset(res, ' ', CATSIZEMAX);
        memcpy(res, category, strlen(category));
      }
      else
      {
        memset(res, '.', CATSIZEMAX);
        memcpy(res + 3, category + categorySize - CATSIZEMAX + 3, CATSIZEMAX - 3);
      }
      res[CATSIZEMAX] = '\0';
    }

    void ConsoleLogHandler::log(const LogLevel    verb,
                                const char       *category,
                                const char       *msg,
                                const char       *file,
                                const char       *fct,
                                const int         line)
    {
      if (verb > qi::log::getVerbosity())
      {
        return;
      }
      else
      {
        _private->header(verb);
        char fixedCategory[CATSIZEMAX + 1];
        fixedCategory[CATSIZEMAX] = '\0';
        cutCat(category, fixedCategory);
        if (qi::log::getContext() != 0)
        {
          printf("%s: %s(%d) %s %s", fixedCategory, file, line, fct, msg);
          fflush (stdout);
        }
        else
        {

#ifndef WIN32
          _private->textColorAttr(_private->reset);
          _private->textColor(_private->gray);
#endif
          printf("%s: ", fixedCategory);
          if (qi::log::getContext())
          {
            printf("%s(%d) %s ", file, line, fct);
          }
          printf("%s", msg);
          fflush (stdout);
        }
      }
      fflush (stdout);
    }
  }
}

<commit_msg>libqi: Fix context color on console log.<commit_after>/*
 *  Author(s):
 *  - Cedric Gestes <gestes@aldebaran-robotics.com>
 *  - Chris  Kilner <ckilner@aldebaran-robotics.com>
 *
 *  Copyright (C) 2010, 2011 Aldebaran Robotics
 */

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <qi/os.hpp>
#include <qi/log.hpp>
#include <qi/log/consoleloghandler.hpp>

#ifdef _WIN32
# include <windows.h>
# include <io.h>
# define isatty _isatty
#else
# include <unistd.h>
#endif

#define CATSIZEMAX 16

namespace qi {
  namespace log {

    class PrivateConsoleLogHandler
    {
    public:
      enum ConsoleAttr {
#ifndef _WIN32
        reset      = 0,
        bright,
        dim,
        blink,
        underline,
        reverse    = 7,
        hidden
#else
        reset      = 0,
        dim        = 0,
        reverse    = 7,
        bright,
        hidden
#endif
      };

      enum ConsoleColor {
#ifdef _WIN32
        black   = 0,
        darkblue,
        green,
        bluegray,
        brown,
        purple,
        whitegray = 7,
        gray,
        whiteblue,
        whitegreen,
        cyan,
        red,
        magenta,
        yellow,
        white
#else
        black   = 0,
        red,
        green,
        yellow,
        blue,
        magenta,
        cyan,
        white,
        gray
#endif
      };

      void textColor(char fg, char bg = -1, char attr = -1) const;
      void textColorBG(char bg) const;
      void textColorAttr(char attr) const;
      void header(const LogLevel verb) const;

      bool _color;

#ifdef _WIN32
      void* _winScreenHandle;
#endif
    };

    void PrivateConsoleLogHandler::textColor(char fg, char bg, char attr) const
    {
      if (!_color)
        return;
#ifdef _WIN32
      if (fg == reset)
      {
        SetConsoleTextAttribute(_winScreenHandle, whitegray);
      }
      else
      {
        SetConsoleTextAttribute(_winScreenHandle, fg);
      }
      return;
#endif
      if (attr != -1 && bg != -1)
        printf("%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40);
      else if (bg != -1)
        printf("%c[%d;%dm", 0x1B, fg + 30, bg + 40);
      else
        printf("%c[%dm", 0x1B, fg + 30);
    }

    void PrivateConsoleLogHandler::textColorBG(char bg) const
    {
      if (!_color)
        return;
#ifdef _WIN32
      return;
#endif
      printf("%c[%dm", 0x1B, bg + 40);
    }

    void PrivateConsoleLogHandler::textColorAttr(char attr) const
    {
      if (!_color)
        return;

#ifdef _WIN32
      if (attr == reset)
      {
        SetConsoleTextAttribute(_winScreenHandle, whitegray);
      }
      else
      {
        SetConsoleTextAttribute(_winScreenHandle, attr);
      }
      return;
#endif
      printf("%c[%dm", 0x1B, attr);
    }

    void PrivateConsoleLogHandler::header(const LogLevel verb) const
    {
      //display log level
      textColorAttr(bright);
      if (verb == fatal)
        textColor(magenta);
      if (verb == error)
        textColor(red);
      if (verb == warning)
        textColor(yellow);
      if (verb == info)
        textColor(white);
      if (verb == verbose)
        textColorAttr(dim);
      if (verb == debug)
        textColorAttr(dim);
      printf("%s ", logLevelToString(verb));
      textColorAttr(reset);
      textColor(reset);
    }

    ConsoleLogHandler::ConsoleLogHandler(const ConsoleLogHandler &rhs)
      : _private(new PrivateConsoleLogHandler)
    {
      *_private = *rhs._private;
    }

    const ConsoleLogHandler & ConsoleLogHandler::operator=(const ConsoleLogHandler &rhs)
    {
      *_private = *rhs._private;
      return *this;
    }

    ConsoleLogHandler::ConsoleLogHandler()
      : _private(new PrivateConsoleLogHandler)
    {
      const char *verbose = std::getenv("VERBOSE");
      const char *context = std::getenv("CONTEXT");
      const char *color   = std::getenv("CLICOLOR");

      if (verbose)
        qi::log::setVerbosity((LogLevel)atoi(verbose));
      if (context)
        qi::log::setContext(atoi(context) > 0 ? true: false);

#ifdef _WIN32
      _private->_winScreenHandle = GetStdHandle(STD_OUTPUT_HANDLE);
#endif
      _private->_color = 1;

      if (color)
        _private->_color = atoi(color) > 0 ? true: false;
      if (!isatty(1))
        _private->_color = 0;
    }

    void cutCat(const char* category, char* res)
    {
      int categorySize = strlen(category);
      if (categorySize < CATSIZEMAX)
      {
        memset(res, ' ', CATSIZEMAX);
        memcpy(res, category, strlen(category));
      }
      else
      {
        memset(res, '.', CATSIZEMAX);
        memcpy(res + 3, category + categorySize - CATSIZEMAX + 3, CATSIZEMAX - 3);
      }
      res[CATSIZEMAX] = '\0';
    }

    void ConsoleLogHandler::log(const LogLevel    verb,
                                const char       *category,
                                const char       *msg,
                                const char       *file,
                                const char       *fct,
                                const int         line)
    {
      if (verb > qi::log::getVerbosity())
      {
        return;
      }
      else
      {
        _private->header(verb);
        char fixedCategory[CATSIZEMAX + 1];
        fixedCategory[CATSIZEMAX] = '\0';
        cutCat(category, fixedCategory);
#ifndef WIN32
        _private->textColorAttr(_private->reset);
        _private->textColor(_private->gray);
#endif
        printf("%s: ", fixedCategory);
        if (qi::log::getContext())
        {
          printf("%s(%d) %s ", file, line, fct);
        }
        printf("%s", msg);
        fflush (stdout);
      }
      fflush (stdout);
    }
  }
}

<|endoftext|>


<commit_before>/*
 * D-Bus AT-SPI, Qt Adaptor
 *
 * Copyright 2008, 2009      Nokia.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <QtCore/QHash>
#include <QAccessible>

#include "constant_mappings.h"

#define BITARRAY_SEQ_TERM 0xffffffff

#define BITARRAY_SET(p, n) ((p)[n>>5] |= (1<<(n&31)))

/*---------------------------------------------------------------------------*/

QHash <QAccessible::Role, QSpiRole> qSpiRoleMapping;

static void initialize_role_mapping ()
{
       qSpiRoleMapping.insert (QAccessible::NoRole, ROLE_INVALID);
       qSpiRoleMapping.insert (QAccessible::TitleBar, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::MenuBar, ROLE_MENU_BAR);
       qSpiRoleMapping.insert (QAccessible::ScrollBar, ROLE_SCROLL_BAR);
       qSpiRoleMapping.insert (QAccessible::Grip, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Sound, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Cursor, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Caret, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::AlertMessage, ROLE_ALERT);
       qSpiRoleMapping.insert (QAccessible::Window, ROLE_WINDOW);
       qSpiRoleMapping.insert (QAccessible::Client, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::PopupMenu, ROLE_POPUP_MENU);
       qSpiRoleMapping.insert (QAccessible::MenuItem, ROLE_MENU_ITEM);
       qSpiRoleMapping.insert (QAccessible::ToolTip, ROLE_TOOL_TIP);
       qSpiRoleMapping.insert (QAccessible::Application, ROLE_APPLICATION);
       qSpiRoleMapping.insert (QAccessible::Document, ROLE_DOCUMENT_FRAME);
       qSpiRoleMapping.insert (QAccessible::Pane, ROLE_PANEL);
       qSpiRoleMapping.insert (QAccessible::Chart, ROLE_CHART);
       qSpiRoleMapping.insert (QAccessible::Dialog, ROLE_DIALOG);
       qSpiRoleMapping.insert (QAccessible::Border, ROLE_FRAME);
       qSpiRoleMapping.insert (QAccessible::Grouping, ROLE_PANEL);
       qSpiRoleMapping.insert (QAccessible::Separator, ROLE_SEPARATOR);
       qSpiRoleMapping.insert (QAccessible::ToolBar, ROLE_TOOL_BAR);
       qSpiRoleMapping.insert (QAccessible::StatusBar, ROLE_STATUS_BAR);
       qSpiRoleMapping.insert (QAccessible::Table, ROLE_TABLE);
       qSpiRoleMapping.insert (QAccessible::ColumnHeader, ROLE_TABLE_COLUMN_HEADER);
       qSpiRoleMapping.insert (QAccessible::RowHeader, ROLE_TABLE_ROW_HEADER);
       qSpiRoleMapping.insert (QAccessible::Column, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Row, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Cell, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Link, ROLE_LINK);
       qSpiRoleMapping.insert (QAccessible::HelpBalloon, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Assistant, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::List, ROLE_LIST);
       qSpiRoleMapping.insert (QAccessible::ListItem, ROLE_LIST_ITEM);
       qSpiRoleMapping.insert (QAccessible::Tree, ROLE_TREE);
       qSpiRoleMapping.insert (QAccessible::TreeItem, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::PageTab, ROLE_PAGE_TAB);
       qSpiRoleMapping.insert (QAccessible::PropertyPage, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Indicator, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Graphic, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::StaticText, ROLE_TEXT);
       qSpiRoleMapping.insert (QAccessible::EditableText, ROLE_TEXT);
       qSpiRoleMapping.insert (QAccessible::PushButton, ROLE_PUSH_BUTTON);
       qSpiRoleMapping.insert (QAccessible::CheckBox, ROLE_CHECK_BOX);
       qSpiRoleMapping.insert (QAccessible::RadioButton, ROLE_RADIO_BUTTON);
       qSpiRoleMapping.insert (QAccessible::ComboBox, ROLE_COMBO_BOX);
       qSpiRoleMapping.insert (QAccessible::ProgressBar, ROLE_PROGRESS_BAR);
       qSpiRoleMapping.insert (QAccessible::Dial, ROLE_DIAL);
       qSpiRoleMapping.insert (QAccessible::HotkeyField, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Slider, ROLE_SLIDER);
       qSpiRoleMapping.insert (QAccessible::SpinBox, ROLE_SPIN_BUTTON);
       qSpiRoleMapping.insert (QAccessible::Canvas, ROLE_CANVAS);
       qSpiRoleMapping.insert (QAccessible::Animation, ROLE_ANIMATION);
       qSpiRoleMapping.insert (QAccessible::Equation, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::ButtonDropDown, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::ButtonMenu, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::ButtonDropGrid, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Whitespace, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::PageTabList, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Clock, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Splitter, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::LayeredPane, ROLE_FRAME);
       qSpiRoleMapping.insert (QAccessible::UserRole, ROLE_UNKNOWN);
}

/*---------------------------------------------------------------------------*/

QHash <int, QSpiState> qSpiStateMapping;

static void initialize_state_mapping ()
{
       qSpiStateMapping.insert (int(QAccessible::Normal), STATE_ENABLED); /*STATE_ENABLED/SHOWING/VISIBLE*/
       qSpiStateMapping.insert (int(QAccessible::Unavailable), STATE_UNKNOWN); /*STATE_INVALID?*/
       qSpiStateMapping.insert (int(QAccessible::Selected), STATE_SELECTED);
       qSpiStateMapping.insert (int(QAccessible::Focused), STATE_FOCUSED);
       qSpiStateMapping.insert (int(QAccessible::Pressed), STATE_PRESSED);
       qSpiStateMapping.insert (int(QAccessible::Checked), STATE_CHECKED);
       qSpiStateMapping.insert (int(QAccessible::Mixed), STATE_UNKNOWN);
       qSpiStateMapping.insert (int(QAccessible::ReadOnly), STATE_UNKNOWN); /*STATE_EDITABLE if not present?*/
       qSpiStateMapping.insert (int(QAccessible::HotTracked), STATE_UNKNOWN);
       qSpiStateMapping.insert (int(QAccessible::DefaultButton), STATE_UNKNOWN);
       qSpiStateMapping.insert (int(QAccessible::Expanded), STATE_EXPANDED);
       qSpiStateMapping.insert (int(QAccessible::Collapsed), STATE_COLLAPSED);
       qSpiStateMapping.insert (int(QAccessible::Busy), STATE_BUSY);
       qSpiStateMapping.insert (int(QAccessible::Marqueed), STATE_UNKNOWN);
       qSpiStateMapping.insert (int(QAccessible::Animated), STATE_ANIMATED);
       qSpiStateMapping.insert (int(QAccessible::Invisible), STATE_UNKNOWN); /*!STATE_VISIBLE if present?*/
       qSpiStateMapping.insert (int(QAccessible::Offscreen), STATE_UNKNOWN); /*!STATE_VISIBLE if present?*/
       qSpiStateMapping.insert (int(QAccessible::Sizeable), STATE_UNKNOWN);
       qSpiStateMapping.insert (int(QAccessible::Movable), STATE_UNKNOWN);
       qSpiStateMapping.insert (int(QAccessible::SelfVoicing), STATE_UNKNOWN);
       qSpiStateMapping.insert (int(QAccessible::Focusable), STATE_FOCUSABLE);
       qSpiStateMapping.insert (int(QAccessible::Selectable), STATE_SELECTABLE);
       qSpiStateMapping.insert (int(QAccessible::Linked), STATE_UNKNOWN);
       qSpiStateMapping.insert (int(QAccessible::Traversed), STATE_VISITED);
       qSpiStateMapping.insert (int(QAccessible::MultiSelectable), STATE_MULTISELECTABLE);
       qSpiStateMapping.insert (int(QAccessible::ExtSelectable), STATE_UNKNOWN);
       qSpiStateMapping.insert (int(QAccessible::Protected), STATE_UNKNOWN);
       qSpiStateMapping.insert (int(QAccessible::HasPopup), STATE_UNKNOWN);
       qSpiStateMapping.insert (int(QAccessible::Modal), STATE_MODAL);
       qSpiStateMapping.insert (int(QAccessible::HasInvokeExtension), STATE_UNKNOWN);
}

void qspi_stateset_from_qstate (QAccessible::State state, QSpiIntList &set)
{
       int array[2] = {0, 0};

       for (int mask = 1; mask <= QAccessible::HasInvokeExtension; mask <<= 1)
       {
           if (state & mask)
           {
               int a = qSpiStateMapping.value(state & mask);
               BITARRAY_SET (array, a);
           }
       }
       set << array[0];
       set << array[1];
}

/*---------------------------------------------------------------------------*/

void qspi_initialize_constant_mappings ()
{
       initialize_role_mapping ();
       initialize_state_mapping ();
}

/*END------------------------------------------------------------------------*/
<commit_msg>Improve the state mappings.<commit_after>/*
 * D-Bus AT-SPI, Qt Adaptor
 *
 * Copyright 2008, 2009      Nokia.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <QtCore/QHash>
#include <QAccessible>

#include "constant_mappings.h"

#define BITARRAY_SEQ_TERM 0xffffffff

#define BITARRAY_SET(p, n)   ( (p)[n>>5] |=  (1<<(n&31)) )
#define BITARRAY_UNSET(p, n) ( (p)[n>>5] &= ~(1<<(n&31)) )

/*---------------------------------------------------------------------------*/

QHash <QAccessible::Role, QSpiRole> qSpiRoleMapping;

static void initialize_role_mapping ()
{
       qSpiRoleMapping.insert (QAccessible::NoRole, ROLE_INVALID);
       qSpiRoleMapping.insert (QAccessible::TitleBar, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::MenuBar, ROLE_MENU_BAR);
       qSpiRoleMapping.insert (QAccessible::ScrollBar, ROLE_SCROLL_BAR);
       qSpiRoleMapping.insert (QAccessible::Grip, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Sound, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Cursor, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Caret, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::AlertMessage, ROLE_ALERT);
       qSpiRoleMapping.insert (QAccessible::Window, ROLE_WINDOW);
       qSpiRoleMapping.insert (QAccessible::Client, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::PopupMenu, ROLE_POPUP_MENU);
       qSpiRoleMapping.insert (QAccessible::MenuItem, ROLE_MENU_ITEM);
       qSpiRoleMapping.insert (QAccessible::ToolTip, ROLE_TOOL_TIP);
       qSpiRoleMapping.insert (QAccessible::Application, ROLE_APPLICATION);
       qSpiRoleMapping.insert (QAccessible::Document, ROLE_DOCUMENT_FRAME);
       qSpiRoleMapping.insert (QAccessible::Pane, ROLE_PANEL);
       qSpiRoleMapping.insert (QAccessible::Chart, ROLE_CHART);
       qSpiRoleMapping.insert (QAccessible::Dialog, ROLE_DIALOG);
       qSpiRoleMapping.insert (QAccessible::Border, ROLE_FRAME);
       qSpiRoleMapping.insert (QAccessible::Grouping, ROLE_PANEL);
       qSpiRoleMapping.insert (QAccessible::Separator, ROLE_SEPARATOR);
       qSpiRoleMapping.insert (QAccessible::ToolBar, ROLE_TOOL_BAR);
       qSpiRoleMapping.insert (QAccessible::StatusBar, ROLE_STATUS_BAR);
       qSpiRoleMapping.insert (QAccessible::Table, ROLE_TABLE);
       qSpiRoleMapping.insert (QAccessible::ColumnHeader, ROLE_TABLE_COLUMN_HEADER);
       qSpiRoleMapping.insert (QAccessible::RowHeader, ROLE_TABLE_ROW_HEADER);
       qSpiRoleMapping.insert (QAccessible::Column, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Row, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Cell, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Link, ROLE_LINK);
       qSpiRoleMapping.insert (QAccessible::HelpBalloon, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Assistant, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::List, ROLE_LIST);
       qSpiRoleMapping.insert (QAccessible::ListItem, ROLE_LIST_ITEM);
       qSpiRoleMapping.insert (QAccessible::Tree, ROLE_TREE);
       qSpiRoleMapping.insert (QAccessible::TreeItem, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::PageTab, ROLE_PAGE_TAB);
       qSpiRoleMapping.insert (QAccessible::PropertyPage, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Indicator, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Graphic, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::StaticText, ROLE_TEXT);
       qSpiRoleMapping.insert (QAccessible::EditableText, ROLE_TEXT);
       qSpiRoleMapping.insert (QAccessible::PushButton, ROLE_PUSH_BUTTON);
       qSpiRoleMapping.insert (QAccessible::CheckBox, ROLE_CHECK_BOX);
       qSpiRoleMapping.insert (QAccessible::RadioButton, ROLE_RADIO_BUTTON);
       qSpiRoleMapping.insert (QAccessible::ComboBox, ROLE_COMBO_BOX);
       qSpiRoleMapping.insert (QAccessible::ProgressBar, ROLE_PROGRESS_BAR);
       qSpiRoleMapping.insert (QAccessible::Dial, ROLE_DIAL);
       qSpiRoleMapping.insert (QAccessible::HotkeyField, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Slider, ROLE_SLIDER);
       qSpiRoleMapping.insert (QAccessible::SpinBox, ROLE_SPIN_BUTTON);
       qSpiRoleMapping.insert (QAccessible::Canvas, ROLE_CANVAS);
       qSpiRoleMapping.insert (QAccessible::Animation, ROLE_ANIMATION);
       qSpiRoleMapping.insert (QAccessible::Equation, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::ButtonDropDown, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::ButtonMenu, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::ButtonDropGrid, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Whitespace, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::PageTabList, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Clock, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::Splitter, ROLE_UNKNOWN);
       qSpiRoleMapping.insert (QAccessible::LayeredPane, ROLE_FRAME);
       qSpiRoleMapping.insert (QAccessible::UserRole, ROLE_UNKNOWN);
}

/*---------------------------------------------------------------------------*/

void qspi_stateset_from_qstate (QAccessible::State state, QSpiIntList &set)
{
       int array[2] = {0, 0};

       for (int mask = 1; mask <= int(QAccessible::HasInvokeExtension); mask <<= 1)
       {
           /* We may need to take the role of the object into account when
            * mapping between the state sets
            */
           BITARRAY_SET (array, STATE_EDITABLE);

           switch (state & mask)
           {
                 case QAccessible::Normal:
                 {
                         BITARRAY_SET (array, STATE_ENABLED);
                         BITARRAY_SET (array, STATE_SHOWING);
                         BITARRAY_SET (array, STATE_VISIBLE);
                         BITARRAY_SET (array, STATE_SENSITIVE);
                         break;
                 }
                 case QAccessible::Unavailable:
                 {
                         BITARRAY_UNSET (array, STATE_ENABLED);
                         BITARRAY_UNSET (array, STATE_SHOWING);
                         BITARRAY_UNSET (array, STATE_VISIBLE);
                         BITARRAY_UNSET (array, STATE_SENSITIVE);
                         break;
                 }
                 case QAccessible::Selected:
                 {
                         BITARRAY_SET (array, STATE_SELECTED);
                         break;
                 }
                 case QAccessible::Focused:
                 {
                         BITARRAY_SET (array, STATE_FOCUSED);
                         break;
                 }
                 case QAccessible::Pressed:
                 {
                         BITARRAY_SET (array, STATE_PRESSED);
                         break;
                 }
                 case QAccessible::Checked:
                 {
                         BITARRAY_SET (array, STATE_CHECKED);
                         break;
                 }
                 case QAccessible::Mixed:
                 {
                         BITARRAY_SET (array, STATE_INDETERMINATE);
                         break;
                 }
                 case QAccessible::ReadOnly:
                 {
                         BITARRAY_UNSET (array, STATE_EDITABLE);
                         break;
                 }
                 case QAccessible::HotTracked:
                 {
                         break;
                 }
                 case QAccessible::DefaultButton:
                 {
                         BITARRAY_SET (array, STATE_IS_DEFAULT);
                         break;
                 }
                 case QAccessible::Expanded:
                 {
                         BITARRAY_SET (array, STATE_EXPANDED);
                         break;
                 }
                 case QAccessible::Collapsed:
                 {
                         BITARRAY_SET (array, STATE_COLLAPSED);
                         break;
                 }
                 case QAccessible::Busy:
                 {
                         BITARRAY_SET (array, STATE_BUSY);
                         break;
                 }
                 case QAccessible::Marqueed:
                 case QAccessible::Animated:
                 {
                         BITARRAY_SET (array, STATE_ANIMATED);
                         break;
                 }
                 case QAccessible::Invisible:
                 case QAccessible::Offscreen:
                 {
                         BITARRAY_UNSET (array, STATE_VISIBLE);
                         break;
                 }
                 case QAccessible::Sizeable:
                 {
                         BITARRAY_SET (array, STATE_RESIZABLE);
                         break;
                 }
                 case QAccessible::Movable:
                 case QAccessible::SelfVoicing:
                 {
                         break;
                 }
                 case QAccessible::Focusable:
                 {
                         BITARRAY_SET (array, STATE_FOCUSABLE);
                         break;
                 }
                 case QAccessible::Selectable:
                 {
                         BITARRAY_SET (array, STATE_SELECTABLE);
                         break;
                 }
                 case QAccessible::Linked:
                 {
                         break;
                 }
                 case QAccessible::Traversed:
                 {
                         BITARRAY_SET (array, STATE_VISITED);
                         break;
                 }
                 case QAccessible::MultiSelectable:
                 {
                         BITARRAY_SET (array, STATE_MULTISELECTABLE);
                         break;
                 }
                 case QAccessible::ExtSelectable:
                 {
                         BITARRAY_SET (array, STATE_SELECTABLE);
                         break;
                 }
                 case QAccessible::Protected:
                 case QAccessible::HasPopup:
                 {
                         break;
                 }
                 case QAccessible::Modal:
                 {
                         BITARRAY_SET (array, STATE_MODAL);
                         break;
                 }
                 case QAccessible::HasInvokeExtension:
                 {
                         break;
                 }
                 default:
                 {
                         break;
                 }
           }
       }
       set << array[0];
       set << array[1];
}

/*---------------------------------------------------------------------------*/

void qspi_initialize_constant_mappings ()
{
       initialize_role_mapping ();
}

/*END------------------------------------------------------------------------*/
<|endoftext|>