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

#include "background.h"
#include "film.h"
#include "../render/filter.h"
#include "graph.h"
#include "integrator.h"
#include "light.h"
#include "mesh.h"
#include "nodes.h"
#include "object.h"
#include "scene.h"
#include "shader.h"

#include "device.h"

#include "blender_sync.h"
#include "blender_util.h"

#include "util_debug.h"
#include "util_foreach.h"

CCL_NAMESPACE_BEGIN

/* Constructor */

BlenderSync::BlenderSync(BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_)
: b_data(b_data_), b_scene(b_scene_),
  shader_map(&scene_->shaders),
  object_map(&scene_->objects),
  mesh_map(&scene_->meshes),
  light_map(&scene_->lights),
  world_map(NULL),
  world_recalc(false)
{
	scene = scene_;
	preview = preview_;
}

BlenderSync::~BlenderSync()
{
}

/* Sync */

bool BlenderSync::sync_recalc()
{
	/* sync recalc flags from blender to cycles. actual update is done separate,
	   so we can do it later on if doing it immediate is not suitable */

	BL::BlendData::materials_iterator b_mat;

	for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat)
		if(b_mat->recalc())
			shader_map.set_recalc(*b_mat);

	BL::BlendData::lamps_iterator b_lamp;

	for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp)
		if(b_lamp->recalc())
			shader_map.set_recalc(*b_lamp);

	BL::BlendData::objects_iterator b_ob;

	for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
		if(b_ob->recalc()) {
			object_map.set_recalc(*b_ob);
			light_map.set_recalc(*b_ob);
		}

		if(object_is_mesh(*b_ob)) {
			if(b_ob->recalc_data() || b_ob->data().recalc()) {
				BL::ID key = object_is_modified(*b_ob)? *b_ob: b_ob->data();
				mesh_map.set_recalc(key);
			}
		}
		else if(object_is_light(*b_ob)) {
			if(b_ob->recalc_data() || b_ob->data().recalc())
				light_map.set_recalc(*b_ob);
		}
	}

	BL::BlendData::meshes_iterator b_mesh;

	for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh)
		if(b_mesh->recalc())
			mesh_map.set_recalc(*b_mesh);

	BL::BlendData::worlds_iterator b_world;

	for(b_data.worlds.begin(b_world); b_world != b_data.worlds.end(); ++b_world)
		if(world_map == b_world->ptr.data && b_world->recalc())
			world_recalc = true;

	bool recalc =
		shader_map.has_recalc() ||
		object_map.has_recalc() ||
		light_map.has_recalc() ||
		mesh_map.has_recalc() ||
		BlendDataObjects_recalc_get(&b_data.ptr) ||
		world_recalc;

	return recalc;
}

void BlenderSync::sync_data(BL::SpaceView3D b_v3d)
{
	sync_integrator();
	sync_film();
	sync_render_layer(b_v3d);
	sync_shaders();
	sync_objects(b_v3d);
}

/* Integrator */

void BlenderSync::sync_integrator()
{
	PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");

	Integrator *integrator = scene->integrator;
	Integrator previntegrator = *integrator;

	integrator->min_bounce = get_int(cscene, "min_bounces");
	integrator->max_bounce = get_int(cscene, "max_bounces");

	integrator->max_diffuse_bounce = get_int(cscene, "diffuse_bounces");
	integrator->max_glossy_bounce = get_int(cscene, "glossy_bounces");
	integrator->max_transmission_bounce = get_int(cscene, "transmission_bounces");

	integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces");
	integrator->transparent_min_bounce = get_int(cscene, "transparent_min_bounces");
	integrator->transparent_shadows = get_boolean(cscene, "use_transparent_shadows");

	integrator->no_caustics = get_boolean(cscene, "no_caustics");
	integrator->blur_caustics = get_float(cscene, "blur_caustics");

	integrator->seed = get_int(cscene, "seed");

	if(integrator->modified(previntegrator))
		integrator->tag_update(scene);
}

/* Film */

void BlenderSync::sync_film()
{
	PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");

	Film *film = scene->film;
	Film prevfilm = *film;

	film->exposure = get_float(cscene, "film_exposure");

	if(film->modified(prevfilm))
		film->tag_update(scene);

	Filter *filter = scene->filter;
	Filter prevfilter = *filter;

	filter->filter_type = (FilterType)RNA_enum_get(&cscene, "filter_type");
	filter->filter_width = (filter->filter_type == FILTER_BOX)? 1.0f: get_float(cscene, "filter_width");

	if(filter->modified(prevfilter))
		filter->tag_update(scene);
}

/* Render Layer */

void BlenderSync::sync_render_layer(BL::SpaceView3D b_v3d)
{
	if(b_v3d) {
		render_layer.scene_layer = get_layer(b_v3d.layers());
		render_layer.layer = render_layer.scene_layer;
		render_layer.material_override = PointerRNA_NULL;
	}
	else {
		BL::RenderSettings r = b_scene.render();
		BL::RenderSettings::layers_iterator b_rlay;
		bool first = true;

		for(r.layers.begin(b_rlay); b_rlay != r.layers.end(); ++b_rlay) {
			/* single layer for now */
			if(first) {
				render_layer.scene_layer = get_layer(b_scene.layers());
				render_layer.layer = get_layer(b_rlay->layers());
				render_layer.material_override = b_rlay->material_override();

				first = false;
			}
		}
	}
}

/* Scene Parameters */

SceneParams BlenderSync::get_scene_params(BL::Scene b_scene)
{
	SceneParams params;
	PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
	int shadingsystem = RNA_enum_get(&cscene, "shading_system");

	if(shadingsystem == 0)
		params.shadingsystem = SceneParams::SVM;
	else if(shadingsystem == 1)
		params.shadingsystem = SceneParams::OSL;

	params.bvh_type = (SceneParams::BVHType)RNA_enum_get(&cscene, "debug_bvh_type");
	params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");

	return params;
}

/* Session Parameters */

bool BlenderSync::get_session_pause(BL::Scene b_scene, bool background)
{
	PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
	return (background)? false: get_boolean(cscene, "preview_pause");
}

static bool device_type_available(vector<DeviceType>& types, DeviceType dtype)
{
	foreach(DeviceType dt, types)
		if(dt == dtype)
			return true;

	return false;
}

SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background)
{
	SessionParams params;
	PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");

	/* device type */
	params.device_type = DEVICE_CPU;

	if(RNA_enum_get(&cscene, "device") != 0) {
		vector<DeviceType> types = Device::available_types();
		DeviceType dtype = (RNA_enum_get(&cscene, "gpu_type") == 0)? DEVICE_CUDA: DEVICE_OPENCL;

		if(device_type_available(types, dtype))
			params.device_type = dtype;
		else if(device_type_available(types, DEVICE_OPENCL))
			params.device_type = DEVICE_OPENCL;
		else if(device_type_available(types, DEVICE_CUDA))
			params.device_type = DEVICE_CUDA;
	}

	/* Background */
	params.background = background;

	/* samples */
	if(background) {
		params.samples = get_int(cscene, "samples");
	}
	else {
		params.samples = get_int(cscene, "preview_samples");
		if(params.samples == 0)
			params.samples = INT_MAX;
	}

	/* other parameters */
	params.threads = b_scene.render().threads();
	params.tile_size = get_int(cscene, "debug_tile_size");
	params.min_size = get_int(cscene, "debug_min_size");
	params.cancel_timeout = get_float(cscene, "debug_cancel_timeout");
	params.reset_timeout = get_float(cscene, "debug_reset_timeout");
	params.text_timeout = get_float(cscene, "debug_text_timeout");

	if(background) {
		params.progressive = true;
		params.min_size = INT_MAX;
	}
	else
		params.progressive = true;

	return params;
}

CCL_NAMESPACE_END

<commit_msg>Cycles: updates to follow code committed to trunk.<commit_after>/*
 * Copyright 2011, Blender Foundation.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "background.h"
#include "film.h"
#include "../render/filter.h"
#include "graph.h"
#include "integrator.h"
#include "light.h"
#include "mesh.h"
#include "nodes.h"
#include "object.h"
#include "scene.h"
#include "shader.h"

#include "device.h"

#include "blender_sync.h"
#include "blender_util.h"

#include "util_debug.h"
#include "util_foreach.h"

CCL_NAMESPACE_BEGIN

/* Constructor */

BlenderSync::BlenderSync(BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_)
: b_data(b_data_), b_scene(b_scene_),
  shader_map(&scene_->shaders),
  object_map(&scene_->objects),
  mesh_map(&scene_->meshes),
  light_map(&scene_->lights),
  world_map(NULL),
  world_recalc(false)
{
	scene = scene_;
	preview = preview_;
}

BlenderSync::~BlenderSync()
{
}

/* Sync */

bool BlenderSync::sync_recalc()
{
	/* sync recalc flags from blender to cycles. actual update is done separate,
	   so we can do it later on if doing it immediate is not suitable */

	BL::BlendData::materials_iterator b_mat;

	for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat)
		if(b_mat->is_updated())
			shader_map.set_recalc(*b_mat);

	BL::BlendData::lamps_iterator b_lamp;

	for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp)
		if(b_lamp->is_updated())
			shader_map.set_recalc(*b_lamp);

	BL::BlendData::objects_iterator b_ob;

	for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
		if(b_ob->is_updated()) {
			object_map.set_recalc(*b_ob);
			light_map.set_recalc(*b_ob);
		}

		if(object_is_mesh(*b_ob)) {
			if(b_ob->is_updated_data() || b_ob->data().is_updated()) {
				BL::ID key = object_is_modified(*b_ob)? *b_ob: b_ob->data();
				mesh_map.set_recalc(key);
			}
		}
		else if(object_is_light(*b_ob)) {
			if(b_ob->is_updated_data() || b_ob->data().is_updated())
				light_map.set_recalc(*b_ob);
		}
	}

	BL::BlendData::meshes_iterator b_mesh;

	for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh)
		if(b_mesh->is_updated())
			mesh_map.set_recalc(*b_mesh);

	BL::BlendData::worlds_iterator b_world;

	for(b_data.worlds.begin(b_world); b_world != b_data.worlds.end(); ++b_world)
		if(world_map == b_world->ptr.data && b_world->is_updated())
			world_recalc = true;

	bool recalc =
		shader_map.has_recalc() ||
		object_map.has_recalc() ||
		light_map.has_recalc() ||
		mesh_map.has_recalc() ||
		BlendDataObjects_is_updated_get(&b_data.ptr) ||
		world_recalc;

	return recalc;
}

void BlenderSync::sync_data(BL::SpaceView3D b_v3d)
{
	sync_integrator();
	sync_film();
	sync_render_layer(b_v3d);
	sync_shaders();
	sync_objects(b_v3d);
}

/* Integrator */

void BlenderSync::sync_integrator()
{
	PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");

	Integrator *integrator = scene->integrator;
	Integrator previntegrator = *integrator;

	integrator->min_bounce = get_int(cscene, "min_bounces");
	integrator->max_bounce = get_int(cscene, "max_bounces");

	integrator->max_diffuse_bounce = get_int(cscene, "diffuse_bounces");
	integrator->max_glossy_bounce = get_int(cscene, "glossy_bounces");
	integrator->max_transmission_bounce = get_int(cscene, "transmission_bounces");

	integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces");
	integrator->transparent_min_bounce = get_int(cscene, "transparent_min_bounces");
	integrator->transparent_shadows = get_boolean(cscene, "use_transparent_shadows");

	integrator->no_caustics = get_boolean(cscene, "no_caustics");
	integrator->blur_caustics = get_float(cscene, "blur_caustics");

	integrator->seed = get_int(cscene, "seed");

	if(integrator->modified(previntegrator))
		integrator->tag_update(scene);
}

/* Film */

void BlenderSync::sync_film()
{
	PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");

	Film *film = scene->film;
	Film prevfilm = *film;

	film->exposure = get_float(cscene, "film_exposure");

	if(film->modified(prevfilm))
		film->tag_update(scene);

	Filter *filter = scene->filter;
	Filter prevfilter = *filter;

	filter->filter_type = (FilterType)RNA_enum_get(&cscene, "filter_type");
	filter->filter_width = (filter->filter_type == FILTER_BOX)? 1.0f: get_float(cscene, "filter_width");

	if(filter->modified(prevfilter))
		filter->tag_update(scene);
}

/* Render Layer */

void BlenderSync::sync_render_layer(BL::SpaceView3D b_v3d)
{
	if(b_v3d) {
		render_layer.scene_layer = get_layer(b_v3d.layers());
		render_layer.layer = render_layer.scene_layer;
		render_layer.material_override = PointerRNA_NULL;
	}
	else {
		BL::RenderSettings r = b_scene.render();
		BL::RenderSettings::layers_iterator b_rlay;
		bool first = true;

		for(r.layers.begin(b_rlay); b_rlay != r.layers.end(); ++b_rlay) {
			/* single layer for now */
			if(first) {
				render_layer.scene_layer = get_layer(b_scene.layers());
				render_layer.layer = get_layer(b_rlay->layers());
				render_layer.material_override = b_rlay->material_override();

				first = false;
			}
		}
	}
}

/* Scene Parameters */

SceneParams BlenderSync::get_scene_params(BL::Scene b_scene)
{
	SceneParams params;
	PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
	int shadingsystem = RNA_enum_get(&cscene, "shading_system");

	if(shadingsystem == 0)
		params.shadingsystem = SceneParams::SVM;
	else if(shadingsystem == 1)
		params.shadingsystem = SceneParams::OSL;

	params.bvh_type = (SceneParams::BVHType)RNA_enum_get(&cscene, "debug_bvh_type");
	params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");

	return params;
}

/* Session Parameters */

bool BlenderSync::get_session_pause(BL::Scene b_scene, bool background)
{
	PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
	return (background)? false: get_boolean(cscene, "preview_pause");
}

static bool device_type_available(vector<DeviceType>& types, DeviceType dtype)
{
	foreach(DeviceType dt, types)
		if(dt == dtype)
			return true;

	return false;
}

SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background)
{
	SessionParams params;
	PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");

	/* device type */
	params.device_type = DEVICE_CPU;

	if(RNA_enum_get(&cscene, "device") != 0) {
		vector<DeviceType> types = Device::available_types();
		DeviceType dtype = (RNA_enum_get(&cscene, "gpu_type") == 0)? DEVICE_CUDA: DEVICE_OPENCL;

		if(device_type_available(types, dtype))
			params.device_type = dtype;
		else if(device_type_available(types, DEVICE_OPENCL))
			params.device_type = DEVICE_OPENCL;
		else if(device_type_available(types, DEVICE_CUDA))
			params.device_type = DEVICE_CUDA;
	}

	/* Background */
	params.background = background;

	/* samples */
	if(background) {
		params.samples = get_int(cscene, "samples");
	}
	else {
		params.samples = get_int(cscene, "preview_samples");
		if(params.samples == 0)
			params.samples = INT_MAX;
	}

	/* other parameters */
	params.threads = b_scene.render().threads();
	params.tile_size = get_int(cscene, "debug_tile_size");
	params.min_size = get_int(cscene, "debug_min_size");
	params.cancel_timeout = get_float(cscene, "debug_cancel_timeout");
	params.reset_timeout = get_float(cscene, "debug_reset_timeout");
	params.text_timeout = get_float(cscene, "debug_text_timeout");

	if(background) {
		params.progressive = true;
		params.min_size = INT_MAX;
	}
	else
		params.progressive = true;

	return params;
}

CCL_NAMESPACE_END

<|endoftext|>


<commit_before>/*
    Kopete Testbed Protocol

    Copyright (c) 2006 by Cláudio da Silveira Pinheiro   <taupter@gmail.com>
    Kopete    (c) 2002-2006 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "testbedwebcamdialog.h"
#include "avdevice/videodevicepool.h"

#include <qframe.h>
#include <qobject.h>
#include <qwidget.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qvbox.h>
#include <kdebug.h>
#include <klocale.h>

TestbedWebcamDialog::TestbedWebcamDialog( const QString &contactId, QWidget * parent, const char * name )
: KDialogBase( KDialogBase::Plain, i18n( "Webcam for %1" ).arg( contactId ),
                   KDialogBase::Close, KDialogBase::Close, parent, name, false, true /*seperator*/ )
{
	setInitialSize( QSize(320,290), false );

	setEscapeButton( KDialogBase::Close );
	QObject::connect( this, SIGNAL( closeClicked() ), this, SIGNAL( closingWebcamDialog() ) );

	contactName = contactId;
	QWidget *page = plainPage();
	setMainWidget(page);

	QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
	m_imageContainer = new QLabel( page );
	m_imageContainer->setText( i18n( "No webcam image received" ) );
	m_imageContainer->setAlignment( Qt::AlignCenter );
	m_imageContainer->setMinimumSize(320,240);
	m_imageContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	topLayout->add( m_imageContainer );

	m_Viewer = new QLabel( page );
	m_Viewer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	m_Viewer->hide();
	topLayout->add( m_Viewer );

	show();

	m_videoDevicePool = Kopete::AV::VideoDevicePool::self();
	m_videoDevicePool->open();
	m_videoDevicePool->setSize(320, 240);
	m_videoDevicePool->startCapturing();
}

TestbedWebcamDialog::~ TestbedWebcamDialog( )
{
	m_videoDevicePool->stopCapturing();
	m_videoDevicePool->close();
}

void TestbedWebcamDialog::newImage( const QPixmap &image )
{
	m_imageContainer->clear();
	bitBlt(m_imageContainer, 0, 0, &image, 0, Qt::CopyROP);
	show();
}

#include "testbedwebcamdialog.moc"
<commit_msg>Delete the TestWeb webcam dialog when closing it. Request from taupter<commit_after>/*
    Kopete Testbed Protocol

    Copyright (c) 2006 by Cláudio da Silveira Pinheiro   <taupter@gmail.com>
    Kopete    (c) 2002-2006 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "testbedwebcamdialog.h"
#include "avdevice/videodevicepool.h"

#include <qframe.h>
#include <qobject.h>
#include <qwidget.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qvbox.h>
#include <kdebug.h>
#include <klocale.h>

TestbedWebcamDialog::TestbedWebcamDialog( const QString &contactId, QWidget * parent, const char * name )
: KDialogBase( KDialogBase::Plain, Qt::WDestructiveClose, parent, name, false, i18n( "Webcam for %1" ).arg( contactId ),
                   KDialogBase::Close, KDialogBase::Close, true /*seperator*/ )
{
	setInitialSize( QSize(320,290), false );

	setEscapeButton( KDialogBase::Close );
	QObject::connect( this, SIGNAL( closeClicked() ), this, SIGNAL( closingWebcamDialog() ) );

	contactName = contactId;
	QWidget *page = plainPage();
	setMainWidget(page);

	QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
	m_imageContainer = new QLabel( page );
	m_imageContainer->setText( i18n( "No webcam image received" ) );
	m_imageContainer->setAlignment( Qt::AlignCenter );
	m_imageContainer->setMinimumSize(320,240);
	m_imageContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	topLayout->add( m_imageContainer );

	m_Viewer = new QLabel( page );
	m_Viewer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	m_Viewer->hide();
	topLayout->add( m_Viewer );

	show();

	m_videoDevicePool = Kopete::AV::VideoDevicePool::self();
	m_videoDevicePool->open();
	m_videoDevicePool->setSize(320, 240);
	m_videoDevicePool->startCapturing();
}

TestbedWebcamDialog::~ TestbedWebcamDialog( )
{
	kdDebug(14210) << k_funcinfo << endl;

	m_videoDevicePool->stopCapturing();
	m_videoDevicePool->close();
}

void TestbedWebcamDialog::newImage( const QPixmap &image )
{
	m_imageContainer->clear();
	bitBlt(m_imageContainer, 0, 0, &image, 0, Qt::CopyROP);
	show();
}

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


<commit_before>// $Id: INIFile.C,v 1.25 2001/05/17 00:41:33 oliver Exp $

#include <BALL/FORMAT/INIFile.h>
#include <fstream>

#include <iostream>

using namespace std;

namespace BALL
{

	const String INIFile::UNDEFINED = "[UNDEFINED!]";
	const String INIFile::HEADER = "#HEADER!";

	// Default constructor
	INIFile::INIFile()
		:	check_duplicate_keys_(false),
			valid_(false),
			filename_("")
	{
		appendSection(HEADER);
	}

	INIFile::INIFile(const String& filename)
		: check_duplicate_keys_(false),
			valid_(false),
			filename_(filename)
	{
	}

	void INIFile::destroy()
	{
		clear();
		filename_ = "";
		valid_ = false;
	}

	void INIFile::clear()
	{
		sections_.destroy();
		section_index_.destroy();
		valid_ = false;
		check_duplicate_keys_ = false;

    appendSection(HEADER);
	}

	INIFile::~INIFile()
	{
		clear();
	}

	bool INIFile::isValid() const
	{
		return valid_;
	}

	void INIFile::setFilename(const String& filename)
	{
		filename_ = filename;
		valid_ = false;
	}

	const String& INIFile::getFilename() const
	{
		return filename_;
	}

	bool INIFile::read()
	{
		// destroy all datastructures - we make a new start
		// we only keep the filename...
		clear();

		// try to open the file
		ifstream infile(filename_.c_str());

		// if we couldn't open the file: abort
		if (!infile)
		{
			return false;
		}

		List<Section>::Iterator	section_it(sections_.begin());
		List<String >::Iterator	   line_it(section_it->lines_.begin());

		// read all lines from the file
		char buffer[MAX_LINE_LENGTH];
		while (infile.getline(&(buffer[0]), MAX_LINE_LENGTH))
		{
			// remove leading blanks
			String line(buffer);
			line.trimLeft();

			// check for comment lines or empty line
			if ((line.size() == 0) || (line[0] == '!') ||
					(line[0] == ';')   || (line[0] == '#'))
			{
				section_it->lines_.push_back(buffer);
				line_it++;
				continue;
			}

			// check for start of section
			if (line[0] == '[')
			{
				if (!appendSection(line))
				{
					return false;
				}

				section_it++;
				line_it = section_it->lines_.begin();

				continue;
			}

			// this is neither a comment line nor a section start
			// line still has to be added
			if (!appendLine("", line))
			{
				return false;
			}

			line_it++;

		}

		// close the file
		infile.close();

		// done.
		valid_ = true;
		return true;
	}

	bool INIFile::write()
	{
		// try to open the file
		ofstream out(filename_.c_str(), ios::out);

		if (out.bad())
		{
			return false;
		}

		LineIterator line_it(getLine(0));
		// iterate over all lines and write them
		for (; +line_it; ++line_it)
		{
			out << *line_it << endl;
		}

		out.close();
		valid_ = true;
		return true;
	}

	INIFile::LineIterator INIFile::getLine(Size line_number)
	{
		if (line_number >= getNumberOfLines())
		{
			return LineIterator();
		}

		int line_nr(line_number);
		int nr(-1);
		LineIterator line_it;

		Section_iterator section_it(sections_.begin());
		for (; (section_it != sections_.end() && nr != line_nr); ++section_it)
		{
			if ((int)section_it->lines_.size() + nr < line_nr)
			{
				nr += section_it->lines_.size();
				continue;
			}

			line_it = getSectionFirstLine(section_it->getName());
			nr++;

			for (; nr < line_nr; ++line_it)
			{
				nr++;
			}
		}
		return (line_it);
	}

	bool INIFile::setLine(LineIterator line_it, const String& line)
	{
		// section lines cannot be changed with this method
		if (!isValid(line_it) || (*line_it)[0] == '[')
		{
			return false;
		}

		String new_key(line.before("="));
		new_key.trim();

		if ((*line_it).hasSubstring("=", 1))
		{
			// oh, this line had a key :(
			String old_key((*line_it).before("="));
			old_key.trim();

			if (old_key == new_key)
			{
				line_it.setLine_(line);
				return true;
			}

			// its a new key: delete the old one.
			line_it.getSection()->key_map_.remove(old_key);
		}

		line_it.setLine_(line);

		if (line.hasSubstring("=", 1))
		{
			// oh, the new line has a key :(
			line_it.getSection()->key_map_[new_key] = line_it.getPosition();
		}

		return true;
	}

	bool INIFile::insertLine(LineIterator line_it, const String& line)
	{
		if (!isValid(line_it))
		{
      Log.error() << "In INIFile " << filename_ << " , error while inserting line: "
                  << line << " . Illegal iterator!" << endl;
			return false;
		}

		if (line_it.isSectionLastLine())
    {
			return appendLine(line_it.getSection()->getName(), line);
		}

		Section& section(*line_it.getSection());

		// key?
    if (line.hasSubstring("=", 1))
    {
			String key(line.before("="));
			key.trim();

			if (section.key_map_.has(key) && check_duplicate_keys_)
			{

        Log.error() << "In INIFile " << filename_ << " , error while appending line: "
                    << line << " . Key '" << key << "' already exists in section." << endl;
				return false;
			}

			line_it.getSectionNextLine();

			section.key_map_[key] = section.lines_.insert(line_it.position_, line);
			return true;
		}

		line_it.getSectionNextLine();
		section.lines_.insert(line_it.position_, line);
		return true;
	}

	bool INIFile::deleteLine(LineIterator line_it)
	{
		// test if line exists and if we try to remove a section line
		if (!isValid(line_it) || (*line_it)[0] == '[')
		{
			return false;
		}

		// falls key, entfernen
		if ((*line_it).hasSubstring("=", 1))
		{
			String key((*line_it).before("="));
			key.trim();
			line_it.getSection()->key_map_.remove(key);
		}
		line_it.getSection()->lines_.erase(line_it.position_);

		return true;
	}

	bool INIFile::appendLine(const String& sectionName, const String& line)
	{
		String section_name(sectionName);

		if (section_name == "")
		{
			Section_iterator it(sections_.end());
			it--;
			section_name = it->getName();
		}

		if (!hasSection(section_name) || line[0] == '[')
		{
      Log.error() << "In INIFile " << filename_ << " , error while appending line: "
                  << line << " . Illegal section-name: " << sectionName << endl;
			return false;
		}

		Section& section(*getSection(section_name));

		// key?
    if (line.hasSubstring("=", 1))
    {
			String key(line.before("="));
			key.trim();

			if (section.key_map_.has(key) && check_duplicate_keys_)
			{
				Log.error() << "In INIFile " << filename_ << " , error while appending line: "
										<< line << " . Key '" << key << "' already exists in section." << endl;
				return false;
 			}

			section.lines_.push_back(line);
			List<String >::Iterator	line_it(section.lines_.end());
			line_it--;

			section.key_map_[key] = line_it;

			return true;
		}

		section.lines_.push_back(line);

		return true;
	}

	Size INIFile::getNumberOfLines() const
	{
		Size number_of_lines(0);

		List<Section>::ConstIterator it = sections_.begin();
		for (; it != sections_.end(); ++it)
		{
			number_of_lines += it->lines_.size();
		}

		return number_of_lines;
	}

	Size INIFile::getNumberOfSections() const
	{
		// HEADER is not counted
		// BAUSTELLE: wo wird sichergestellt, dass sections_ mindestens
		// 1 ist? Ansonsten gibt es einen Unterlauf und der Rueckgabewert
		// wird sehr gross positiv!
		return (Size)sections_.size() - 1;
	}

	bool INIFile::hasSection(const String& section_name) const
	{
		return section_index_.has(section_name);
	}

	INIFile::Section_iterator INIFile::getSection(const String& section_name)
	{
		if (!section_index_.has(section_name))
		{
			return Section_iterator(sections_.end());
		}
		return section_index_[section_name];
	}

	INIFile::Section_iterator INIFile::getSection(Position pos)
	{
		if (pos >= sections_.size())
		{
			return Section_iterator(sections_.end());
		}

		Section_iterator it = sections_.begin();
		for (Position i = 0; i < pos && it != sections_.end(); i++)
		{
			++it;
		}
		return it;
	}

	INIFile::LineIterator INIFile::getSectionFirstLine(const String& section_name)
	{
		if (!section_index_.has(section_name))
		{
			return LineIterator();
		}

		return LineIterator(sections_, getSection(section_name),
												 getSection(section_name)->lines_.begin());
	}

	INIFile::LineIterator INIFile::getSectionLastLine(const String& section_name)
	{
		if (!section_index_.has(section_name))
		{
			return LineIterator();
		}

		List<String >::Iterator	line_it(getSection(section_name)->lines_.end());
		line_it--;
		return LineIterator(sections_, getSection(section_name), line_it);
	}

	Size INIFile::getSectionLength(const String& section_name) const
	{
		if (!section_index_.has(section_name))
		{
			return INVALID_SIZE;
		}

		return (Size)section_index_[section_name]->lines_.size();
	}

	bool INIFile::hasEntry(const String& section_name, const String& key) const
	{
		if (!section_index_.has(section_name))
		{
			return false;
		}

		// check the hash map for the key
		return section_index_[section_name]->key_map_.has(key);
	}

	bool INIFile::setValue(const String& section_name, const String& key, const String& new_value)
	{
		// does section exists?
		if (!section_index_.has(section_name)									||
				key.isEmpty()																			||
				!section_index_[section_name]->key_map_.has(key))
		{
			return false;
		}

		String new_line(key + "=" + new_value);
		(*section_index_[section_name]->key_map_[key]) = new_line;

		return true;
	}

	String INIFile::getValue(const String& section_name, const String& key) const
	{
		if (!section_index_.has(section_name)									||
				key.isEmpty()																			||
				!section_index_[section_name]->key_map_.has(key))
		{
			return UNDEFINED;
		}

		// get the part of the line behind the "="
		String match_name((*section_index_[section_name]->key_map_[key]).after('=', 0));
		match_name.trim();

		return match_name;
	}

	bool INIFile::deleteSection(const String& section_name)
	{
		if (!section_index_.has(section_name))
		{
			return false;
		}

		if (section_name == HEADER)
		{
			while (+getSectionFirstLine(HEADER))
			{
				deleteLine(getSectionFirstLine(HEADER));
			}

			return true;
		}

		sections_.erase(section_index_[section_name]);
		section_index_.remove(section_name);
		return true;
	}

	bool INIFile::appendSection(const String& section_name)
	{
		// strip the bracket to get the name
		String line(section_name);
		if (line[0] == '[')
		{
			// remove the leading '['
			line.erase(0, 1);
			if (!line.has(']'))
			{
				Log.error() << "In INIFile " << filename_ << " , while adding section:"
										<< "missing bracet." << endl;
				return false;
			}
			line = line.before("]");
		}

		if (section_index_.has(line))
		{
      Log.error() << "In INIFile " << filename_ << " , while adding section: '"
                  << line << "' already exists." << endl;
			return false;
		}

		Section section;
		section.name_ = line;
		sections_.push_back(section);

		Section_iterator section_it(sections_.end());
		section_it--;

		// remember the current section_name
		section_index_[line] = section_it;

		if (line == HEADER)
		{
			return true;
		}

		// store the line
		line = '[' + line +']';
		section_it->lines_.push_back(line);

		return true;
	}

	bool INIFile::apply(UnaryProcessor<LineIterator>& processor)
	{
		if (!processor.start())
		{
			return false;
		}

		LineIterator line_it(getLine(0));
		for (; +line_it; ++line_it)
		{
			Processor::Result result = processor(line_it);

			if (result <= Processor::BREAK)
			{
				return (result && processor.finish());
			}
		}

		return (processor.finish());
	}

	bool INIFile::isValid(const LineIterator& it) const
	{
		return (+it && it.getBound_() == &sections_);
	}

	bool INIFile::operator == (const INIFile& inifile) const
	{
		return (sections_ == inifile.sections_);
	}

	bool INIFile::isValid(const Section_iterator& it) const
	{
		return ((List<Section>::ConstIterator)it != sections_.end());
	}

	void INIFile::setDuplicateKeyCheck(bool mode)
	{
		check_duplicate_keys_ = mode;
	}

	bool INIFile::getDuplicateKeyCheck() const
	{
		return check_duplicate_keys_;
	}

} // namespace BALL
<commit_msg>added: commentary<commit_after>// $Id: INIFile.C,v 1.26 2001/05/17 09:18:59 amoll Exp $

#include <BALL/FORMAT/INIFile.h>
#include <fstream>

#include <iostream>

using namespace std;

namespace BALL
{

	const String INIFile::UNDEFINED = "[UNDEFINED!]";
	const String INIFile::HEADER = "#HEADER!";

	// Default constructor
	INIFile::INIFile()
		:	check_duplicate_keys_(false),
			valid_(false),
			filename_("")
	{
		appendSection(HEADER);
	}

	INIFile::INIFile(const String& filename)
		: check_duplicate_keys_(false),
			valid_(false),
			filename_(filename)
	{
	}

	void INIFile::destroy()
	{
		clear();
		filename_ = "";
		valid_ = false;
	}

	void INIFile::clear()
	{
		sections_.destroy();
		section_index_.destroy();
		valid_ = false;
		check_duplicate_keys_ = false;

    appendSection(HEADER);
	}

	INIFile::~INIFile()
	{
		clear();
	}

	bool INIFile::isValid() const
	{
		return valid_;
	}

	void INIFile::setFilename(const String& filename)
	{
		filename_ = filename;
		valid_ = false;
	}

	const String& INIFile::getFilename() const
	{
		return filename_;
	}

	bool INIFile::read()
	{
		// destroy all datastructures - we make a new start
		// we only keep the filename...
		clear();

		// try to open the file
		ifstream infile(filename_.c_str());

		// if we couldn't open the file: abort
		if (!infile)
		{
			return false;
		}

		List<Section>::Iterator	section_it(sections_.begin());
		List<String >::Iterator	   line_it(section_it->lines_.begin());

		// read all lines from the file
		char buffer[MAX_LINE_LENGTH];
		while (infile.getline(&(buffer[0]), MAX_LINE_LENGTH))
		{
			// remove leading blanks
			String line(buffer);
			line.trimLeft();

			// check for comment lines or empty line
			if ((line.size() == 0) || (line[0] == '!') ||
					(line[0] == ';')   || (line[0] == '#'))
			{
				section_it->lines_.push_back(buffer);
				line_it++;
				continue;
			}

			// check for start of section
			if (line[0] == '[')
			{
				if (!appendSection(line))
				{
					return false;
				}

				section_it++;
				line_it = section_it->lines_.begin();

				continue;
			}

			// this is neither a comment line nor a section start
			// line still has to be added
			if (!appendLine("", line))
			{
				return false;
			}

			line_it++;

		}

		// close the file
		infile.close();

		// done.
		valid_ = true;
		return true;
	}

	bool INIFile::write()
	{
		// try to open the file
		ofstream out(filename_.c_str(), ios::out);

		if (out.bad())
		{
			return false;
		}

		LineIterator line_it(getLine(0));
		// iterate over all lines and write them
		for (; +line_it; ++line_it)
		{
			out << *line_it << endl;
		}

		out.close();
		valid_ = true;
		return true;
	}

	INIFile::LineIterator INIFile::getLine(Size line_number)
	{
		if (line_number >= getNumberOfLines())
		{
			return LineIterator();
		}

		int line_nr(line_number);
		int nr(-1);
		LineIterator line_it;

		Section_iterator section_it(sections_.begin());
		for (; (section_it != sections_.end() && nr != line_nr); ++section_it)
		{
			if ((int)section_it->lines_.size() + nr < line_nr)
			{
				nr += section_it->lines_.size();
				continue;
			}

			line_it = getSectionFirstLine(section_it->getName());
			nr++;

			for (; nr < line_nr; ++line_it)
			{
				nr++;
			}
		}
		return (line_it);
	}

	bool INIFile::setLine(LineIterator line_it, const String& line)
	{
		// section lines cannot be changed with this method
		if (!isValid(line_it) || (*line_it)[0] == '[')
		{
			return false;
		}

		String new_key(line.before("="));
		new_key.trim();

		if ((*line_it).hasSubstring("=", 1))
		{
			// oh, this line had a key :(
			String old_key((*line_it).before("="));
			old_key.trim();

			if (old_key == new_key)
			{
				line_it.setLine_(line);
				return true;
			}

			// its a new key: delete the old one.
			line_it.getSection()->key_map_.remove(old_key);
		}

		line_it.setLine_(line);

		if (line.hasSubstring("=", 1))
		{
			// oh, the new line has a key :(
			line_it.getSection()->key_map_[new_key] = line_it.getPosition();
		}

		return true;
	}

	bool INIFile::insertLine(LineIterator line_it, const String& line)
	{
		if (!isValid(line_it))
		{
      Log.error() << "In INIFile " << filename_ << " , error while inserting line: "
                  << line << " . Illegal iterator!" << endl;
			return false;
		}

		if (line_it.isSectionLastLine())
    {
			return appendLine(line_it.getSection()->getName(), line);
		}

		Section& section(*line_it.getSection());

		// key?
    if (line.hasSubstring("=", 1))
    {
			String key(line.before("="));
			key.trim();

			if (section.key_map_.has(key) && check_duplicate_keys_)
			{

        Log.error() << "In INIFile " << filename_ << " , error while appending line: "
                    << line << " . Key '" << key << "' already exists in section." << endl;
				return false;
			}

			line_it.getSectionNextLine();

			section.key_map_[key] = section.lines_.insert(line_it.position_, line);
			return true;
		}

		line_it.getSectionNextLine();
		section.lines_.insert(line_it.position_, line);
		return true;
	}

	bool INIFile::deleteLine(LineIterator line_it)
	{
		// test if line exists and if we try to remove a section line
		if (!isValid(line_it) || (*line_it)[0] == '[')
		{
			return false;
		}

		// falls key, entfernen
		if ((*line_it).hasSubstring("=", 1))
		{
			String key((*line_it).before("="));
			key.trim();
			line_it.getSection()->key_map_.remove(key);
		}
		line_it.getSection()->lines_.erase(line_it.position_);

		return true;
	}

	bool INIFile::appendLine(const String& sectionName, const String& line)
	{
		String section_name(sectionName);

		if (section_name == "")
		{
			Section_iterator it(sections_.end());
			it--;
			section_name = it->getName();
		}

		if (!hasSection(section_name) || line[0] == '[')
		{
      Log.error() << "In INIFile " << filename_ << " , error while appending line: "
                  << line << " . Illegal section-name: " << sectionName << endl;
			return false;
		}

		Section& section(*getSection(section_name));

		// key?
    if (line.hasSubstring("=", 1))
    {
			String key(line.before("="));
			key.trim();

			if (section.key_map_.has(key) && check_duplicate_keys_)
			{
				Log.error() << "In INIFile " << filename_ << " , error while appending line: "
										<< line << " . Key '" << key << "' already exists in section." << endl;
				return false;
 			}

			section.lines_.push_back(line);
			List<String >::Iterator	line_it(section.lines_.end());
			line_it--;

			section.key_map_[key] = line_it;

			return true;
		}

		section.lines_.push_back(line);

		return true;
	}

	Size INIFile::getNumberOfLines() const
	{
		Size number_of_lines(0);

		List<Section>::ConstIterator it = sections_.begin();
		for (; it != sections_.end(); ++it)
		{
			number_of_lines += it->lines_.size();
		}

		return number_of_lines;
	}

	Size INIFile::getNumberOfSections() const
	{
		// HEADER is not counted
		// every inifile has at least one section: the header
		// wird sehr gross positiv!
		return (Size)sections_.size() - 1;
	}

	bool INIFile::hasSection(const String& section_name) const
	{
		return section_index_.has(section_name);
	}

	INIFile::Section_iterator INIFile::getSection(const String& section_name)
	{
		if (!section_index_.has(section_name))
		{
			return Section_iterator(sections_.end());
		}
		return section_index_[section_name];
	}

	INIFile::Section_iterator INIFile::getSection(Position pos)
	{
		if (pos >= sections_.size())
		{
			return Section_iterator(sections_.end());
		}

		Section_iterator it = sections_.begin();
		for (Position i = 0; i < pos && it != sections_.end(); i++)
		{
			++it;
		}
		return it;
	}

	INIFile::LineIterator INIFile::getSectionFirstLine(const String& section_name)
	{
		if (!section_index_.has(section_name))
		{
			return LineIterator();
		}

		return LineIterator(sections_, getSection(section_name),
												 getSection(section_name)->lines_.begin());
	}

	INIFile::LineIterator INIFile::getSectionLastLine(const String& section_name)
	{
		if (!section_index_.has(section_name))
		{
			return LineIterator();
		}

		List<String >::Iterator	line_it(getSection(section_name)->lines_.end());
		line_it--;
		return LineIterator(sections_, getSection(section_name), line_it);
	}

	Size INIFile::getSectionLength(const String& section_name) const
	{
		if (!section_index_.has(section_name))
		{
			return INVALID_SIZE;
		}

		return (Size)section_index_[section_name]->lines_.size();
	}

	bool INIFile::hasEntry(const String& section_name, const String& key) const
	{
		if (!section_index_.has(section_name))
		{
			return false;
		}

		// check the hash map for the key
		return section_index_[section_name]->key_map_.has(key);
	}

	bool INIFile::setValue(const String& section_name, const String& key, const String& new_value)
	{
		// does section exists?
		if (!section_index_.has(section_name)									||
				key.isEmpty()																			||
				!section_index_[section_name]->key_map_.has(key))
		{
			return false;
		}

		String new_line(key + "=" + new_value);
		(*section_index_[section_name]->key_map_[key]) = new_line;

		return true;
	}

	String INIFile::getValue(const String& section_name, const String& key) const
	{
		if (!section_index_.has(section_name)									||
				key.isEmpty()																			||
				!section_index_[section_name]->key_map_.has(key))
		{
			return UNDEFINED;
		}

		// get the part of the line behind the "="
		String match_name((*section_index_[section_name]->key_map_[key]).after('=', 0));
		match_name.trim();

		return match_name;
	}

	bool INIFile::deleteSection(const String& section_name)
	{
		if (!section_index_.has(section_name))
		{
			return false;
		}

		if (section_name == HEADER)
		{
			while (+getSectionFirstLine(HEADER))
			{
				deleteLine(getSectionFirstLine(HEADER));
			}

			return true;
		}

		sections_.erase(section_index_[section_name]);
		section_index_.remove(section_name);
		return true;
	}

	bool INIFile::appendSection(const String& section_name)
	{
		// strip the bracket to get the name
		String line(section_name);
		if (line[0] == '[')
		{
			// remove the leading '['
			line.erase(0, 1);
			if (!line.has(']'))
			{
				Log.error() << "In INIFile " << filename_ << " , while adding section:"
										<< "missing bracet." << endl;
				return false;
			}
			line = line.before("]");
		}

		if (section_index_.has(line))
		{
      Log.error() << "In INIFile " << filename_ << " , while adding section: '"
                  << line << "' already exists." << endl;
			return false;
		}

		Section section;
		section.name_ = line;
		sections_.push_back(section);

		Section_iterator section_it(sections_.end());
		section_it--;

		// remember the current section_name
		section_index_[line] = section_it;

		if (line == HEADER)
		{
			return true;
		}

		// store the line
		line = '[' + line +']';
		section_it->lines_.push_back(line);

		return true;
	}

	bool INIFile::apply(UnaryProcessor<LineIterator>& processor)
	{
		if (!processor.start())
		{
			return false;
		}

		LineIterator line_it(getLine(0));
		for (; +line_it; ++line_it)
		{
			Processor::Result result = processor(line_it);

			if (result <= Processor::BREAK)
			{
				return (result && processor.finish());
			}
		}

		return (processor.finish());
	}

	bool INIFile::isValid(const LineIterator& it) const
	{
		return (+it && it.getBound_() == &sections_);
	}

	bool INIFile::operator == (const INIFile& inifile) const
	{
		return (sections_ == inifile.sections_);
	}

	bool INIFile::isValid(const Section_iterator& it) const
	{
		return ((List<Section>::ConstIterator)it != sections_.end());
	}

	void INIFile::setDuplicateKeyCheck(bool mode)
	{
		check_duplicate_keys_ = mode;
	}

	bool INIFile::getDuplicateKeyCheck() const
	{
		return check_duplicate_keys_;
	}

} // namespace BALL
<|endoftext|>


<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: residue.C,v 1.22 2002/02/27 12:21:25 sturm Exp $

#include <BALL/KERNEL/residue.h>

#include <BALL/KERNEL/chain.h>
#include <BALL/KERNEL/protein.h>
#include <BALL/STRUCTURE/geometricProperties.h>

using namespace std;

namespace BALL
{

	Residue::Residue()
		throw()
		:	Fragment(),
			id_(BALL_RESIDUE_DEFAULT_ID),
			insertion_code_(BALL_RESIDUE_DEFAULT_INSERTION_CODE)
	{
	}

	Residue::Residue(const Residue& residue, bool deep)
		throw()
		:	Fragment(residue, deep),
			id_(residue.id_),
			insertion_code_(residue.insertion_code_)
	{
	}

	Residue::Residue(const String& name, const String& id, char insertion_code)
		throw()
		:	Fragment(name),
			id_(id),
			insertion_code_(insertion_code)
	{
	}

	Residue::~Residue()
		throw()
	{
		destroy();
	}

	void Residue::clear()
		throw()
	{
		Fragment::clear();
		id_ = BALL_RESIDUE_DEFAULT_ID;
		insertion_code_ = BALL_RESIDUE_DEFAULT_INSERTION_CODE;
	}

	void Residue::destroy()
		throw()
	{
		Fragment::destroy();
		id_ = BALL_RESIDUE_DEFAULT_ID;
		insertion_code_ = BALL_RESIDUE_DEFAULT_INSERTION_CODE;

	}

	void Residue::persistentWrite(PersistenceManager& pm, const char* name) const
		throw(Exception::GeneralException)
	{
		pm.writeObjectHeader(this, name);
			Fragment::persistentWrite(pm);
			pm.writePrimitive(id_, "id_");
			pm.writePrimitive(insertion_code_, "insertion_code_");
		pm.writeObjectTrailer(name);
	}

	void Residue::persistentRead(PersistenceManager& pm)
		throw(Exception::GeneralException)
	{
		pm.checkObjectHeader(RTTI::getStreamName<Fragment>());
			Fragment::persistentRead(pm);
		pm.checkObjectTrailer(0);

		pm.readPrimitive(id_, "id_");
		pm.readPrimitive(insertion_code_, "insertion_code_");
	}

	void Residue::set(const Residue& residue, bool deep)
		throw()
	{
		Fragment::set(residue, deep);

		id_ = residue.id_;
		insertion_code_ = residue.insertion_code_;
	}

	const Residue& Residue::operator =(const Residue& residue)
		throw()
	{
		set(residue);
		return *this;
	}

	void Residue::get(Residue& residue, bool deep) const
		throw()
	{
		residue.set(*this, deep);
	}

	void Residue::swap(Residue& residue)
		throw()
	{
		Fragment::swap(residue);

		id_.swap(residue.id_);

		char temp_insertion_code = insertion_code_;
		insertion_code_ = residue.insertion_code_;
		residue.insertion_code_ = temp_insertion_code;
	}

	bool Residue::hasTorsionPsi() const
		throw()
	{
		// instance must have a parent chain
		if (getChain() == 0)
		{
			return false;
		}
		// at least 2 residues are needed to create an angle
		if (getChain()->countResidues() < 2)
		{
			return false;
		}
		// the torsion angle psi is not defined for
		// the C-terminus
		return !isCTerminal();
	}

	Angle Residue::getTorsionPsi() const
		throw()
	{
		Angle result(0.0);
		if (hasTorsionPsi())
		{
			const Residue* next = getNext(RTTI::getDefault<Residue>());
			if (next != 0)
			{
				const Atom* C = 0;
				const Atom* N = 0;
				const Atom* CA = 0;
				AtomConstIterator it;
				for (it = beginAtom(); +it; ++it)
				{
					if (it->getName() == "C")	C  = &*it;
					if (it->getName() == "CA") CA = &*it;
					if (it->getName() == "N")	N  = &*it;
				}

				const Atom* next_N = 0;
				for (it = next->beginAtom(); +it; ++it)
				{
					if (it->getName() == "N")
					{
						next_N  = &*it;
						break;
					}
				}

				if ((N != 0) && (C != 0) && (CA != 0) && (next_N != 0))
				{
					result = calculateTorsionAngle(*N, *CA, *C, *next_N);
				}
				else
				{
					Log.error() << "Atoms not found:" << N << "/" << CA << "/" << C << "/" << next_N << endl;
				}
			}
			else
			{
				Log.error() << "No next residue!" << endl;
			}
		}

		return result;
	}

	bool Residue::hasTorsionPhi() const
		throw()
	{
		// instance must have a parent chain
		if (getChain() == 0)
		{
			return false;
		}
		// at least 2 residues are needed to create an angle
		if (getChain()->countResidues() < 2)
		{
			return false;
		}
		// the torsion angle phi is not defined for
		// the N-terminus
		return !isNTerminal();
	}

	Angle Residue::getTorsionPhi() const
		throw()
	{
		Angle result(0.0);
		if (hasTorsionPhi())
		{
			const Residue* previous = getPrevious(RTTI::getDefault<Residue>());
			if (previous != 0)
			{
				const Atom* C = 0;
				const Atom* N = 0;
				const Atom* CA = 0;
				AtomConstIterator it;
				for (it = beginAtom(); +it; ++it)
				{
					if (it->getName() == "C")	 C  = &*it;
					if (it->getName() == "CA") CA = &*it;
					if (it->getName() == "N")  N  = &*it;
				}

				const Atom* last_C = 0;
				for (it = previous->beginAtom(); +it; ++it)
				{
					if (it->getName() == "C")
					{
						last_C  = &*it;
						break;
					}
				}

				if ((N != 0) && (C != 0) && (CA != 0) && (last_C != 0))
				{
					result = calculateTorsionAngle(*last_C, *N, *CA, *C);
				}
				else
				{
					Log.error() << "Atoms not found:" << last_C << "/" << N << "/" << CA << "/" << C << endl;
				}
			}
			else
			{
				Log.error() << "No previous residue!" << endl;
			}
		}

		return result;
	}

	Protein* Residue::getProtein()
		throw()
	{
		for (Composite::AncestorIterator ancestor_it = beginAncestor(); !ancestor_it.isEnd(); ++ancestor_it)
		{
			if (RTTI::isKindOf<Protein>(*ancestor_it))
			{
				return (Protein *)&*ancestor_it;
			}
		}

		return 0;
	}

	const Protein* Residue::getProtein() const
		throw()
	{
		return ((Residue *)this)->getProtein();
	}

	Chain* Residue::getChain()
		throw()
	{
		for (Composite::AncestorIterator ancestor_it = beginAncestor(); !ancestor_it.isEnd(); ++ancestor_it)
		{
			if (RTTI::isKindOf<Chain>(*ancestor_it))
			{
				return (Chain *)&*ancestor_it;
			}
		}

		return 0;
	}

	const Chain *Residue::getChain() const
		throw()
	{
		return ((Residue *)this)->getChain();
	}

	PDBAtom *Residue::getPDBAtom(Position position)
		throw()
	{
		for (PDBAtomIterator protein_atom_iterator = beginPDBAtom();
				 !protein_atom_iterator.isEnd(); ++protein_atom_iterator)
		{
			if (position-- == 0)
			{
				return &(*protein_atom_iterator);
			}
		}

		return 0;
	}

	const PDBAtom* Residue::getPDBAtom(Position position) const
		throw()
	{
		return ((Residue *)this)->getPDBAtom(position);
	}

	void Residue::setID(const String &id)
		throw()
	{
		id_ = id;
	}

	const String &Residue::getID() const
		throw()
	{
		return id_;
	}

	void Residue::setInsertionCode(char insertion_code)
		throw()
	{
		insertion_code_ = insertion_code;
	}

	char Residue::getInsertionCode() const
		throw()
	{
		return insertion_code_;
	}

	Size Residue::countPDBAtoms() const
		throw()
	{
		register Size size = 0;

		for (PDBAtomConstIterator protein_atom_iterator = beginPDBAtom();
				 !protein_atom_iterator.isEnd(); ++protein_atom_iterator)
		{
			++size;
		}

		return size;
	}

	void Residue::prepend(PDBAtom &protein_atom)
		throw()
	{
		Fragment::prepend(protein_atom);
	}

	void Residue::append(PDBAtom& protein_atom)
		throw()
	{
		Fragment::append(protein_atom);
	}

	void Residue::insert(PDBAtom& protein_atom)
		throw()
	{
		Fragment::insert(protein_atom);
	}

	void Residue::insertBefore(PDBAtom& protein_atom, Composite& before)
		throw()
	{
		Fragment::insertBefore(protein_atom, before);
	}

	void Residue::insertAfter(PDBAtom& protein_atom, Composite& after)
		throw()
	{
		Fragment::insertAfter(protein_atom, after);
	}

	bool Residue::remove(PDBAtom& protein_atom)
		throw()
	{
		return Fragment::remove(protein_atom);
	}

	void Residue::spliceBefore(Residue& residue)
		throw()
	{
		Fragment::spliceBefore(residue);
	}

	void Residue::spliceAfter(Residue& residue)
		throw()
	{
		Fragment::spliceAfter(residue);
	}

	void Residue::splice(Residue& residue)
		throw()
	{
		Fragment::splice(residue);
	}

	bool Residue::isAminoAcid() const
		throw()
	{
		return hasProperty(PROPERTY__AMINO_ACID);
	}

	bool Residue::isTerminal() const
		throw()
	{
		return (isNTerminal() || isCTerminal());
	}

	bool Residue::isNTerminal() const
		throw()
	{
		if (isAminoAcid() == true)
		{
			const Chain* chain = getChain();

			if (chain != 0)
			{
				ResidueConstIterator res_it = chain->beginResidue();
				for (; +res_it && &(*res_it) != this && !res_it->isAminoAcid(); ++res_it);

				return (&(*res_it) == this);
			}
		}

		return false;
	}

	bool Residue::isCTerminal() const
		throw()
	{
		if (isAminoAcid() == true)
		{
			const Chain* chain = getChain();

			if (chain != 0)
			{
				ResidueConstIterator res_it = chain->rbeginResidue();
				for (; +res_it && &(*res_it) != this && !res_it->isAminoAcid(); --res_it);

				return (&(*res_it) == this);
			}
		}

		return false;
	}

	bool Residue::isValid() const
		throw()
	{
		return (Fragment::isValid() && id_.isValid());
	}

	void Residue::dump(ostream& s, Size depth) const
		throw()
	{
		BALL_DUMP_STREAM_PREFIX(s);

		Fragment::dump(s, depth);

		BALL_DUMP_DEPTH(s, depth);
		s << "  id: " << id_ << endl;

		BALL_DUMP_DEPTH(s, depth);
		s << "  insertion code: " << insertion_code_ << endl;

		BALL_DUMP_STREAM_SUFFIX(s);
	}

	String Residue::getFullName(Residue::FullNameType type) const
		throw()
	{
		// retrieve the residue name and remove blanks
		String full_name = getName();
		full_name.trim();

		// if the variant extension should be added, do so
		if (type == ADD_VARIANT_EXTENSIONS)
		{
			String suffix = "-";
			if (isNTerminal())
			{
				suffix = "-N";
			}
			if (isCTerminal())
			{
				suffix = "-C";
			}
			if (isCTerminal() && isNTerminal())
			{
				suffix = "-M";
			}
			if (hasProperty(Residue::PROPERTY__HAS_SSBOND))
			{
				suffix += "S";
			}

			if (suffix != "-")
			{
				full_name += suffix;
			}
		}

		return full_name;
	}

	bool Residue::operator == (const Residue& residue) const
		throw()
	{
		return(
			Fragment::operator ==(residue)							&&
			id_							== residue.id_							&&
			insertion_code_	== residue.insertion_code_	);
	}

	bool Residue::operator != (const Residue& residue) const
		throw()
	{
		return ! (*this == residue);
	}

} // namespace BALL
<commit_msg>changed: hasTorsionPsi/Phi now considers amino acids only!<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: residue.C,v 1.23 2003/01/08 09:24:31 oliver Exp $

#include <BALL/KERNEL/residue.h>

#include <BALL/KERNEL/chain.h>
#include <BALL/KERNEL/protein.h>
#include <BALL/STRUCTURE/geometricProperties.h>

using namespace std;

namespace BALL
{

	Residue::Residue()
		throw()
		:	Fragment(),
			id_(BALL_RESIDUE_DEFAULT_ID),
			insertion_code_(BALL_RESIDUE_DEFAULT_INSERTION_CODE)
	{
	}

	Residue::Residue(const Residue& residue, bool deep)
		throw()
		:	Fragment(residue, deep),
			id_(residue.id_),
			insertion_code_(residue.insertion_code_)
	{
	}

	Residue::Residue(const String& name, const String& id, char insertion_code)
		throw()
		:	Fragment(name),
			id_(id),
			insertion_code_(insertion_code)
	{
	}

	Residue::~Residue()
		throw()
	{
		destroy();
	}

	void Residue::clear()
		throw()
	{
		Fragment::clear();
		id_ = BALL_RESIDUE_DEFAULT_ID;
		insertion_code_ = BALL_RESIDUE_DEFAULT_INSERTION_CODE;
	}

	void Residue::destroy()
		throw()
	{
		Fragment::destroy();
		id_ = BALL_RESIDUE_DEFAULT_ID;
		insertion_code_ = BALL_RESIDUE_DEFAULT_INSERTION_CODE;

	}

	void Residue::persistentWrite(PersistenceManager& pm, const char* name) const
		throw(Exception::GeneralException)
	{
		pm.writeObjectHeader(this, name);
			Fragment::persistentWrite(pm);
			pm.writePrimitive(id_, "id_");
			pm.writePrimitive(insertion_code_, "insertion_code_");
		pm.writeObjectTrailer(name);
	}

	void Residue::persistentRead(PersistenceManager& pm)
		throw(Exception::GeneralException)
	{
		pm.checkObjectHeader(RTTI::getStreamName<Fragment>());
			Fragment::persistentRead(pm);
		pm.checkObjectTrailer(0);

		pm.readPrimitive(id_, "id_");
		pm.readPrimitive(insertion_code_, "insertion_code_");
	}

	void Residue::set(const Residue& residue, bool deep)
		throw()
	{
		Fragment::set(residue, deep);

		id_ = residue.id_;
		insertion_code_ = residue.insertion_code_;
	}

	const Residue& Residue::operator =(const Residue& residue)
		throw()
	{
		set(residue);
		return *this;
	}

	void Residue::get(Residue& residue, bool deep) const
		throw()
	{
		residue.set(*this, deep);
	}

	void Residue::swap(Residue& residue)
		throw()
	{
		Fragment::swap(residue);

		id_.swap(residue.id_);

		char temp_insertion_code = insertion_code_;
		insertion_code_ = residue.insertion_code_;
		residue.insertion_code_ = temp_insertion_code;
	}

	bool Residue::hasTorsionPsi() const
		throw()
	{
		// instance must have a parent chain
		if (getChain() == 0)
		{
			return false;
		}
		// at least 2 residues are needed to create an angle
		if (getChain()->countResidues() < 2)
		{
			return false;
		}
		// the torsion angle psi is not defined for
		// the C-terminus
		return !isCTerminal() && hasProperty(PROPERTY__AMINO_ACID);
	}

	Angle Residue::getTorsionPsi() const
		throw()
	{
		Angle result(0.0);
		if (hasTorsionPsi())
		{
			const Residue* next = getNext(RTTI::getDefault<Residue>());
			if (next != 0)
			{
				const Atom* C = 0;
				const Atom* N = 0;
				const Atom* CA = 0;
				AtomConstIterator it;
				for (it = beginAtom(); +it; ++it)
				{
					if (it->getName() == "C")	C  = &*it;
					if (it->getName() == "CA") CA = &*it;
					if (it->getName() == "N")	N  = &*it;
				}

				const Atom* next_N = 0;
				for (it = next->beginAtom(); +it; ++it)
				{
					if (it->getName() == "N")
					{
						next_N  = &*it;
						break;
					}
				}

				if ((N != 0) && (C != 0) && (CA != 0) && (next_N != 0))
				{
					result = calculateTorsionAngle(*N, *CA, *C, *next_N);
				}
				else
				{
					Log.error() << "Atoms not found:" << N << "/" << CA << "/" << C << "/" << next_N << endl;
				}
			}
			else
			{
				Log.error() << "No next residue!" << endl;
			}
		}

		return result;
	}

	bool Residue::hasTorsionPhi() const
		throw()
	{
		// instance must have a parent chain
		if (getChain() == 0)
		{
			return false;
		}
		// at least 2 residues are needed to create an angle
		if (getChain()->countResidues() < 2)
		{
			return false;
		}
		// the torsion angle phi is not defined for
		// the N-terminus
		return !isNTerminal() && hasProperty(PROPERTY__AMINO_ACID);
	}

	Angle Residue::getTorsionPhi() const
		throw()
	{
		Angle result(0.0);
		if (hasTorsionPhi())
		{
			const Residue* previous = getPrevious(RTTI::getDefault<Residue>());
			if (previous != 0)
			{
				const Atom* C = 0;
				const Atom* N = 0;
				const Atom* CA = 0;
				AtomConstIterator it;
				for (it = beginAtom(); +it; ++it)
				{
					if (it->getName() == "C")	 C  = &*it;
					if (it->getName() == "CA") CA = &*it;
					if (it->getName() == "N")  N  = &*it;
				}

				const Atom* last_C = 0;
				for (it = previous->beginAtom(); +it; ++it)
				{
					if (it->getName() == "C")
					{
						last_C  = &*it;
						break;
					}
				}

				if ((N != 0) && (C != 0) && (CA != 0) && (last_C != 0))
				{
					result = calculateTorsionAngle(*last_C, *N, *CA, *C);
				}
				else
				{
					Log.error() << "Atoms not found:" << last_C << "/" << N << "/" << CA << "/" << C << endl;
				}
			}
			else
			{
				Log.error() << "No previous residue!" << endl;
			}
		}

		return result;
	}

	Protein* Residue::getProtein()
		throw()
	{
		for (Composite::AncestorIterator ancestor_it = beginAncestor(); !ancestor_it.isEnd(); ++ancestor_it)
		{
			if (RTTI::isKindOf<Protein>(*ancestor_it))
			{
				return (Protein *)&*ancestor_it;
			}
		}

		return 0;
	}

	const Protein* Residue::getProtein() const
		throw()
	{
		return ((Residue *)this)->getProtein();
	}

	Chain* Residue::getChain()
		throw()
	{
		for (Composite::AncestorIterator ancestor_it = beginAncestor(); !ancestor_it.isEnd(); ++ancestor_it)
		{
			if (RTTI::isKindOf<Chain>(*ancestor_it))
			{
				return (Chain *)&*ancestor_it;
			}
		}

		return 0;
	}

	const Chain *Residue::getChain() const
		throw()
	{
		return ((Residue *)this)->getChain();
	}

	PDBAtom *Residue::getPDBAtom(Position position)
		throw()
	{
		for (PDBAtomIterator protein_atom_iterator = beginPDBAtom();
				 !protein_atom_iterator.isEnd(); ++protein_atom_iterator)
		{
			if (position-- == 0)
			{
				return &(*protein_atom_iterator);
			}
		}

		return 0;
	}

	const PDBAtom* Residue::getPDBAtom(Position position) const
		throw()
	{
		return ((Residue *)this)->getPDBAtom(position);
	}

	void Residue::setID(const String &id)
		throw()
	{
		id_ = id;
	}

	const String &Residue::getID() const
		throw()
	{
		return id_;
	}

	void Residue::setInsertionCode(char insertion_code)
		throw()
	{
		insertion_code_ = insertion_code;
	}

	char Residue::getInsertionCode() const
		throw()
	{
		return insertion_code_;
	}

	Size Residue::countPDBAtoms() const
		throw()
	{
		register Size size = 0;

		for (PDBAtomConstIterator protein_atom_iterator = beginPDBAtom();
				 !protein_atom_iterator.isEnd(); ++protein_atom_iterator)
		{
			++size;
		}

		return size;
	}

	void Residue::prepend(PDBAtom &protein_atom)
		throw()
	{
		Fragment::prepend(protein_atom);
	}

	void Residue::append(PDBAtom& protein_atom)
		throw()
	{
		Fragment::append(protein_atom);
	}

	void Residue::insert(PDBAtom& protein_atom)
		throw()
	{
		Fragment::insert(protein_atom);
	}

	void Residue::insertBefore(PDBAtom& protein_atom, Composite& before)
		throw()
	{
		Fragment::insertBefore(protein_atom, before);
	}

	void Residue::insertAfter(PDBAtom& protein_atom, Composite& after)
		throw()
	{
		Fragment::insertAfter(protein_atom, after);
	}

	bool Residue::remove(PDBAtom& protein_atom)
		throw()
	{
		return Fragment::remove(protein_atom);
	}

	void Residue::spliceBefore(Residue& residue)
		throw()
	{
		Fragment::spliceBefore(residue);
	}

	void Residue::spliceAfter(Residue& residue)
		throw()
	{
		Fragment::spliceAfter(residue);
	}

	void Residue::splice(Residue& residue)
		throw()
	{
		Fragment::splice(residue);
	}

	bool Residue::isAminoAcid() const
		throw()
	{
		return hasProperty(PROPERTY__AMINO_ACID);
	}

	bool Residue::isTerminal() const
		throw()
	{
		return (isNTerminal() || isCTerminal());
	}

	bool Residue::isNTerminal() const
		throw()
	{
		if (isAminoAcid() == true)
		{
			const Chain* chain = getChain();

			if (chain != 0)
			{
				ResidueConstIterator res_it = chain->beginResidue();
				for (; +res_it && &(*res_it) != this && !res_it->isAminoAcid(); ++res_it);

				return (&(*res_it) == this);
			}
		}

		return false;
	}

	bool Residue::isCTerminal() const
		throw()
	{
		if (isAminoAcid() == true)
		{
			const Chain* chain = getChain();

			if (chain != 0)
			{
				ResidueConstIterator res_it = chain->rbeginResidue();
				for (; +res_it && &(*res_it) != this && !res_it->isAminoAcid(); --res_it);

				return (&(*res_it) == this);
			}
		}

		return false;
	}

	bool Residue::isValid() const
		throw()
	{
		return (Fragment::isValid() && id_.isValid());
	}

	void Residue::dump(ostream& s, Size depth) const
		throw()
	{
		BALL_DUMP_STREAM_PREFIX(s);

		Fragment::dump(s, depth);

		BALL_DUMP_DEPTH(s, depth);
		s << "  id: " << id_ << endl;

		BALL_DUMP_DEPTH(s, depth);
		s << "  insertion code: " << insertion_code_ << endl;

		BALL_DUMP_STREAM_SUFFIX(s);
	}

	String Residue::getFullName(Residue::FullNameType type) const
		throw()
	{
		// retrieve the residue name and remove blanks
		String full_name = getName();
		full_name.trim();

		// if the variant extension should be added, do so
		if (type == ADD_VARIANT_EXTENSIONS)
		{
			String suffix = "-";
			if (isNTerminal())
			{
				suffix = "-N";
			}
			if (isCTerminal())
			{
				suffix = "-C";
			}
			if (isCTerminal() && isNTerminal())
			{
				suffix = "-M";
			}
			if (hasProperty(Residue::PROPERTY__HAS_SSBOND))
			{
				suffix += "S";
			}

			if (suffix != "-")
			{
				full_name += suffix;
			}
		}

		return full_name;
	}

	bool Residue::operator == (const Residue& residue) const
		throw()
	{
		return(
			Fragment::operator ==(residue)							&&
			id_							== residue.id_							&&
			insertion_code_	== residue.insertion_code_	);
	}

	bool Residue::operator != (const Residue& residue) const
		throw()
	{
		return ! (*this == residue);
	}

} // namespace BALL
<|endoftext|>


<commit_before>#include "downloader.h"
#include "ui_downloader.h"

Downloader::Downloader(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Downloader)
{
    ui->setupUi(this);
    ui->urlEdit->setText("");
    ui->statusLabel->setWordWrap(true);
    ui->downloadButton->setDefault(true);
    ui->quitButton->setAutoDefault(false);
    ui->continueButton->setAutoDefault(false);

    progressDialog = new QProgressDialog(this);

    // This will be set true when Quit/Continue pressed
    downloaderQuit = false;
    downloaderContinue = false;

    connect(ui->urlEdit, SIGNAL(textChanged(QString)),
                this, SLOT(enableDownloadButton()));
    connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelDownload()));
}

Downloader::~Downloader()
{
    delete ui;
}

void Downloader::on_downloadButton_clicked()
{
    manager = new QNetworkAccessManager(this);

    // get url
    url = (ui->urlEdit->text());

    QFileInfo fileInfo(url.path());
    QString fileName = fileInfo.fileName();

    if (fileName.isEmpty())
    {
        QMessageBox::information(this, tr("Downloader"),
                      tr("Filename cannot be empty.")
                      );
        return;
    }

    if (!fileDest.isEmpty())
    {
        fileName = fileDest;
    }

    if (QFile::exists(fileName))
    {
        if (QMessageBox::question(this, tr("Downloader"),
                tr("There already exists a file called %1 in "
                "the current directory. Overwrite?").arg(fileName),
                QMessageBox::Yes|QMessageBox::No, QMessageBox::No)
                == QMessageBox::No)
        {
            ui->continueButton->setEnabled(true);
            return;
        }
        QFile::remove(fileName);
    }

    file = new QFile(fileName);
    if (!file->open(QIODevice::WriteOnly))
    {
        QMessageBox::information(this, tr("Downloader"),
                      tr("Unable to save the file %1: %2.")
                      .arg(fileName).arg(file->errorString()));
        delete file;
        file = 0;
        return;
    }

    // used for progressDialog
    // This will be set true when canceled from progress dialog
    httpRequestAborted = false;

    progressDialog->setWindowTitle(tr("Downloader"));
    progressDialog->setLabelText(tr("Downloading %1.").arg(fileName));

    // download button disabled after requesting download.
    ui->downloadButton->setEnabled(false);
    ui->continueButton->setEnabled(false);

    startRequest(url);
}

void Downloader::httpReadyRead()
{
    // this slot gets called every time the QNetworkReply has new data.
    // We read all of its new data and write it into the file.
    // That way we use less RAM than when reading it at the finished()
    // signal of the QNetworkReply
    if (file)
        file->write(reply->readAll());
}

void Downloader::updateDownloadProgress(qint64 bytesRead, qint64 totalBytes)
{
    if (httpRequestAborted)
        return;

    progressDialog->setMaximum(totalBytes);
    progressDialog->setValue(bytesRead);
}

void Downloader::on_continueButton_clicked()
{
    downloaderContinue = true;

    this->close();
}

void Downloader::on_quitButton_clicked()
{
    downloaderQuit = true;

    this->close();
}

void Downloader::on_urlEdit_returnPressed()
{
    on_downloadButton_clicked();
}

void Downloader::enableDownloadButton()
{
    ui->downloadButton->setEnabled(!(ui->urlEdit->text()).isEmpty());
}

// During the download progress, it can be canceled
void Downloader::cancelDownload()
{
    ui->statusLabel->setText(tr("Download canceled."));
    httpRequestAborted = true;
    reply->abort();
    ui->downloadButton->setEnabled(true);
}

// When download finished or canceled, this will be called
void Downloader::downloaderFinished()
{
    // when canceled
    if (httpRequestAborted)
    {
        if (file)
        {
            file->close();
            file->remove();
            delete file;
            file = 0;
        }
        reply->deleteLater();
        progressDialog->hide();
        return;
    }

    // download finished normally
    progressDialog->hide();
    file->flush();
    file->close();

    // get redirection url
    QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
    if (reply->error())
    {
        file->remove();
        QMessageBox::information(this, tr("Downloader"),
                                 tr("Download failed: %1.")
                                 .arg(reply->errorString()));
        ui->downloadButton->setEnabled(true);
    }
    else
    {
        if (!redirectionTarget.isNull())
        {
            QUrl newUrl = url.resolved(redirectionTarget.toUrl());
            if (QMessageBox::question(this, tr("Downloader"),
                                  tr("Redirect to %1 ?").arg(newUrl.toString()),
                                  QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
            {
                url = newUrl;
                reply->deleteLater();
                file->open(QIODevice::WriteOnly);
                file->resize(0);
                startRequest(url);
                return;
            }
        }
        else
        {
            QString fileName = QFileInfo(QUrl(ui->urlEdit->text()).path()).fileName();
            ui->statusLabel->setText(tr("Downloaded %1 to %2.").arg(fileName).arg(fileDest));
            ui->downloadButton->setEnabled(false);
            ui->continueButton->setEnabled(true);
        }
    }

    reply->deleteLater();
    reply = 0;
    delete file;
    file = 0;
    manager = 0;
}

// This will be called when download button is clicked
void Downloader::startRequest(QUrl url)
{
    // get() method posts a request
    // to obtain the contents of the target request
    // and returns a new QNetworkReply object
    // opened for reading which emits
    // the readyRead() signal whenever new data arrives.
    reply = manager->get(QNetworkRequest(url));

    // Whenever more data is received from the network,
    // this readyRead() signal is emitted
    connect(reply, SIGNAL(readyRead()),
            this, SLOT(httpReadyRead()));

    // Also, downloadProgress() signal is emitted when data is received
    connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
            this, SLOT(updateDownloadProgress(qint64,qint64)));

    // This signal is emitted when the reply has finished processing.
    // After this signal is emitted,
    // there will be no more updates to the reply's data or metadata.
    connect(reply, SIGNAL(finished()),
            this, SLOT(downloaderFinished()));
}

// This is called when the URL is already pre-defined and you want to bypass the dialog window
void Downloader::setUrl(QUrl url)
{
    ui->urlEdit->setText(url.url());
}

// This is called when the Destination is already pre-defined and you want to bypass the dialog window
void Downloader::setDest(QString dest)
{
    fileDest = dest;

    if (QFile::exists(fileDest))
    {
        ui->statusLabel->setText(tr("File: %1 exists.").arg(fileDest));
        ui->continueButton->setEnabled(true);
    }
    else
    {
        ui->continueButton->setEnabled(false);
    }
}
<commit_msg>bug fix<commit_after>#include "downloader.h"
#include "ui_downloader.h"

Downloader::Downloader(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Downloader)
{
    ui->setupUi(this);
    ui->urlEdit->setText("");
    ui->statusLabel->setWordWrap(true);
    ui->downloadButton->setDefault(true);
    ui->quitButton->setAutoDefault(false);
    ui->continueButton->setAutoDefault(false);

    progressDialog = new QProgressDialog(this);

    // This will be set true when Quit/Continue pressed
    downloaderQuit = false;
    downloaderContinue = false;

    connect(ui->urlEdit, SIGNAL(textChanged(QString)),
                this, SLOT(enableDownloadButton()));
    connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelDownload()));
}

Downloader::~Downloader()
{
    delete ui;
}

void Downloader::on_downloadButton_clicked()
{
    manager = new QNetworkAccessManager(this);

    // get url
    url = (ui->urlEdit->text());

    QFileInfo fileInfo(url.path());
    QString fileName = fileInfo.fileName();

    if (fileName.isEmpty())
    {
        QMessageBox::information(this, tr("Downloader"),
                      tr("Filename cannot be empty.")
                      );
        return;
    }

    if (!fileDest.isEmpty())
    {
        fileName = fileDest;
    }

    if (QFile::exists(fileName))
    {
        if (QMessageBox::question(this, tr("Downloader"),
                tr("There already exists a file called %1 in "
                "the current directory. Overwrite?").arg(fileName),
                QMessageBox::Yes|QMessageBox::No, QMessageBox::No)
                == QMessageBox::No)
        {
            ui->continueButton->setEnabled(true);
            return;
        }
        QFile::remove(fileName);
    }

    file = new QFile(fileName);
    if (!file->open(QIODevice::WriteOnly))
    {
        QMessageBox::information(this, tr("Downloader"),
                      tr("Unable to save the file %1: %2.")
                      .arg(fileName).arg(file->errorString()));
        delete file;
        file = 0;
        return;
    }

    // used for progressDialog
    // This will be set true when canceled from progress dialog
    httpRequestAborted = false;

    progressDialog->setWindowTitle(tr("Downloader"));
    progressDialog->setLabelText(tr("Downloading %1.").arg(fileName));

    // download button disabled after requesting download.
    ui->downloadButton->setEnabled(false);
    ui->continueButton->setEnabled(false);

    startRequest(url);
}

void Downloader::httpReadyRead()
{
    // this slot gets called every time the QNetworkReply has new data.
    // We read all of its new data and write it into the file.
    // That way we use less RAM than when reading it at the finished()
    // signal of the QNetworkReply
    if (file)
        file->write(reply->readAll());
}

void Downloader::updateDownloadProgress(qint64 bytesRead, qint64 totalBytes)
{
    if (httpRequestAborted)
        return;

    progressDialog->setMaximum(totalBytes);
    progressDialog->setValue(bytesRead);
}

void Downloader::on_continueButton_clicked()
{
    downloaderContinue = true;

    this->close();
}

void Downloader::on_quitButton_clicked()
{
    downloaderQuit = true;

    this->close();
}

void Downloader::on_urlEdit_returnPressed()
{
    on_downloadButton_clicked();
}

void Downloader::enableDownloadButton()
{
    ui->downloadButton->setEnabled(!(ui->urlEdit->text()).isEmpty());
}

// During the download progress, it can be canceled
void Downloader::cancelDownload()
{
    ui->statusLabel->setText(tr("Download canceled."));
    httpRequestAborted = true;
    reply->abort();
    ui->downloadButton->setEnabled(true);
}

// When download finished or canceled, this will be called
void Downloader::downloaderFinished()
{
    // when canceled
    if (httpRequestAborted)
    {
        if (file)
        {
            file->close();
            file->remove();
            delete file;
            file = 0;
        }
        reply->deleteLater();
        progressDialog->hide();
        return;
    }

    // download finished normally
    progressDialog->hide();
    file->flush();
    file->close();

    // get redirection url
    QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
    if (reply->error())
    {
        file->remove();
        QMessageBox::information(this, tr("Downloader"),
                                 tr("Download failed: %1.")
                                 .arg(reply->errorString()));
        ui->downloadButton->setEnabled(true);
    }
    else
    {
        if (!redirectionTarget.isNull())
        {
            QUrl newUrl = url.resolved(redirectionTarget.toUrl());
            if (QMessageBox::question(this, tr("Downloader"),
                                  tr("Redirect to %1 ?").arg(newUrl.toString()),
                                  QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
            {
                url = newUrl;
                reply->deleteLater();
                file->open(QIODevice::WriteOnly);
                file->resize(0);
                startRequest(url);
                return;
            }
        }
        else
        {
            QString fileName = QFileInfo(QUrl(ui->urlEdit->text()).path()).fileName();
            ui->statusLabel->setText(tr("Downloaded %1 to %2.").arg(fileName).arg(fileDest));
            ui->downloadButton->setEnabled(false);
            ui->continueButton->setEnabled(true);
            ui->continueButton->setDefault(true);
        }
    }

    reply->deleteLater();
    reply = 0;
    delete file;
    file = 0;
    manager = 0;
}

// This will be called when download button is clicked
void Downloader::startRequest(QUrl url)
{
    // get() method posts a request
    // to obtain the contents of the target request
    // and returns a new QNetworkReply object
    // opened for reading which emits
    // the readyRead() signal whenever new data arrives.
    reply = manager->get(QNetworkRequest(url));

    // Whenever more data is received from the network,
    // this readyRead() signal is emitted
    connect(reply, SIGNAL(readyRead()),
            this, SLOT(httpReadyRead()));

    // Also, downloadProgress() signal is emitted when data is received
    connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
            this, SLOT(updateDownloadProgress(qint64,qint64)));

    // This signal is emitted when the reply has finished processing.
    // After this signal is emitted,
    // there will be no more updates to the reply's data or metadata.
    connect(reply, SIGNAL(finished()),
            this, SLOT(downloaderFinished()));
}

// This is called when the URL is already pre-defined and you want to bypass the dialog window
void Downloader::setUrl(QUrl url)
{
    ui->urlEdit->setText(url.url());
}

// This is called when the Destination is already pre-defined and you want to bypass the dialog window
void Downloader::setDest(QString dest)
{
    fileDest = dest;

    if (QFile::exists(fileDest))
    {
        ui->statusLabel->setText(tr("File: %1 exists.").arg(fileDest));
        ui->continueButton->setEnabled(true);
        ui->continueButton->setDefault(true);
    }
    else
    {
        ui->continueButton->setEnabled(false);
    }
}
<|endoftext|>


<commit_before><commit_msg>Fixed cant destroy sign<commit_after><|endoftext|>


<commit_before>#include "process.hpp"
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <stdexcept>

Process::Data::Data(): id(-1) {}

Process::id_type Process::open(const std::string &command, const std::string &path) {
  if(open_stdin)
    stdin_fd=std::make_unique<fd_type>();
  if(read_stdout)
    stdout_fd=std::make_unique<fd_type>();
  if(read_stderr)
    stderr_fd=std::make_unique<fd_type>();

  int stdin_p[2], stdout_p[2], stderr_p[2];

  if(stdin_fd && pipe(stdin_p)!=0) {
    close(stdin_p[0]);close(stdin_p[1]);
    return -1;
  }
  if(stdout_fd && pipe(stdout_p)!=0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    close(stdout_p[0]);close(stdout_p[1]);
    return -1;
  }
  if(stderr_fd && pipe(stderr_p)!=0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    close(stderr_p[0]);close(stderr_p[1]);
    return -1;
  }

  id_type pid = fork();

  if (pid < 0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    if(stderr_fd) {close(stderr_p[0]);close(stderr_p[1]);}
    return pid;
  }
  else if (pid == 0) {
    if(stdin_fd) dup2(stdin_p[0], 0);
    if(stdout_fd) dup2(stdout_p[1], 1);
    if(stderr_fd) dup2(stderr_p[1], 2);
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    if(stderr_fd) {close(stderr_p[0]);close(stderr_p[1]);}

    //Based on http://stackoverflow.com/a/899533/3808293
    int fd_max=sysconf(_SC_OPEN_MAX);
    for(int fd=3;fd<fd_max;fd++)
      close(fd);

    setpgid(0, 0);
    //TODO: See here on how to emulate tty for colors: http://stackoverflow.com/questions/1401002/trick-an-application-into-thinking-its-stdin-is-interactive-not-a-pipe
    //TODO: One solution is: echo "command;exit"|script -q /dev/null

    if(!path.empty()) {
      auto path_escaped=path;
      size_t pos=0;
      //Based on https://www.reddit.com/r/cpp/comments/3vpjqg/a_new_platform_independent_process_library_for_c11/cxsxyb7
      while((pos=path_escaped.find('\'', pos))!=std::string::npos) {
        path_escaped.replace(pos, 1, "'\\''");
        pos+=4;
      }
      execl("/bin/sh", "sh", "-c", ("cd '"+path_escaped+"' && "+command).c_str(), NULL);
    }
    else
      execl("/bin/sh", "sh", "-c", command.c_str(), NULL);

    _exit(EXIT_FAILURE);
  }

  if(stdin_fd) close(stdin_p[0]);
  if(stdout_fd) close(stdout_p[1]);
  if(stderr_fd) close(stderr_p[1]);

  if(stdin_fd) *stdin_fd = stdin_p[1];
  if(stdout_fd) *stdout_fd = stdout_p[0];
  if(stderr_fd) *stderr_fd = stderr_p[0];

  closed=false;
  data.id=pid;
  return pid;
}

void Process::async_read() {
  if(data.id<=0)
    return;
  if(stdout_fd) {
    stdout_thread=std::thread([this](){
      char buffer[buffer_size];
      ssize_t n;
      while ((n=read(*stdout_fd, buffer, buffer_size)) > 0)
        read_stdout(buffer, static_cast<size_t>(n));
    });
  }
  if(stderr_fd) {
    stderr_thread=std::thread([this](){
      char buffer[buffer_size];
      ssize_t n;
      while ((n=read(*stderr_fd, buffer, buffer_size)) > 0)
        read_stderr(buffer, static_cast<size_t>(n));
    });
  }
}

int Process::get_exit_status() {
  if(data.id<=0)
    return -1;
  int exit_status;
  waitpid(data.id, &exit_status, 0);
  {
    std::lock_guard<std::mutex> lock(close_mutex);
    closed=true;
  }
  close_fds();

  return exit_status;
}

void Process::close_fds() {
  if(stdout_thread.joinable())
    stdout_thread.join();
  if(stderr_thread.joinable())
    stderr_thread.join();

  if(stdin_fd)
    close_stdin();
  if(stdout_fd) {
    if(data.id>0)
      close(*stdout_fd);
    stdout_fd.reset();
  }
  if(stderr_fd) {
    if(data.id>0)
      close(*stderr_fd);
    stderr_fd.reset();
  }
}

bool Process::write(const char *bytes, size_t n) {
  if(!open_stdin)
    throw std::invalid_argument("Can't write to an unopened stdin pipe. Please set open_stdin=true when constructing the process.");

  std::lock_guard<std::mutex> lock(stdin_mutex);
  if(stdin_fd) {
    if(::write(*stdin_fd, bytes, n)>=0) {
      return true;
    }
    else {
      return false;
    }
  }
  return false;
}

void Process::close_stdin() {
  std::lock_guard<std::mutex> lock(stdin_mutex);
  if(stdin_fd) {
    if(data.id>0)
      close(*stdin_fd);
    stdin_fd.reset();
  }
}

void Process::kill(bool force) {
  std::lock_guard<std::mutex> lock(close_mutex);
  if(data.id>0 && !closed) {
    if(force)
      ::kill(-data.id, SIGTERM);
    else
      ::kill(-data.id, SIGINT);
  }
}

void Process::kill(id_type id, bool force) {
  if(id<=0)
    return;
  if(force)
    ::kill(-id, SIGTERM);
  else
    ::kill(-id, SIGINT);
}
<commit_msg>Replaced C99 Variable Length Array with modern C++ alternative.<commit_after>#include "process.hpp"
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <stdexcept>

Process::Data::Data(): id(-1) {}

Process::id_type Process::open(const std::string &command, const std::string &path) {
  if(open_stdin)
    stdin_fd=std::make_unique<fd_type>();
  if(read_stdout)
    stdout_fd=std::make_unique<fd_type>();
  if(read_stderr)
    stderr_fd=std::make_unique<fd_type>();

  int stdin_p[2], stdout_p[2], stderr_p[2];

  if(stdin_fd && pipe(stdin_p)!=0) {
    close(stdin_p[0]);close(stdin_p[1]);
    return -1;
  }
  if(stdout_fd && pipe(stdout_p)!=0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    close(stdout_p[0]);close(stdout_p[1]);
    return -1;
  }
  if(stderr_fd && pipe(stderr_p)!=0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    close(stderr_p[0]);close(stderr_p[1]);
    return -1;
  }

  id_type pid = fork();

  if (pid < 0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    if(stderr_fd) {close(stderr_p[0]);close(stderr_p[1]);}
    return pid;
  }
  else if (pid == 0) {
    if(stdin_fd) dup2(stdin_p[0], 0);
    if(stdout_fd) dup2(stdout_p[1], 1);
    if(stderr_fd) dup2(stderr_p[1], 2);
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    if(stderr_fd) {close(stderr_p[0]);close(stderr_p[1]);}

    //Based on http://stackoverflow.com/a/899533/3808293
    int fd_max=sysconf(_SC_OPEN_MAX);
    for(int fd=3;fd<fd_max;fd++)
      close(fd);

    setpgid(0, 0);
    //TODO: See here on how to emulate tty for colors: http://stackoverflow.com/questions/1401002/trick-an-application-into-thinking-its-stdin-is-interactive-not-a-pipe
    //TODO: One solution is: echo "command;exit"|script -q /dev/null

    if(!path.empty()) {
      auto path_escaped=path;
      size_t pos=0;
      //Based on https://www.reddit.com/r/cpp/comments/3vpjqg/a_new_platform_independent_process_library_for_c11/cxsxyb7
      while((pos=path_escaped.find('\'', pos))!=std::string::npos) {
        path_escaped.replace(pos, 1, "'\\''");
        pos+=4;
      }
      execl("/bin/sh", "sh", "-c", ("cd '"+path_escaped+"' && "+command).c_str(), NULL);
    }
    else
      execl("/bin/sh", "sh", "-c", command.c_str(), NULL);

    _exit(EXIT_FAILURE);
  }

  if(stdin_fd) close(stdin_p[0]);
  if(stdout_fd) close(stdout_p[1]);
  if(stderr_fd) close(stderr_p[1]);

  if(stdin_fd) *stdin_fd = stdin_p[1];
  if(stdout_fd) *stdout_fd = stdout_p[0];
  if(stderr_fd) *stderr_fd = stderr_p[0];

  closed=false;
  data.id=pid;
  return pid;
}

void Process::async_read() {
  if(data.id<=0)
    return;
  if(stdout_fd) {
    stdout_thread=std::thread([this](){
      auto buffer = std::make_unique<char[]>(buffer_size);
      ssize_t n;
      while ((n=read(*stdout_fd, buffer.get(), buffer_size)) > 0)
        read_stdout(buffer.get(), static_cast<size_t>(n));
    });
  }
  if(stderr_fd) {
    stderr_thread=std::thread([this](){
      auto buffer = std::make_unique<char[]>(buffer_size);
      ssize_t n;
      while ((n=read(*stderr_fd, buffer.get(), buffer_size)) > 0)
        read_stderr(buffer.get(), static_cast<size_t>(n));
    });
  }
}

int Process::get_exit_status() {
  if(data.id<=0)
    return -1;
  int exit_status;
  waitpid(data.id, &exit_status, 0);
  {
    std::lock_guard<std::mutex> lock(close_mutex);
    closed=true;
  }
  close_fds();

  return exit_status;
}

void Process::close_fds() {
  if(stdout_thread.joinable())
    stdout_thread.join();
  if(stderr_thread.joinable())
    stderr_thread.join();

  if(stdin_fd)
    close_stdin();
  if(stdout_fd) {
    if(data.id>0)
      close(*stdout_fd);
    stdout_fd.reset();
  }
  if(stderr_fd) {
    if(data.id>0)
      close(*stderr_fd);
    stderr_fd.reset();
  }
}

bool Process::write(const char *bytes, size_t n) {
  if(!open_stdin)
    throw std::invalid_argument("Can't write to an unopened stdin pipe. Please set open_stdin=true when constructing the process.");

  std::lock_guard<std::mutex> lock(stdin_mutex);
  if(stdin_fd) {
    if(::write(*stdin_fd, bytes, n)>=0) {
      return true;
    }
    else {
      return false;
    }
  }
  return false;
}

void Process::close_stdin() {
  std::lock_guard<std::mutex> lock(stdin_mutex);
  if(stdin_fd) {
    if(data.id>0)
      close(*stdin_fd);
    stdin_fd.reset();
  }
}

void Process::kill(bool force) {
  std::lock_guard<std::mutex> lock(close_mutex);
  if(data.id>0 && !closed) {
    if(force)
      ::kill(-data.id, SIGTERM);
    else
      ::kill(-data.id, SIGINT);
  }
}

void Process::kill(id_type id, bool force) {
  if(id<=0)
    return;
  if(force)
    ::kill(-id, SIGTERM);
  else
    ::kill(-id, SIGINT);
}
<|endoftext|>


<commit_before>// ftpd is a server implementation based on the following:
// - RFC  959 (https://tools.ietf.org/html/rfc959)
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
//
// Copyright (C) 2020 Michael Theall
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#include "platform.h"

#include "log.h"

#include <dswifi9.h>
#include <fat.h>

#include <netinet/in.h>

#include <cstring>

#ifndef CLASSIC
#error "NDS must be built in classic mode"
#endif

PrintConsole g_statusConsole;
PrintConsole g_logConsole;
PrintConsole g_sessionConsole;

namespace
{
/// \brief Host address
struct in_addr s_addr = {0};
/// \brief Whether to power backlight
bool s_backlight = true;
}

bool platform::networkVisible ()
{
	switch (Wifi_AssocStatus ())
	{
	case ASSOCSTATUS_DISCONNECTED:
	case ASSOCSTATUS_CANNOTCONNECT:
		s_addr.s_addr = 0;
		Wifi_AutoConnect ();
		break;

	case ASSOCSTATUS_SEARCHING:
	case ASSOCSTATUS_AUTHENTICATING:
	case ASSOCSTATUS_ASSOCIATING:
	case ASSOCSTATUS_ACQUIRINGDHCP:
		s_addr.s_addr = 0;
		break;

	case ASSOCSTATUS_ASSOCIATED:
		if (!s_addr.s_addr)
			s_addr = Wifi_GetIPInfo (nullptr, nullptr, nullptr, nullptr);
		return true;
	}

	return false;
}

bool platform::init ()
{
	sassert (fatInitDefault (), "Failed to initialize fat");

	// turn off unused arm7 hardware
	powerOff (PM_SOUND_AMP);
	powerOn (PM_SOUND_MUTE);

	// turn off unused arm9 hardware
	powerOff (POWER_MATRIX | POWER_3D_CORE);

	videoSetMode (MODE_0_2D);
	videoSetModeSub (MODE_0_2D);

	vramSetBankA (VRAM_A_MAIN_BG);
	vramSetBankC (VRAM_C_SUB_BG);

	consoleInit (&g_statusConsole, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 0, true, true);
	g_logConsole = g_statusConsole;
	consoleInit (&g_sessionConsole, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 0, false, true);

	consoleSetWindow (&g_statusConsole, 0, 0, 32, 1);
	consoleSetWindow (&g_logConsole, 0, 1, 32, 23);
	consoleSetWindow (&g_sessionConsole, 0, 0, 32, 24);

	consoleDebugInit (DebugDevice_NOCASH);
	std::setvbuf (stderr, nullptr, _IONBF, 0);

	Wifi_InitDefault (INIT_ONLY);
	Wifi_AutoConnect ();

	return true;
}

bool platform::loop ()
{
	scanKeys ();

	// check if the user wants to exit
	auto const kDown = keysDown ();
	if (kDown & KEY_START)
		return false;

	// check if the user wants to toggle the backlight
	if (kDown & KEY_SELECT)
	{
		s_backlight = !s_backlight;
		(s_backlight ? powerOn : powerOff) (POWER_LCD);
	}

	return true;
}

void platform::render ()
{
	swiWaitForVBlank ();
}

void platform::exit ()
{
	powerOn (POWER_LCD);
}
<commit_msg>Fix nds flickering<commit_after>// ftpd is a server implementation based on the following:
// - RFC  959 (https://tools.ietf.org/html/rfc959)
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
//
// Copyright (C) 2020 Michael Theall
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#include "platform.h"

#include "log.h"

#include <dswifi9.h>
#include <fat.h>

#include <netinet/in.h>

#include <cstring>

#ifndef CLASSIC
#error "NDS must be built in classic mode"
#endif

PrintConsole g_statusConsole;
PrintConsole g_logConsole;
PrintConsole g_sessionConsole;

namespace
{
/// \brief Host address
struct in_addr s_addr = {0};
/// \brief Which side of double-buffer we're on
bool s_backBuffer = false;
/// \brief Whether to power backlight
bool s_backlight = true;
}

bool platform::networkVisible ()
{
	switch (Wifi_AssocStatus ())
	{
	case ASSOCSTATUS_DISCONNECTED:
	case ASSOCSTATUS_CANNOTCONNECT:
		s_addr.s_addr = 0;
		Wifi_AutoConnect ();
		break;

	case ASSOCSTATUS_SEARCHING:
	case ASSOCSTATUS_AUTHENTICATING:
	case ASSOCSTATUS_ASSOCIATING:
	case ASSOCSTATUS_ACQUIRINGDHCP:
		s_addr.s_addr = 0;
		break;

	case ASSOCSTATUS_ASSOCIATED:
		if (!s_addr.s_addr)
			s_addr = Wifi_GetIPInfo (nullptr, nullptr, nullptr, nullptr);
		return true;
	}

	return false;
}

bool platform::init ()
{
	sassert (fatInitDefault (), "Failed to initialize fat");

	// turn off unused arm7 hardware
	powerOff (PM_SOUND_AMP);
	powerOn (PM_SOUND_MUTE);

	// turn off unused arm9 hardware
	powerOff (POWER_MATRIX | POWER_3D_CORE);

	videoSetMode (MODE_0_2D);
	videoSetModeSub (MODE_0_2D);

	vramSetBankA (VRAM_A_MAIN_BG);
	vramSetBankC (VRAM_C_SUB_BG);

	consoleInit (&g_statusConsole, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 0, true, true);
	g_logConsole = g_statusConsole;
	consoleInit (&g_sessionConsole, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 0, false, true);

	consoleSetWindow (&g_statusConsole, 0, 0, 32, 1);
	consoleSetWindow (&g_logConsole, 0, 1, 32, 23);
	consoleSetWindow (&g_sessionConsole, 0, 0, 32, 24);

	consoleDebugInit (DebugDevice_NOCASH);
	std::setvbuf (stderr, nullptr, _IONBF, 0);

	Wifi_InitDefault (INIT_ONLY);
	Wifi_AutoConnect ();

	return true;
}

bool platform::loop ()
{
	scanKeys ();

	// check if the user wants to exit
	auto const kDown = keysDown ();
	if (kDown & KEY_START)
		return false;

	// check if the user wants to toggle the backlight
	if (kDown & KEY_SELECT)
	{
		s_backlight = !s_backlight;
		(s_backlight ? powerOn : powerOff) (POWER_LCD);
	}

	return true;
}

void platform::render ()
{
	// make consoles point to maps being drawn
	g_statusConsole.fontBgMap  = bgGetMapPtr (g_statusConsole.bgId);
	g_logConsole.fontBgMap     = g_statusConsole.fontBgMap;
	g_sessionConsole.fontBgMap = bgGetMapPtr (g_sessionConsole.bgId);

	swiWaitForVBlank ();

	// point maps to back buffer to draw on next frame
	bgInit (0, BgType_Text4bpp, BgSize_T_256x256, 4 + s_backBuffer, 0);
	bgInitSub (0, BgType_Text4bpp, BgSize_T_256x256, 4 + s_backBuffer, 0);

	// initialize back buffer with previous contents
	dmaCopyWordsAsynch (0, bgGetMapPtr (g_statusConsole.bgId), g_statusConsole.fontBgMap, 0x800);
	dmaCopyWordsAsynch (1, bgGetMapPtr (g_sessionConsole.bgId), g_sessionConsole.fontBgMap, 0x800);
	while ((DMA_CR (0) & DMA_BUSY) || (DMA_CR (1) & DMA_BUSY))
	{
	}

	// flip buffers
	s_backBuffer = !s_backBuffer;
}

void platform::exit ()
{
	powerOn (POWER_LCD);
}
<|endoftext|>