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

#include <iostream>
#include <templet.hpp>
#include <omp.h>

using namespace std;

const int N = 10;
int arr[N];

/*---------------------------------*/
#include <algorithm>

const int NUM_BLOCKS = 100;
const int BLOCK_SIZE = 10000;

int block_array[NUM_BLOCKS*BLOCK_SIZE];

void block_sort(int block_num)
{
	std::sort(&block_array[block_num*BLOCK_SIZE], &block_array[(block_num+1)*BLOCK_SIZE]);
}

void block_merge(int less_block_num, int more_block_num)
{
	int tmp_array[2*BLOCK_SIZE];
	std::merge(&block_array[less_block_num*BLOCK_SIZE], &block_array[(less_block_num + 1)*BLOCK_SIZE],
		&block_array[more_block_num*BLOCK_SIZE], &block_array[(more_block_num + 1)*BLOCK_SIZE],
		&tmp_array[0]);
	std::copy(&tmp_array[0], &tmp_array[BLOCK_SIZE], &block_array[less_block_num*BLOCK_SIZE]);
	std::copy(&tmp_array[BLOCK_SIZE], &tmp_array[2*BLOCK_SIZE], &block_array[more_block_num*BLOCK_SIZE]);
}

bool is_sorted()
{
	int prev = block_array[0];
	for (int i = 1; i < NUM_BLOCKS*BLOCK_SIZE; i++) {
		if (prev > block_array[i])return false;
		prev = block_array[i];
	}
	return true;
}
/*---------------------------------*/

/*$TET$*/

using namespace TEMPLET;

#pragma templet ~mes=

struct mes : message_interface{
/*$TET$mes$$data*/
	int number;
/*$TET$*/
};

#pragma templet *producer(out!mes)+

struct producer : actor_interface{
	producer(engine_interface&){
/*$TET$producer$producer*/
/*$TET$*/
	}

	mes out;

	void start(){
/*$TET$producer$start*/
		cur = 0;
		out.number = arr[cur++];
		out.send();
/*$TET$*/
	}

	void out_handler(mes&m){
/*$TET$producer$out*/
		if (cur == N) return;
		out.number = arr[cur++];
		out.send();
/*$TET$*/
	}

/*$TET$producer$$code&data*/
	int cur;
/*$TET$*/
};

#pragma templet *sorter(in?mes,out!mes)

struct sorter : actor_interface{
	sorter(engine_interface&){
/*$TET$sorter$sorter*/
		is_first=true;
		_in=0;
/*$TET$*/
	}

	void in(mes&){}
	mes out;

	void in_handler(mes&m){
/*$TET$sorter$in*/
		_in=&m;
		sort();
/*$TET$*/
	}

	void out_handler(mes&m){
/*$TET$sorter$out*/
		sort();
/*$TET$*/
	}

/*$TET$sorter$$code&data*/
	void sort(){
		if (!(access(_in) && access(out)))return;

		if(is_first){
			number=_in->number;
			is_first=false;
			_in->send();
		}
		else{
			if(number <= _in->number){
				out.number = _in->number;
				_in->send();out.send();
			}
			else{
				out.number = number;
				number = _in->number;
				_in->send();out.send();
			}
		}
	}

	int number;
	bool is_first;
	mes* _in;
/*$TET$*/
};

#pragma templet *stopper(in?mes)

struct stopper : actor_interface{
	stopper(engine_interface&){
/*$TET$stopper$stopper*/
/*$TET$*/
	}

	void in(mes&){}

	void in_handler(mes&m){
/*$TET$stopper$in*/
		number=m.number;
		stop();
/*$TET$*/
	}

/*$TET$stopper$$code&data*/
	int number;
/*$TET$*/
};

int main(int argc, char *argv[])
{
	//engine_interface e(argc, argv);
/*$TET$footer*/

	for (int i = 0; i < NUM_BLOCKS*BLOCK_SIZE; i++)	block_array[i] = rand();

	// generalized sequantial blocksort
	double time = omp_get_wtime();
	for (int i = 0; i<NUM_BLOCKS; i++) block_sort(i);
	for (int i = 1; i<NUM_BLOCKS; i++) for (int j = 0; j<i; j++) block_merge(j, i);
	time = omp_get_wtime() - time;

	if (!is_sorted())std::cout << "\nSomething went wrong!!!\n";
	else std::cout << "Sort time is " << time << " sec";
/*
	sorter** a_sorter = new sorter*[N-1];
	for(int i=0;i<N-1;i++)a_sorter[i]=new sorter(e);

	producer a_producer(e);
	stopper a_stoper(e);

	mes* prev=&a_producer.out;
	for(int i=0;i<N-1;i++){
		a_sorter[i]->in(*prev);
		prev=&(a_sorter[i]->out);
	}
	a_stoper.in(*prev);

	srand(0);
	for(int i=0;i<N;i++) arr[i]=rand();

	printf("before the sort: \n");
	for (int i = 0; i < N; i++) printf("%d\n", arr[i]);

	e.run();

	for(int i=0;i<N-1;i++){
		arr[i]=a_sorter[i]->number;
	}
	arr[N-1]=a_stoper.number;

	printf("\n\nafter the sort: \n");
	for(int i=0;i<N;i++) printf("%d\n",arr[i]);

	return 0;
	*/
/*$TET$*/
}
<commit_msg>actor structure added<commit_after>/*$TET$actor*/
/*--------------------------------------------------------------------------*/
/*  Copyright 2017 Sergei Vostokin                                          */
/*                                                                          */
/*  Licensed under the Apache License, Version 2.0 (the "License");         */
/*  you may not use this file except in compliance with the License.        */
/*  You may obtain a copy of the License at                                 */
/*                                                                          */
/*  http://www.apache.org/licenses/LICENSE-2.0                              */
/*                                                                          */
/*  Unless required by applicable law or agreed to in writing, software     */
/*  distributed under the License is distributed on an "AS IS" BASIS,       */
/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*/
/*  See the License for the specific language governing permissions and     */
/*  limitations under the License.                                          */
/*--------------------------------------------------------------------------*/

#include <iostream>
#include <templet.hpp>
#include <omp.h>
#include <algorithm>

using namespace std;

const int NUM_BLOCKS = 2;
const int BLOCK_SIZE = 50000000;

//const int NUM_BLOCKS = 1;
//const int BLOCK_SIZE = 100000000;

int block_array[NUM_BLOCKS*BLOCK_SIZE];

void block_sort(int block_num)
{
	std::sort(&block_array[block_num*BLOCK_SIZE], &block_array[(block_num+1)*BLOCK_SIZE]);
}

void block_merge(int less_block_num, int more_block_num)
{
	static int tmp_array[2*BLOCK_SIZE];
	std::merge(&block_array[less_block_num*BLOCK_SIZE], &block_array[(less_block_num + 1)*BLOCK_SIZE],
		&block_array[more_block_num*BLOCK_SIZE], &block_array[(more_block_num + 1)*BLOCK_SIZE],
		&tmp_array[0]);
	std::copy(&tmp_array[0], &tmp_array[BLOCK_SIZE], &block_array[less_block_num*BLOCK_SIZE]);
	std::copy(&tmp_array[BLOCK_SIZE], &tmp_array[2*BLOCK_SIZE], &block_array[more_block_num*BLOCK_SIZE]);
}

bool is_sorted()
{
	int prev = block_array[0];
	for (int i = 1; i < NUM_BLOCKS*BLOCK_SIZE; i++) {
		if (prev > block_array[i])return false;
		prev = block_array[i];
	}
	return true;
}

/*$TET$*/

using namespace TEMPLET;

#pragma templet ~mes=

struct mes : message_interface{
/*$TET$mes$$data*/
	int block_j;
/*$TET$*/
};

#pragma templet *sorter(out!mes)+

struct sorter : actor_interface{
	sorter(engine_interface&){
/*$TET$sorter$sorter*/
/*$TET$*/
	}

	mes out;

	void start(){
/*$TET$sorter$start*/
		block_sort(block_i);
		out.send();
/*$TET$*/
	}

	void out_handler(mes&m){
/*$TET$sorter$out*/
/*$TET$*/
	}

/*$TET$sorter$$code&data*/
	int block_i;
/*$TET$*/
};

#pragma templet *producer(in?mes,out!mes)

struct producer : actor_interface{
	producer(engine_interface&){
/*$TET$producer$producer*/
		block_j = NUM_BLOCKS;
/*$TET$*/
	}

	void in(mes&){}
	mes out;

	void in_handler(mes&m){
/*$TET$producer$in*/
		block_j--;
		if (!block_j) start();
/*$TET$*/
	}

	void out_handler(mes&m){
/*$TET$producer$out*/
		if (block_j == NUM_BLOCKS) return;
		out.block_j = ++block_j;
		out.send();
/*$TET$*/
	}

/*$TET$producer$$code&data*/
	void start() {
		block_j = 0;
		out.block_j = block_j++;
		out.send();
	}

	int block_j;
/*$TET$*/
};

#pragma templet *merger(in?mes,out!mes)

struct merger : actor_interface{
	merger(engine_interface&){
/*$TET$merger$merger*/
		is_first=true;
		_in=0;
/*$TET$*/
	}

	void in(mes&){}
	mes out;

	void in_handler(mes&m){
/*$TET$merger$in*/
		_in=&m;
		sort();
/*$TET$*/
	}

	void out_handler(mes&m){
/*$TET$merger$out*/
		sort();
/*$TET$*/
	}

/*$TET$merger$$code&data*/
	void sort(){
		if (!(access(_in) && access(out)))return;

		if(is_first){
			is_first=false;
			_in->send();
		}
		else{
			block_merge(_in->block_j,block_i);
			out.block_j = _in->block_j;
			_in->send();out.send();
		}
	}

	int  block_i;
	bool is_first;
	mes* _in;
/*$TET$*/
};

#pragma templet *stopper(in?mes)

struct stopper : actor_interface{
	stopper(engine_interface&){
/*$TET$stopper$stopper*/
/*$TET$*/
	}

	void in(mes&){}

	void in_handler(mes&m){
/*$TET$stopper$in*/
		stop();
/*$TET$*/
	}

/*$TET$stopper$$code&data*/
/*$TET$*/
};

int main(int argc, char *argv[])
{
	engine_interface e(argc, argv);
/*$TET$footer*/

	//for (int i = 0; i < NUM_BLOCKS*BLOCK_SIZE; i++)	block_array[i] = rand();

	//////////////// generalized sequantial blocksort /////////////
	double time = omp_get_wtime();
//#pragma omp parallel for
	//for (int i = 0; i<NUM_BLOCKS; i++) block_sort(i);
	//for (int i = 1; i<NUM_BLOCKS; i++) for (int j = 0; j<i; j++) block_merge(j, i);
	//time = omp_get_wtime() - time;

	//if (!is_sorted())std::cout << "\nSomething went wrong in the sequantial blocksort!!!\n";
	//else std::cout << "Sort time is " << time << " sec";
	///////////////////////////////////////////////////////////////

	/////////////////// parallel actor blocksort //////////////////
	producer a_producer(e);
	stopper a_stoper(e);

	sorter** a_sorter = new sorter*[NUM_BLOCKS - 1];
	for (int i = 0; i < NUM_BLOCKS - 1; i++) {
		a_sorter[i] = new sorter(e);
		a_sorter[i]->block_i = i;
		a_producer.in(a_sorter[i]->out);
	}

	merger** a_merger = new merger*[NUM_BLOCKS-1];
	for(int i=0;i<NUM_BLOCKS-1;i++)a_merger[i]=new merger(e);

	mes* prev=&a_producer.out;
	for(int i=0;i<NUM_BLOCKS -1;i++){
		a_merger[i]->in(*prev);
		a_merger[i]->block_i = i;
		prev=&(a_merger[i]->out);
	}
	a_stoper.in(*prev);

	for (int i = 0; i < NUM_BLOCKS*BLOCK_SIZE; i++)	block_array[i] = rand();

	time = omp_get_wtime();
	for (int i = 0; i<NUM_BLOCKS; i++) block_sort(i); /////////////
	e.run();
	time = omp_get_wtime() - time;

	if (!is_sorted())std::cout << "\nSomething went wrong in the parallel actor blocksort!!!\n";
	else std::cout << "Sort time is " << time << " sec";

	return 0;
	///////////////////////////////////////////////////////////////

/*$TET$*/
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2015 Michael C. Miller. All right reserved.

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

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */

#if defined(ESP8266)

#include <Arduino.h>
#include <Servo.h>

#define INVALID_SERVO         255     // flag indicating an invalid servo index

const uint32_t c_CycleCompensation = 4;  // compensation us to trim adjust for digitalWrite delays

struct ServoInfo  {
    uint8_t pin : 6;             // a pin number from 0 to 63
    uint8_t isActive : 1;        // true if this channel is enabled, pin not pulsed if false
};

struct ServoState {
    ServoInfo info;
    volatile uint16_t usPulse;
};

#if !defined (SERVO_EXCLUDE_TIMER0)
ServoTimer0 s_servoTimer0;
#endif

#if !defined (SERVO_EXCLUDE_TIMER1)
ServoTimer1 s_servoTimer1;
#endif

static ServoState s_servos[MAX_SERVOS];     // static array of servo structures

static uint8_t s_servoCount = 0;            // the total number of attached s_servos

// inconvenience macros
#define SERVO_INDEX_TO_TIMER(servoIndex) ((ServoTimerSequence)(servoIndex / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO_INDEX(timerId, channel)  ((timerId * SERVOS_PER_TIMER) + channel)     // macro to access servo index by timer and channel

//------------------------------------------------------------------------------
// Interrupt handler template method that takes a class that implements
// a standard set of methods for the timer abstraction
//------------------------------------------------------------------------------
template <class T> void Servo_Handler(T* timer)
{
    noInterrupts();

    uint8_t servoIndex;

    // clear interrupt
    timer->ResetInterrupt();

    if (timer->isEndOfCycle()) {
        timer->StartCycle();
    }
    else {
        servoIndex = SERVO_INDEX(timer->timerId(), timer->getCurrentChannel());
        if (servoIndex < s_servoCount && s_servos[servoIndex].info.isActive) {
            // pulse this channel low if activated
            digitalWrite(s_servos[servoIndex].info.pin, LOW);
        }
        timer->nextChannel();
    }

    servoIndex = SERVO_INDEX(timer->timerId(), timer->getCurrentChannel());

    if (servoIndex < s_servoCount && timer->getCurrentChannel() < SERVOS_PER_TIMER) {
        timer->SetPulseCompare(timer->usToTicks(s_servos[servoIndex].usPulse) - c_CycleCompensation);

        if (s_servos[servoIndex].info.isActive) {  // check if activated
            digitalWrite(s_servos[servoIndex].info.pin, HIGH); // its an active channel so pulse it high
        }
    }
    else {
        // finished all channels so wait for the refresh period to expire before starting over
        // allow a few ticks to ensure the next match is not missed
        uint32_t refreshCompare = timer->usToTicks(REFRESH_INTERVAL);
        if ((timer->GetCycleCount() + c_CycleCompensation * 2) < refreshCompare) {
            timer->SetCycleCompare(refreshCompare - c_CycleCompensation);
        }
        else {
            // at least REFRESH_INTERVAL has elapsed
            timer->SetCycleCompare(timer->GetCycleCount() + c_CycleCompensation * 2);
        }

        timer->setEndOfCycle();
    }

    interrupts();
}

static void initISR(ServoTimerSequence timerId)
{
#if !defined (SERVO_EXCLUDE_TIMER0)
    if (timerId == ServoTimerSequence_Timer0)
        s_servoTimer0.InitInterrupt([]() {Servo_Handler<ServoTimer0>(&s_servoTimer0); });
#endif
#if !defined (SERVO_EXCLUDE_TIMER1)
    if (timerId == ServoTimerSequence_Timer1)
        s_servoTimer1.InitInterrupt([]() {Servo_Handler<ServoTimer1>(&s_servoTimer1); });
#endif
}

static void finISR(ServoTimerSequence timerId)
{
#if !defined (SERVO_EXCLUDE_TIMER0)
    if (timerId == ServoTimerSequence_Timer0)
        s_servoTimer0.StopInterrupt();
#endif
#if !defined (SERVO_EXCLUDE_TIMER1)
    if (timerId == ServoTimerSequence_Timer1)
        s_servoTimer1.StopInterrupt();
#endif
}

// returns true if any servo is active on this timer
static boolean isTimerActive(ServoTimerSequence timerId)
{
    for (uint8_t channel = 0; channel < SERVOS_PER_TIMER; channel++) {
        if (s_servos[SERVO_INDEX(timerId, channel)].info.isActive) {
            return true;
        }
    }
    return false;
}

//-------------------------------------------------------------------
// Servo class methods

Servo::Servo()
{
    if (s_servoCount < MAX_SERVOS) {
        // assign a servo index to this instance
        _servoIndex = s_servoCount++;
        // store default values
        s_servos[_servoIndex].usPulse = DEFAULT_PULSE_WIDTH;
    }
    else {
        _servoIndex = INVALID_SERVO;  // too many servos
    }
}

uint8_t Servo::attach(int pin)
{
    return attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}

uint8_t Servo::attach(int pin, int minUs, int maxUs)
{
    ServoTimerSequence timerId;

    Serial.print("_servoIndex ");
    Serial.println(_servoIndex);

    if (_servoIndex < MAX_SERVOS) {
        pinMode(pin, OUTPUT);       // set servo pin to output
        digitalWrite(pin, LOW);
        s_servos[_servoIndex].info.pin = pin;

        // keep the min and max within 200-3000 us, these are extreme
        // ranges and should support extreme servos while maintaining
        // reasonable ranges
        _maxUs = max(250, min(3000, maxUs));
        _minUs = max(200, min(_maxUs, minUs));

        // initialize the timerId if it has not already been initialized
        timerId = SERVO_INDEX_TO_TIMER(_servoIndex);
        if (!isTimerActive(timerId)) {
            initISR(timerId);
        }
        s_servos[_servoIndex].info.isActive = true;  // this must be set after the check for isTimerActive
    }
    return _servoIndex;
}

void Servo::detach()
{
    ServoTimerSequence timerId;

    s_servos[_servoIndex].info.isActive = false;
    timerId = SERVO_INDEX_TO_TIMER(_servoIndex);
    if (!isTimerActive(timerId)) {
        finISR(timerId);
    }
}

void Servo::write(int value)
{
    // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
    if (value < MIN_PULSE_WIDTH) {
        // assumed to be 0-180 degrees servo
        value = max(0, min(180, value));
        value = map(value, 0, 180, _minUs, _maxUs);
    }
    writeMicroseconds(value);
}

void Servo::writeMicroseconds(int value)
{
    // ensure channel is valid
    if ((_servoIndex < MAX_SERVOS)) {
        // ensure pulse width is valid
        value = max(_minUs, min(_maxUs, value));

        s_servos[_servoIndex].usPulse = value;
    }
}

int Servo::read() // return the value as degrees
{
    return map(readMicroseconds(), _minUs, _maxUs, 0, 180);
}

int Servo::readMicroseconds()
{
    unsigned int pulsewidth;
    if (_servoIndex != INVALID_SERVO) {
        pulsewidth = s_servos[_servoIndex].usPulse;
    }
    else {
        pulsewidth = 0;
    }

    return pulsewidth;
}

bool Servo::attached()
{
    return s_servos[_servoIndex].info.isActive;
}

#endif

<commit_msg>Remove unneeded Serial output<commit_after>/*
  Copyright (c) 2015 Michael C. Miller. All right reserved.

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

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */

#if defined(ESP8266)

#include <Arduino.h>
#include <Servo.h>

#define INVALID_SERVO         255     // flag indicating an invalid servo index

const uint32_t c_CycleCompensation = 4;  // compensation us to trim adjust for digitalWrite delays

struct ServoInfo  {
    uint8_t pin : 6;             // a pin number from 0 to 63
    uint8_t isActive : 1;        // true if this channel is enabled, pin not pulsed if false
};

struct ServoState {
    ServoInfo info;
    volatile uint16_t usPulse;
};

#if !defined (SERVO_EXCLUDE_TIMER0)
ServoTimer0 s_servoTimer0;
#endif

#if !defined (SERVO_EXCLUDE_TIMER1)
ServoTimer1 s_servoTimer1;
#endif

static ServoState s_servos[MAX_SERVOS];     // static array of servo structures

static uint8_t s_servoCount = 0;            // the total number of attached s_servos

// inconvenience macros
#define SERVO_INDEX_TO_TIMER(servoIndex) ((ServoTimerSequence)(servoIndex / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO_INDEX(timerId, channel)  ((timerId * SERVOS_PER_TIMER) + channel)     // macro to access servo index by timer and channel

//------------------------------------------------------------------------------
// Interrupt handler template method that takes a class that implements
// a standard set of methods for the timer abstraction
//------------------------------------------------------------------------------
template <class T> void Servo_Handler(T* timer)
{
    noInterrupts();

    uint8_t servoIndex;

    // clear interrupt
    timer->ResetInterrupt();

    if (timer->isEndOfCycle()) {
        timer->StartCycle();
    }
    else {
        servoIndex = SERVO_INDEX(timer->timerId(), timer->getCurrentChannel());
        if (servoIndex < s_servoCount && s_servos[servoIndex].info.isActive) {
            // pulse this channel low if activated
            digitalWrite(s_servos[servoIndex].info.pin, LOW);
        }
        timer->nextChannel();
    }

    servoIndex = SERVO_INDEX(timer->timerId(), timer->getCurrentChannel());

    if (servoIndex < s_servoCount && timer->getCurrentChannel() < SERVOS_PER_TIMER) {
        timer->SetPulseCompare(timer->usToTicks(s_servos[servoIndex].usPulse) - c_CycleCompensation);

        if (s_servos[servoIndex].info.isActive) {  // check if activated
            digitalWrite(s_servos[servoIndex].info.pin, HIGH); // its an active channel so pulse it high
        }
    }
    else {
        // finished all channels so wait for the refresh period to expire before starting over
        // allow a few ticks to ensure the next match is not missed
        uint32_t refreshCompare = timer->usToTicks(REFRESH_INTERVAL);
        if ((timer->GetCycleCount() + c_CycleCompensation * 2) < refreshCompare) {
            timer->SetCycleCompare(refreshCompare - c_CycleCompensation);
        }
        else {
            // at least REFRESH_INTERVAL has elapsed
            timer->SetCycleCompare(timer->GetCycleCount() + c_CycleCompensation * 2);
        }

        timer->setEndOfCycle();
    }

    interrupts();
}

static void initISR(ServoTimerSequence timerId)
{
#if !defined (SERVO_EXCLUDE_TIMER0)
    if (timerId == ServoTimerSequence_Timer0)
        s_servoTimer0.InitInterrupt([]() {Servo_Handler<ServoTimer0>(&s_servoTimer0); });
#endif
#if !defined (SERVO_EXCLUDE_TIMER1)
    if (timerId == ServoTimerSequence_Timer1)
        s_servoTimer1.InitInterrupt([]() {Servo_Handler<ServoTimer1>(&s_servoTimer1); });
#endif
}

static void finISR(ServoTimerSequence timerId)
{
#if !defined (SERVO_EXCLUDE_TIMER0)
    if (timerId == ServoTimerSequence_Timer0)
        s_servoTimer0.StopInterrupt();
#endif
#if !defined (SERVO_EXCLUDE_TIMER1)
    if (timerId == ServoTimerSequence_Timer1)
        s_servoTimer1.StopInterrupt();
#endif
}

// returns true if any servo is active on this timer
static boolean isTimerActive(ServoTimerSequence timerId)
{
    for (uint8_t channel = 0; channel < SERVOS_PER_TIMER; channel++) {
        if (s_servos[SERVO_INDEX(timerId, channel)].info.isActive) {
            return true;
        }
    }
    return false;
}

//-------------------------------------------------------------------
// Servo class methods

Servo::Servo()
{
    if (s_servoCount < MAX_SERVOS) {
        // assign a servo index to this instance
        _servoIndex = s_servoCount++;
        // store default values
        s_servos[_servoIndex].usPulse = DEFAULT_PULSE_WIDTH;
    }
    else {
        _servoIndex = INVALID_SERVO;  // too many servos
    }
}

uint8_t Servo::attach(int pin)
{
    return attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}

uint8_t Servo::attach(int pin, int minUs, int maxUs)
{
    ServoTimerSequence timerId;

    if (_servoIndex < MAX_SERVOS) {
        pinMode(pin, OUTPUT);       // set servo pin to output
        digitalWrite(pin, LOW);
        s_servos[_servoIndex].info.pin = pin;

        // keep the min and max within 200-3000 us, these are extreme
        // ranges and should support extreme servos while maintaining
        // reasonable ranges
        _maxUs = max(250, min(3000, maxUs));
        _minUs = max(200, min(_maxUs, minUs));

        // initialize the timerId if it has not already been initialized
        timerId = SERVO_INDEX_TO_TIMER(_servoIndex);
        if (!isTimerActive(timerId)) {
            initISR(timerId);
        }
        s_servos[_servoIndex].info.isActive = true;  // this must be set after the check for isTimerActive
    }
    return _servoIndex;
}

void Servo::detach()
{
    ServoTimerSequence timerId;

    s_servos[_servoIndex].info.isActive = false;
    timerId = SERVO_INDEX_TO_TIMER(_servoIndex);
    if (!isTimerActive(timerId)) {
        finISR(timerId);
    }
}

void Servo::write(int value)
{
    // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
    if (value < MIN_PULSE_WIDTH) {
        // assumed to be 0-180 degrees servo
        value = max(0, min(180, value));
        value = map(value, 0, 180, _minUs, _maxUs);
    }
    writeMicroseconds(value);
}

void Servo::writeMicroseconds(int value)
{
    // ensure channel is valid
    if ((_servoIndex < MAX_SERVOS)) {
        // ensure pulse width is valid
        value = max(_minUs, min(_maxUs, value));

        s_servos[_servoIndex].usPulse = value;
    }
}

int Servo::read() // return the value as degrees
{
    return map(readMicroseconds(), _minUs, _maxUs, 0, 180);
}

int Servo::readMicroseconds()
{
    unsigned int pulsewidth;
    if (_servoIndex != INVALID_SERVO) {
        pulsewidth = s_servos[_servoIndex].usPulse;
    }
    else {
        pulsewidth = 0;
    }

    return pulsewidth;
}

bool Servo::attached()
{
    return s_servos[_servoIndex].info.isActive;
}

#endif

<|endoftext|>


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

#ifndef _IMP_OP_HXX
#define _IMP_OP_HXX

#ifndef _GEN_HXX //autogen
#include <tools/gen.hxx>
#endif

#ifndef SC_XIROOT_HXX
#include "xiroot.hxx"
#endif
#ifndef SC_XISTREAM_HXX
#include "xistream.hxx"
#endif
#ifndef SC_XISTYLE_HXX
#include "xistyle.hxx"
#endif
#ifndef _FLTTYPES_HXX
#include "flttypes.hxx"
#endif
#ifndef _NAMEBUFF_HXX
#include "namebuff.hxx"
#endif
#ifndef _ROOT_HXX
#include "root.hxx"
#endif
#ifndef _OTLNBUFF_HXX
#include "otlnbuff.hxx"
#endif
#ifndef _COLROWST_HXX
#include "colrowst.hxx"
#endif
#ifndef _EXCDEFS_HXX
#include "excdefs.hxx"
#endif

class SfxItemSet;
class SvStream;

class ScFormulaCell;
class SdrObject;
class ScDocument;
class ScToken;
class ScToken2;
class _ScRangeListTabs;

class XF_Buffer;
class ValueFormBuffer;
class ExcelToSc;

class ImportTyp
{
protected:
    CharSet             eQuellChar;     // Quell-Zeichensatz
    ScDocument*         pD;             // Dokument

public:
                        ImportTyp( ScDocument*, CharSet eSrc );
    virtual             ~ImportTyp();

    virtual FltError    Read( void );
};

class SvInPlaceObjectRef;

struct ExcelChartData
{
    Rectangle               aRect;              // Ecken
    String                  aTitle, aXTitle, aYTitle, aZTitle;
    String                  aLastLabel;         // letzter SERIESTEXT-Label
    SfxItemSet*             pAttrs;             // Attribute
    ExcelChartData*         pNext;              // wer weiss schon...
    SCROW                   nRow1, nRow2;
    SCCOL                   nCol1, nCol2;
    SCTAB                   nTab1, nTab2;   // Quellbereich
    SCTAB                   nBaseTab;
    UINT32                  nObjNum;

                            ExcelChartData( ScDocument*, const Point&, const Point&,
                                            const SCTAB nBaseTab );
                            ~ExcelChartData();
};

class XclImpOutlineDataBuffer
{
private:
    typedef ::std::auto_ptr< XclImpOutlineBuffer >  XclImpOutlineBufferPtr;
    typedef ::std::auto_ptr< XclImpColRowSettings > XclImpColRowSettingsPtr;

    XclImpOutlineBufferPtr      pColOutlineBuff;
    XclImpOutlineBufferPtr      pRowOutlineBuff;
    XclImpColRowSettingsPtr     pColRowBuff;
    SCTAB nTab;

public:
    XclImpOutlineDataBuffer(RootData& rRootData, SCTAB nScTab);
    ~XclImpOutlineDataBuffer();

    inline XclImpColRowSettings* GetColRowBuff() const { return pColRowBuff.get(); }
    inline XclImpOutlineBuffer* GetColOutline()  const { return pColOutlineBuff.get(); }
    inline XclImpOutlineBuffer* GetRowOutline()  const { return pRowOutlineBuff.get(); }
    void Apply(ScDocument* pD);
};

class ImportExcel : public ImportTyp, protected XclImpRoot
{
private:
    ExcelChartData*         pChart;             // aktuelle Chart-Daten
    ExcelChartData*         pUsedChartFirst;    // benutzte Chart-Daten, erster
    ExcelChartData*         pUsedChartLast;     // benutzte Chart-Daten, letzter

protected:
    static const double     fExcToTwips;        // Umrechnung 1/256 Zeichen -> Twips

    RootData*               pExcRoot;

    XclImpStream            maStrm;             // input stream
    XclImpStream&           aIn;                // input stream

    NameBuffer*             pExtNameBuff;       // ... externe Namen (Ind.-Basis=1)
    ExcelToSc*              pFormConv;          // Formel-Konverter

    XclImpOutlineBuffer*    pColOutlineBuff;
    XclImpOutlineBuffer*    pRowOutlineBuff;
    XclImpColRowSettings*   pColRowBuff;        // Col/Row-Einstellungen 1 Tabelle

    typedef ScfDelList< XclImpOutlineDataBuffer > XclImpOutlineListBuffer;
    XclImpOutlineListBuffer* pOutlineListBuffer;

    UINT16                  nIxfeIndex;         // merkt sich Angabe im IXFE-Record
    UINT16                  nLastXF;            // letzter XF in Formula-Record
    SCTAB                   nBdshtTab;          // Counter fuer Boundsheet
    ScFormulaCell*          pLastFormCell;      // fuer String-Records

    BOOL                    bTabTruncated;      // wenn Bereichsueberschreitung zum
                                                //  Abschneiden von Zellen fuehrt

    // Record-Funktionen
    void                    Dimensions( void );             // 0x00
    void                    Window1();
    void                    Blank25( void );                // 0x01
    void                    Integer( void );                // 0x02
    void                    Number25( void );               // 0x03
    void                    Boolerr25( void );              // 0x05
    void                    Formula25( void );              // 0x06     -> excform.cxx
    void                    RecString( void );              // 0x07, 0x0207
    void                    Row25( void );                  // 0x08
    void                    Bof2( void );                   // 0x09
    void                    Eof( void );                    // 0x0A
    void                    DocProtect( void );             // 0x12
    void                    Protect( void );                // 0x12 Sheet Protection
    BOOL                    Password( void );               // 0x13
    void                    Externsheet( void );            // 0x17
    void                    Note( void );                   // 0x1C
    void                    Columndefault( void );          // 0x20
    void                    Array25( void );                // 0x21
    void                    Rec1904( void );                // 0x22
    void                    Externname25( void );           // 0x23
    void                    Colwidth( void );               // 0x24
    void                    Defrowheight2( void );          // 0x25
//      void                Window1( void );                // 0x3D
    void                    Codepage( void );               // 0x42
    void                    Ixfe( void );                   // 0x44
    void                    DefColWidth( void );            // 0x55
    void                    Builtinfmtcnt( void );          // 0x56
    void                    Obj( void );                    // 0x5D
    void                    Colinfo( void );                // 0x7D
    void                    Rk( void );                     // 0x7E
    void                    Wsbool( void );                 // 0x81
    void                    Boundsheet( void );             // 0x85
    void                    Country( void );                // 0x8C
    void                    Hideobj( void );                // 0x8D
    void                    Bundleheader( void );           // 0x8F
    void                    Standardwidth( void );          // 0x99
    void                    Shrfmla( void );                // 0xBC
    void                    Mulrk( void );                  // 0xBD
    void                    Mulblank( void );               // 0xBE
    void                    Rstring( void );                // 0xD6
    void                    Olesize( void );                // 0xDE
    void                    ReadUsesElfs();                 // 0x0160
    void                    Blank34( void );                // 0x0201
    void                    Number34( void );               // 0x0203
    void                    Label( void );                  // 0x0204
    void                    Boolerr34( void );              // 0x0205
    void                    Formula3( void );               // 0x0206       -> excform.cxx
                                                            // 0x0207 -> 0x07
    void                    Row34( void );                  // 0x0208
    void                    Bof3( void );                   // 0x0209
    void                    Array34( void );                // 0x0221
    void                    Externname34( void );           // 0x0223
    void                    Defrowheight345( void );        // 0x0225
    void                    TableOp( void );                // 0x0236
    //void                  Rk( void );                     // 0x027E -> 0x7E
    void                    Formula4( void );               // 0x0406       -> excform.cxx
    void                    Bof4( void );                   // 0x0409
    void                    Bof5( void );                   // 0x0809
    // ---------------------------------------------------------------
    void                    SetLineStyle( SfxItemSet&, short, short, short );
    void                    SetFillStyle( SfxItemSet&, short, short, short );
    SdrObject*              LineObj( SfxItemSet&, const Point&, const Point& );
    SdrObject*              RectObj( SfxItemSet&, const Point&, const Point& );
    SdrObject*              BeginChartObj( SfxItemSet&, const Point&, const Point& );
    void                    EndChartObj( void );
    void                    ChartSelection( void );
    void                    ChartSeriesText( void );
    void                    ChartObjectLink( void );
    void                    ChartAi( void );

    // ---------------------------------------------------------------
    void                    Formula( const XclAddress& rXclPos,
                                UINT16 nXF, UINT16 nFormLen, double &rCurVal,
                                BYTE nFlag, BOOL bShrFmla );
                                            //      -> excform.cxx

    void                    EndSheet( void );
    void                    NeueTabelle( void );
    const ScTokenArray*     ErrorToFormula( BYTE bErrOrVal, BYTE nError,
                                double& rVal );

    virtual void            EndAllChartObjects( void );     // -> excobj.cxx

    virtual void            AdjustRowHeight();
    virtual void            PostDocLoad( void );

public:
                            ImportExcel( XclImpRootData& rImpData );

    virtual                 ~ImportExcel( void );

    virtual FltError        Read( void );
};

#endif

<commit_msg>INTEGRATION: CWS dr46 (1.35.22); FILE MERGED 2006/02/24 17:45:46 dr 1.35.22.2: #i10000# import of conditional formatting broken 2006/02/16 12:57:13 dr 1.35.22.1: new file dumper, remove unused member mrBookStrm from root data<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: imp_op.hxx,v $
 *
 *  $Revision: 1.36 $
 *
 *  last change: $Author: obo $ $Date: 2006-03-22 12:07:34 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _IMP_OP_HXX
#define _IMP_OP_HXX

#ifndef _GEN_HXX //autogen
#include <tools/gen.hxx>
#endif

#ifndef SC_XIROOT_HXX
#include "xiroot.hxx"
#endif
#ifndef SC_XISTREAM_HXX
#include "xistream.hxx"
#endif
#ifndef SC_XISTYLE_HXX
#include "xistyle.hxx"
#endif
#ifndef _FLTTYPES_HXX
#include "flttypes.hxx"
#endif
#ifndef _NAMEBUFF_HXX
#include "namebuff.hxx"
#endif
#ifndef _ROOT_HXX
#include "root.hxx"
#endif
#ifndef _OTLNBUFF_HXX
#include "otlnbuff.hxx"
#endif
#ifndef _COLROWST_HXX
#include "colrowst.hxx"
#endif
#ifndef _EXCDEFS_HXX
#include "excdefs.hxx"
#endif

class SfxItemSet;
class SvStream;

class ScFormulaCell;
class SdrObject;
class ScDocument;
class ScToken;
class ScToken2;
class _ScRangeListTabs;

class XF_Buffer;
class ValueFormBuffer;
class ExcelToSc;

class ImportTyp
{
protected:
    CharSet             eQuellChar;     // Quell-Zeichensatz
    ScDocument*         pD;             // Dokument

public:
                        ImportTyp( ScDocument*, CharSet eSrc );
    virtual             ~ImportTyp();

    virtual FltError    Read( void );
};

class SvInPlaceObjectRef;

struct ExcelChartData
{
    Rectangle               aRect;              // Ecken
    String                  aTitle, aXTitle, aYTitle, aZTitle;
    String                  aLastLabel;         // letzter SERIESTEXT-Label
    SfxItemSet*             pAttrs;             // Attribute
    ExcelChartData*         pNext;              // wer weiss schon...
    SCROW                   nRow1, nRow2;
    SCCOL                   nCol1, nCol2;
    SCTAB                   nTab1, nTab2;   // Quellbereich
    SCTAB                   nBaseTab;
    UINT32                  nObjNum;

                            ExcelChartData( ScDocument*, const Point&, const Point&,
                                            const SCTAB nBaseTab );
                            ~ExcelChartData();
};

class XclImpOutlineDataBuffer
{
private:
    typedef ::std::auto_ptr< XclImpOutlineBuffer >  XclImpOutlineBufferPtr;
    typedef ::std::auto_ptr< XclImpColRowSettings > XclImpColRowSettingsPtr;

    XclImpOutlineBufferPtr      pColOutlineBuff;
    XclImpOutlineBufferPtr      pRowOutlineBuff;
    XclImpColRowSettingsPtr     pColRowBuff;
    SCTAB nTab;

public:
    XclImpOutlineDataBuffer(RootData& rRootData, SCTAB nScTab);
    ~XclImpOutlineDataBuffer();

    inline XclImpColRowSettings* GetColRowBuff() const { return pColRowBuff.get(); }
    inline XclImpOutlineBuffer* GetColOutline()  const { return pColOutlineBuff.get(); }
    inline XclImpOutlineBuffer* GetRowOutline()  const { return pRowOutlineBuff.get(); }
    void Apply(ScDocument* pD);
};

class ImportExcel : public ImportTyp, protected XclImpRoot
{
private:
    ExcelChartData*         pChart;             // aktuelle Chart-Daten
    ExcelChartData*         pUsedChartFirst;    // benutzte Chart-Daten, erster
    ExcelChartData*         pUsedChartLast;     // benutzte Chart-Daten, letzter

protected:
    static const double     fExcToTwips;        // Umrechnung 1/256 Zeichen -> Twips

    RootData*               pExcRoot;

    XclImpStream            maStrm;             // input stream
    XclImpStream&           aIn;                // input stream

    NameBuffer*             pExtNameBuff;       // ... externe Namen (Ind.-Basis=1)
    ExcelToSc*              pFormConv;          // Formel-Konverter

    XclImpOutlineBuffer*    pColOutlineBuff;
    XclImpOutlineBuffer*    pRowOutlineBuff;
    XclImpColRowSettings*   pColRowBuff;        // Col/Row-Einstellungen 1 Tabelle

    typedef ScfDelList< XclImpOutlineDataBuffer > XclImpOutlineListBuffer;
    XclImpOutlineListBuffer* pOutlineListBuffer;

    UINT16                  nIxfeIndex;         // merkt sich Angabe im IXFE-Record
    UINT16                  nLastXF;            // letzter XF in Formula-Record
    SCTAB                   nBdshtTab;          // Counter fuer Boundsheet
    ScFormulaCell*          pLastFormCell;      // fuer String-Records

    BOOL                    bTabTruncated;      // wenn Bereichsueberschreitung zum
                                                //  Abschneiden von Zellen fuehrt

    // Record-Funktionen
    void                    Dimensions( void );             // 0x00
    void                    Window1();
    void                    Blank25( void );                // 0x01
    void                    Integer( void );                // 0x02
    void                    Number25( void );               // 0x03
    void                    Boolerr25( void );              // 0x05
    void                    Formula25( void );              // 0x06     -> excform.cxx
    void                    RecString( void );              // 0x07, 0x0207
    void                    Row25( void );                  // 0x08
    void                    Bof2( void );                   // 0x09
    void                    Eof( void );                    // 0x0A
    void                    DocProtect( void );             // 0x12
    void                    Protect( void );                // 0x12 Sheet Protection
    BOOL                    Password( void );               // 0x13
    void                    Externsheet( void );            // 0x17
    void                    Note( void );                   // 0x1C
    void                    Columndefault( void );          // 0x20
    void                    Array25( void );                // 0x21
    void                    Rec1904( void );                // 0x22
    void                    Externname25( void );           // 0x23
    void                    Colwidth( void );               // 0x24
    void                    Defrowheight2( void );          // 0x25
//      void                Window1( void );                // 0x3D
    void                    Codepage( void );               // 0x42
    void                    Ixfe( void );                   // 0x44
    void                    DefColWidth( void );            // 0x55
    void                    Builtinfmtcnt( void );          // 0x56
    void                    Obj( void );                    // 0x5D
    void                    Colinfo( void );                // 0x7D
    void                    Rk( void );                     // 0x7E
    void                    Wsbool( void );                 // 0x81
    void                    Boundsheet( void );             // 0x85
    void                    Country( void );                // 0x8C
    void                    Hideobj( void );                // 0x8D
    void                    Bundleheader( void );           // 0x8F
    void                    Standardwidth( void );          // 0x99
    void                    Shrfmla( void );                // 0xBC
    void                    Mulrk( void );                  // 0xBD
    void                    Mulblank( void );               // 0xBE
    void                    Rstring( void );                // 0xD6
    void                    Olesize( void );                // 0xDE
    void                    ReadUsesElfs();                 // 0x0160
    void                    Blank34( void );                // 0x0201
    void                    Number34( void );               // 0x0203
    void                    Label( void );                  // 0x0204
    void                    Boolerr34( void );              // 0x0205
    void                    Formula3( void );               // 0x0206       -> excform.cxx
                                                            // 0x0207 -> 0x07
    void                    Row34( void );                  // 0x0208
    void                    Bof3( void );                   // 0x0209
    void                    Array34( void );                // 0x0221
    void                    Externname34( void );           // 0x0223
    void                    Defrowheight345( void );        // 0x0225
    void                    TableOp( void );                // 0x0236
    //void                  Rk( void );                     // 0x027E -> 0x7E
    void                    Formula4( void );               // 0x0406       -> excform.cxx
    void                    Bof4( void );                   // 0x0409
    void                    Bof5( void );                   // 0x0809
    // ---------------------------------------------------------------
    void                    SetLineStyle( SfxItemSet&, short, short, short );
    void                    SetFillStyle( SfxItemSet&, short, short, short );
    SdrObject*              LineObj( SfxItemSet&, const Point&, const Point& );
    SdrObject*              RectObj( SfxItemSet&, const Point&, const Point& );
    SdrObject*              BeginChartObj( SfxItemSet&, const Point&, const Point& );
    void                    EndChartObj( void );
    void                    ChartSelection( void );
    void                    ChartSeriesText( void );
    void                    ChartObjectLink( void );
    void                    ChartAi( void );

    // ---------------------------------------------------------------
    void                    Formula( const XclAddress& rXclPos,
                                UINT16 nXF, UINT16 nFormLen, double &rCurVal,
                                BYTE nFlag, BOOL bShrFmla );
                                            //      -> excform.cxx

    virtual void            EndSheet( void );
    void                    NeueTabelle( void );
    const ScTokenArray*     ErrorToFormula( BYTE bErrOrVal, BYTE nError,
                                double& rVal );

    virtual void            EndAllChartObjects( void );     // -> excobj.cxx

    virtual void            AdjustRowHeight();
    virtual void            PostDocLoad( void );

public:
                            ImportExcel( XclImpRootData& rImpData, SvStream& rStrm );

    virtual                 ~ImportExcel( void );

    virtual FltError        Read( void );
};

#endif

<|endoftext|>


<commit_before>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "kmmimeparttree.h"

#include "kmreaderwin.h"
#include "partNode.h"
#include "kmmsgpart.h"
#include "kmkernel.h"
#include "objecttreeparser.h"
using KMail::ObjectTreeParser;

#include <kdebug.h>
#include <klocale.h>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <kiconloader.h>

#include <qheader.h>
#include <qpopupmenu.h>

KMMimePartTree::KMMimePartTree( KMReaderWin* readerWin,
                                QWidget* parent,
                                const char* name )
    : KListView(  parent, name ),
      mReaderWin( readerWin )
{
    addColumn( i18n("Description") );
    addColumn( i18n("Type") );
    addColumn( i18n("Encoding") );
    addColumn( i18n("Size") );
    setColumnAlignment( 3, Qt::AlignRight );

    restoreLayoutIfPresent();
    connect( this, SIGNAL( clicked( QListViewItem* ) ),
             this, SLOT( itemClicked( QListViewItem* ) ) );
    connect( this, SIGNAL( contextMenuRequested( QListViewItem*,
                                                 const QPoint&, int ) ),
             this, SLOT( itemRightClicked( QListViewItem*, const QPoint& ) ) );
    setSelectionMode( QListView::Extended );
    setRootIsDecorated( false );
    setAllColumnsShowFocus( true );
    setShowToolTips( true );
    setSorting(-1);
}

static const char configGroup[] = "MimePartTree";

KMMimePartTree::~KMMimePartTree() {
  saveLayout( KMKernel::config(), configGroup );
}

void KMMimePartTree::restoreLayoutIfPresent() {
  // first column: soaks up the rest of the space:
  setColumnWidthMode( 0, Manual );
  header()->setStretchEnabled( true, 0 );
  // rest of the columns:
  if ( KMKernel::config()->hasGroup( configGroup ) ) {
    // there is a saved layout. use it...
    restoreLayout( KMKernel::config(), configGroup );
    // and disable Maximum mode:
    for ( int i = 1 ; i < 4 ; ++i )
      setColumnWidthMode( i, Manual );
  } else {
    // columns grow with their contents:
    for ( int i = 1 ; i < 4 ; ++i )
      setColumnWidthMode( i, Maximum );
  }
}

void KMMimePartTree::itemClicked( QListViewItem* item )
{
    KMMimePartTreeItem* i = dynamic_cast<KMMimePartTreeItem*>( item );
    if ( 0 == i ) {
        kdDebug(5006) << "Item was not a KMMimePartTreeItem!" << endl;
    }
    else {
        kdDebug(5006) << "\n**\n** KMMimePartTree::itemClicked() **\n**" << endl;
        if( mReaderWin->mRootNode == i->node() )
          mReaderWin->update( true ); // Force update
        else {
          ObjectTreeParser otp( mReaderWin, 0, true );
	  otp.parseObjectTree( i->node() );
	}
    }
}

void KMMimePartTree::itemRightClicked( QListViewItem* item,
                                       const QPoint& point )
{
    mCurrentContextMenuItem = dynamic_cast<KMMimePartTreeItem*>( item );
    if ( 0 == mCurrentContextMenuItem ) {
        kdDebug(5006) << "Item was not a KMMimePartTreeItem!" << endl;
    }
    else {
        kdDebug(5006) << "\n**\n** KMMimePartTree::itemRightClicked() **\n**" << endl;
/*
        if( mReaderWin->mRootNode == i->node() )
          mReaderWin->setMsg(mReaderWin->mMsg, true); // Force update
        else
          mReaderWin->parseObjectTree( i->node(), true );
//        mReaderWin->parseObjectTree( mCurrentContextMenuItem->node(), true );
*/
        QPopupMenu* popup = new QPopupMenu;
        popup->insertItem( i18n( "Save &As..." ), this, SLOT( slotSaveAs() ) );
        popup->insertItem( i18n( "Save as &Encoded..." ), this,
                           SLOT( slotSaveAsEncoded() ) );
        popup->insertItem( i18n( "Save All Attachments..." ), this,
                           SLOT( slotSaveAll() ) );
        popup->exec( point );
        delete popup;
        //mReaderWin->parseObjectTree( mCurrentContextMenuItem->node(), true );
        mCurrentContextMenuItem = 0;
    }
}

void KMMimePartTree::slotSaveAs()
{
    QPtrList<QListViewItem> selected = selectedItems();

    Q_ASSERT( !selected.isEmpty() );
    if ( selected.isEmpty() )
        return;
    if ( selected.count() == 1 )
        saveOneFile( selected.first(), false );
    else
        saveMultipleFiles( selected, false );
}

void KMMimePartTree::slotSaveAsEncoded()
{
    QPtrList<QListViewItem> selected = selectedItems();

    Q_ASSERT( !selected.isEmpty() );
    if ( selected.isEmpty() )
        return;
    if ( selected.count() == 1 )
        saveOneFile( selected.first(), true );
    else
        saveMultipleFiles( selected, true );
}

void KMMimePartTree::slotSaveAll()
{
    if( childCount() == 0)
        return;

    for ( QListViewItemIterator lit( firstChild() ); lit.current();  ++lit ) {
        KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( lit.current() );

        //Check if it has the Content-Disposition... filename: header
        //to make sure it's an actual attachment
        if( item->node()->msgPart().fileName().isNull() )
            continue;

        items.append( item.current() );
    }

    saveMultipleFiles( items, false );
}

void KMMimePartTree::saveOneFile( QListViewItem* item, bool encoded )
{
    QString s = item->text(0);
    if( s.startsWith( "file: " ) )
        s = s.mid(6).stripWhiteSpace();
    else
        s = s.stripWhiteSpace();
    QString filename = KFileDialog::getSaveFileName( s,
                                                     QString::null,
                                                     this, QString::null );
    if( !filename.isEmpty() ) {
        if( QFile::exists( filename ) ) {
            if( KMessageBox::warningYesNo( this,
                                           i18n( "A file with this name already exists. Do you want to overwrite it?" ),
                                           i18n( "KMail Warning" ) ) ==
                KMessageBox::No )
                return;
        }
        saveItem( static_cast<KMMimePartTreeItem *>(item), filename, encoded );
    }
}

void KMMimePartTree::saveMultipleFiles( const QPtrList<QListViewItem>& selected, bool encoded )
{
    QPtrListIterator<QListViewItem> it( selected );
    // Let the user choose a *directory*.
    // This is why this method is totally different from saveOneFile
    KFileDialog fdlg( QString::null, QString::null, this, 0, TRUE );
    fdlg.setMode( KFile::Directory );
    if (!fdlg.exec()) return;
    QString dir = fdlg.selectedURL().path();

    while ( it.current() ) {
        KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( it.current() );
        QString s = item->text(0);
        if( s.startsWith( "file: " ) )
            s = s.mid(6).stripWhiteSpace();
        else
            s = s.stripWhiteSpace();

        QString filename = dir + "/" + s;

        if( !filename.isEmpty() ) {
            if( QFile::exists( filename ) ) {
                // Unlike slotSaveAs, we're saving multiple files, so show which one creates trouble
                if( KMessageBox::warningYesNo( this,
                                               i18n( "A file named %1 already exists. Do you want to overwrite it?" ).arg( s ),
                                               i18n( "KMail Warning" ) ) ==
                    KMessageBox::No ) {
                    ++it;
                    continue;
                }
            }
            saveItem( item, filename, encoded );
        }
        ++it;
    }
}

void KMMimePartTree::saveItem( KMMimePartTreeItem* item, const QString& filename, bool encoded )
{
    if ( item && !filename.isEmpty() ) {
        bool bSaveEncrypted = false;
        bool bEncryptedParts = item->node()->encryptionState() != KMMsgNotEncrypted;
        if( bEncryptedParts )
            if( KMessageBox::questionYesNo( this,
                                            i18n( "This part of the message is encrypted. Do you want to keep the encryption when saving?" ),
                                            i18n( "KMail Question" ) ) ==
                KMessageBox::Yes )
                bSaveEncrypted = true;

        bool bSaveWithSig = true;
        if( item->node()->signatureState() != KMMsgNotSigned )
            if( KMessageBox::questionYesNo( this,
                                            i18n( "This part of the message is signed. Do you want to keep the signature when saving?" ),
                                            i18n( "KMail Question" ) ) !=
                KMessageBox::Yes )
                bSaveWithSig = false;

        QFile file( filename );
        if( file.open( IO_WriteOnly ) ) {
            if ( encoded )
            {
                // Note:   SaveAsEncoded *always* stores the ENCRYPTED content with SIGNATURES.
                // reason: SaveAsEncoded does not decode the Message Content-Transfer-Encoding
                //         but saves the _original_ content of the message (or the message part, resp.)
                QDataStream ds( &file );
                QCString cstr( mCurrentContextMenuItem->node()->msgPart().body() );
                ds.writeRawBytes( cstr, cstr.length() );
            }
            else
            {
                QDataStream ds( &file );
                if( (bSaveEncrypted || !bEncryptedParts) && bSaveWithSig ) {
                    QByteArray cstr = item->node()->msgPart().bodyDecodedBinary();
                    ds.writeRawBytes( cstr, cstr.size() );
                } else {
                    ObjectTreeParser otp( mReaderWin, 0, true,
                                          bSaveEncrypted, bSaveWithSig );
                    otp.parseObjectTree( item->node() );
                }
            }
            file.close();
        } else
            KMessageBox::error( this, i18n( "Could not write the file" ),
                                i18n( "KMail Error" ) );
    }
}

KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTree * parent,
                                        partNode* node,
                                        const QString & description,
                                        const QString & mimetype,
                                        const QString & encoding,
                                        KIO::filesize_t size )
  : QListViewItem( parent, description,
		   QString::null, // set by setIconAndTextForType()
		   encoding,
		   KIO::convertSize( size ) ),
    mPartNode( node )
{
  if( node )
    node->setMimePartTreeItem( this );
  setIconAndTextForType( mimetype );
}

KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTreeItem * parent,
                                        partNode* node,
                                        const QString & description,
                                        const QString & mimetype,
                                        const QString & encoding,
                                        KIO::filesize_t size,
                                        bool revertOrder )
  : QListViewItem( parent, description,
		   QString::null, // set by setIconAndTextForType()
		   encoding,
		   KIO::convertSize( size ) ),
    mPartNode( node )
{
  if( revertOrder && nextSibling() ){
    QListViewItem* sib = nextSibling();
    while( sib->nextSibling() )
      sib = sib->nextSibling();
    moveItem( sib );
  }
  if( node )
    node->setMimePartTreeItem( this );
  setIconAndTextForType( mimetype );
}

void KMMimePartTreeItem::setIconAndTextForType( const QString & mime )
{
  QString mimetype = mime.lower();
  if ( mimetype.startsWith( "multipart/" ) ) {
    setText( 1, mimetype );
    setPixmap( 0, SmallIcon("folder") );
  } else if ( mimetype == "application/octet-stream" ) {
    setText( 1, i18n("Unspecified Binary Data") ); // don't show "Unknown"...
    setPixmap( 0, SmallIcon("unknown") );
  } else {
    KMimeType::Ptr mtp = KMimeType::mimeType( mimetype );
    setText( 1, mtp ? mtp->comment() : mimetype );
    setPixmap( 0, mtp ? mtp->pixmap( KIcon::Small) : SmallIcon("unknown") );
  }
}

#include "kmmimeparttree.moc"
<commit_msg>Fix as suggested by Ingo<commit_after>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "kmmimeparttree.h"

#include "kmreaderwin.h"
#include "partNode.h"
#include "kmmsgpart.h"
#include "kmkernel.h"
#include "objecttreeparser.h"
using KMail::ObjectTreeParser;

#include <kdebug.h>
#include <klocale.h>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <kiconloader.h>

#include <qheader.h>
#include <qpopupmenu.h>

KMMimePartTree::KMMimePartTree( KMReaderWin* readerWin,
                                QWidget* parent,
                                const char* name )
    : KListView(  parent, name ),
      mReaderWin( readerWin )
{
    addColumn( i18n("Description") );
    addColumn( i18n("Type") );
    addColumn( i18n("Encoding") );
    addColumn( i18n("Size") );
    setColumnAlignment( 3, Qt::AlignRight );

    restoreLayoutIfPresent();
    connect( this, SIGNAL( clicked( QListViewItem* ) ),
             this, SLOT( itemClicked( QListViewItem* ) ) );
    connect( this, SIGNAL( contextMenuRequested( QListViewItem*,
                                                 const QPoint&, int ) ),
             this, SLOT( itemRightClicked( QListViewItem*, const QPoint& ) ) );
    setSelectionMode( QListView::Extended );
    setRootIsDecorated( false );
    setAllColumnsShowFocus( true );
    setShowToolTips( true );
    setSorting(-1);
}

static const char configGroup[] = "MimePartTree";

KMMimePartTree::~KMMimePartTree() {
  saveLayout( KMKernel::config(), configGroup );
}

void KMMimePartTree::restoreLayoutIfPresent() {
  // first column: soaks up the rest of the space:
  setColumnWidthMode( 0, Manual );
  header()->setStretchEnabled( true, 0 );
  // rest of the columns:
  if ( KMKernel::config()->hasGroup( configGroup ) ) {
    // there is a saved layout. use it...
    restoreLayout( KMKernel::config(), configGroup );
    // and disable Maximum mode:
    for ( int i = 1 ; i < 4 ; ++i )
      setColumnWidthMode( i, Manual );
  } else {
    // columns grow with their contents:
    for ( int i = 1 ; i < 4 ; ++i )
      setColumnWidthMode( i, Maximum );
  }
}

void KMMimePartTree::itemClicked( QListViewItem* item )
{
    KMMimePartTreeItem* i = dynamic_cast<KMMimePartTreeItem*>( item );
    if ( 0 == i ) {
        kdDebug(5006) << "Item was not a KMMimePartTreeItem!" << endl;
    }
    else {
        kdDebug(5006) << "\n**\n** KMMimePartTree::itemClicked() **\n**" << endl;
        if( mReaderWin->mRootNode == i->node() )
          mReaderWin->update( true ); // Force update
        else {
          ObjectTreeParser otp( mReaderWin, 0, true );
	  otp.parseObjectTree( i->node() );
	}
    }
}

void KMMimePartTree::itemRightClicked( QListViewItem* item,
                                       const QPoint& point )
{
    // TODO: remove this member var?
    mCurrentContextMenuItem = dynamic_cast<KMMimePartTreeItem*>( item );
    if ( 0 == mCurrentContextMenuItem ) {
        kdDebug(5006) << "Item was not a KMMimePartTreeItem!" << endl;
    }
    else {
        kdDebug(5006) << "\n**\n** KMMimePartTree::itemRightClicked() **\n**" << endl;
/*
        if( mReaderWin->mRootNode == i->node() )
          mReaderWin->setMsg(mReaderWin->mMsg, true); // Force update
        else
          mReaderWin->parseObjectTree( i->node(), true );
//        mReaderWin->parseObjectTree( mCurrentContextMenuItem->node(), true );
*/
        QPopupMenu* popup = new QPopupMenu;
        popup->insertItem( i18n( "Save &As..." ), this, SLOT( slotSaveAs() ) );
        popup->insertItem( i18n( "Save as &Encoded..." ), this,
                           SLOT( slotSaveAsEncoded() ) );
        popup->insertItem( i18n( "Save All Attachments..." ), this,
                           SLOT( slotSaveAll() ) );
        popup->exec( point );
        delete popup;
        //mReaderWin->parseObjectTree( mCurrentContextMenuItem->node(), true );
        mCurrentContextMenuItem = 0;
    }
}

void KMMimePartTree::slotSaveAs()
{
    QPtrList<QListViewItem> selected = selectedItems();

    Q_ASSERT( !selected.isEmpty() );
    if ( selected.isEmpty() )
        return;
    if ( selected.count() == 1 )
        saveOneFile( selected.first(), false );
    else
        saveMultipleFiles( selected, false );
}

void KMMimePartTree::slotSaveAsEncoded()
{
    QPtrList<QListViewItem> selected = selectedItems();

    Q_ASSERT( !selected.isEmpty() );
    if ( selected.isEmpty() )
        return;
    if ( selected.count() == 1 )
        saveOneFile( selected.first(), true );
    else
        saveMultipleFiles( selected, true );
}

void KMMimePartTree::slotSaveAll()
{
    if( childCount() == 0)
        return;

    for ( QListViewItemIterator lit( firstChild() ); lit.current();  ++lit ) {
        KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( lit.current() );

        //Check if it has the Content-Disposition... filename: header
        //to make sure it's an actual attachment
        if( item->node()->msgPart().fileName().isNull() )
            continue;

        items.append( item.current() );
    }

    saveMultipleFiles( items, false );
}

void KMMimePartTree::saveOneFile( QListViewItem* item, bool encoded )
{
    QString s = item->text(0);
    if( s.startsWith( "file: " ) )
        s = s.mid(6).stripWhiteSpace();
    else
        s = s.stripWhiteSpace();
    QString filename = KFileDialog::getSaveFileName( s,
                                                     QString::null,
                                                     this, QString::null );
    if( !filename.isEmpty() ) {
        if( QFile::exists( filename ) ) {
            if( KMessageBox::warningYesNo( this,
                                           i18n( "A file with this name already exists. Do you want to overwrite it?" ),
                                           i18n( "KMail Warning" ) ) ==
                KMessageBox::No )
                return;
        }
        saveItem( static_cast<KMMimePartTreeItem *>(item), filename, encoded );
    }
}

void KMMimePartTree::saveMultipleFiles( const QPtrList<QListViewItem>& selected, bool encoded )
{
    QPtrListIterator<QListViewItem> it( selected );
    // Let the user choose a *directory*.
    // This is why this method is totally different from saveOneFile
    KFileDialog fdlg( QString::null, QString::null, this, 0, TRUE );
    fdlg.setMode( KFile::Directory );
    if (!fdlg.exec()) return;
    QString dir = fdlg.selectedURL().path();

    while ( it.current() ) {
        KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( it.current() );
        QString s = item->text(0);
        if( s.startsWith( "file: " ) )
            s = s.mid(6).stripWhiteSpace();
        else
            s = s.stripWhiteSpace();

        QString filename = dir + "/" + s;

        if( !filename.isEmpty() ) {
            if( QFile::exists( filename ) ) {
                // Unlike slotSaveAs, we're saving multiple files, so show which one creates trouble
                if( KMessageBox::warningYesNo( this,
                                               i18n( "A file named %1 already exists. Do you want to overwrite it?" ).arg( s ),
                                               i18n( "KMail Warning" ) ) ==
                    KMessageBox::No ) {
                    ++it;
                    continue;
                }
            }
            saveItem( item, filename, encoded );
        }
        ++it;
    }
}

void KMMimePartTree::saveItem( KMMimePartTreeItem* item, const QString& filename, bool encoded )
{
    if ( item && !filename.isEmpty() ) {
        bool bSaveEncrypted = false;
        bool bEncryptedParts = item->node()->encryptionState() != KMMsgNotEncrypted;
        if( bEncryptedParts )
            if( KMessageBox::questionYesNo( this,
                                            i18n( "This part of the message is encrypted. Do you want to keep the encryption when saving?" ),
                                            i18n( "KMail Question" ) ) ==
                KMessageBox::Yes )
                bSaveEncrypted = true;

        bool bSaveWithSig = true;
        if( item->node()->signatureState() != KMMsgNotSigned )
            if( KMessageBox::questionYesNo( this,
                                            i18n( "This part of the message is signed. Do you want to keep the signature when saving?" ),
                                            i18n( "KMail Question" ) ) !=
                KMessageBox::Yes )
                bSaveWithSig = false;

        QFile file( filename );
        if( file.open( IO_WriteOnly ) ) {
            if ( encoded )
            {
                // Note:   SaveAsEncoded *always* stores the ENCRYPTED content with SIGNATURES.
                // reason: SaveAsEncoded does not decode the Message Content-Transfer-Encoding
                //         but saves the _original_ content of the message (or the message part, resp.)
                QDataStream ds( &file );
                QCString cstr( item->node()->msgPart().body() );
                ds.writeRawBytes( cstr, cstr.length() );
            }
            else
            {
                QDataStream ds( &file );
                if( (bSaveEncrypted || !bEncryptedParts) && bSaveWithSig ) {
                    QByteArray cstr = item->node()->msgPart().bodyDecodedBinary();
                    ds.writeRawBytes( cstr, cstr.size() );
                } else {
                    ObjectTreeParser otp( mReaderWin, 0, true,
                                          bSaveEncrypted, bSaveWithSig );
                    otp.parseObjectTree( item->node() );
                }
            }
            file.close();
        } else
            KMessageBox::error( this, i18n( "Could not write the file" ),
                                i18n( "KMail Error" ) );
    }
}

KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTree * parent,
                                        partNode* node,
                                        const QString & description,
                                        const QString & mimetype,
                                        const QString & encoding,
                                        KIO::filesize_t size )
  : QListViewItem( parent, description,
		   QString::null, // set by setIconAndTextForType()
		   encoding,
		   KIO::convertSize( size ) ),
    mPartNode( node )
{
  if( node )
    node->setMimePartTreeItem( this );
  setIconAndTextForType( mimetype );
}

KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTreeItem * parent,
                                        partNode* node,
                                        const QString & description,
                                        const QString & mimetype,
                                        const QString & encoding,
                                        KIO::filesize_t size,
                                        bool revertOrder )
  : QListViewItem( parent, description,
		   QString::null, // set by setIconAndTextForType()
		   encoding,
		   KIO::convertSize( size ) ),
    mPartNode( node )
{
  if( revertOrder && nextSibling() ){
    QListViewItem* sib = nextSibling();
    while( sib->nextSibling() )
      sib = sib->nextSibling();
    moveItem( sib );
  }
  if( node )
    node->setMimePartTreeItem( this );
  setIconAndTextForType( mimetype );
}

void KMMimePartTreeItem::setIconAndTextForType( const QString & mime )
{
  QString mimetype = mime.lower();
  if ( mimetype.startsWith( "multipart/" ) ) {
    setText( 1, mimetype );
    setPixmap( 0, SmallIcon("folder") );
  } else if ( mimetype == "application/octet-stream" ) {
    setText( 1, i18n("Unspecified Binary Data") ); // don't show "Unknown"...
    setPixmap( 0, SmallIcon("unknown") );
  } else {
    KMimeType::Ptr mtp = KMimeType::mimeType( mimetype );
    setText( 1, mtp ? mtp->comment() : mimetype );
    setPixmap( 0, mtp ? mtp->pixmap( KIcon::Small) : SmallIcon("unknown") );
  }
}

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


<commit_before><commit_msg>Adds NetCDF outputs NPP, GPP, Burned soil C.<commit_after><|endoftext|>


<commit_before><commit_msg>Skip cameras without global R in viewer<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2004, Mart Kelder (mart.kde@hccnet.nl)
 *
 * 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 "keditlistboxman.h"

#include <kconfig.h>
#include <kdebug.h>

#include <qmap.h>
#include <qlistview.h>
#include <qstring.h>

KEditListBoxManager::KEditListBoxManager(	QWidget *parent, const char *name,
						bool checkAtEntering, KEditListBox::Buttons buttons )
	: KEditListBox( parent, name, checkAtEntering, buttons ),
	_config( 0 ),
	_groupName( 0 ),
	_subGroupName( 0 ),
	_prevCount( 0 )
{
	init();
}

KEditListBoxManager::KEditListBoxManager(	const QString& title, QWidget *parent,
						const char *name, bool checkAtEntering,
						KEditListBox::Buttons buttons)
	: KEditListBox( title, parent, name, checkAtEntering, buttons ),
	_config( 0 ),
	_groupName( 0 ),
	_subGroupName( 0 ),
	_prevCount( 0 )
{
	init();
}

KEditListBoxManager::KEditListBoxManager(	const QString& title,
						const KEditListBox::CustomEditor &customEditor,
						QWidget *parent, const char *name,
						bool checkAtEntering, KEditListBox::Buttons buttons )
	: KEditListBox( title, customEditor, parent, name, checkAtEntering, buttons ),
	_config( 0 ),
	_groupName( 0 ),
	_subGroupName( 0 ),
	_prevCount( 0 )
{
	init();
}

KEditListBoxManager::~KEditListBoxManager()
{
	delete _groupName;
}

void KEditListBoxManager::setConfig( KConfig* config )
{
	_config = config;
	if( _groupName )
		readNames();
}

void KEditListBoxManager::setGroupName( const QString& name )
{
	if( _groupName )
		*_groupName = name;
	else
		_groupName = new QString( name );

	if( _config )
		readNames();
}

void KEditListBoxManager::setSubGroupName( const QString& name )
{
	if( _subGroupName )
		*_subGroupName = name;
	else
		_subGroupName = new QString( name );

	if( _config && _groupName )
		readNames();
}

void KEditListBoxManager::init()
{
	connect( this, SIGNAL( changed() ), this, SLOT( slotChanged() ) );
	connect( this, SIGNAL( added( const QString& ) ), this, SLOT( slotAdded( const QString& ) ) );
	connect( this, SIGNAL( removed( const QString& ) ), this, SLOT( slotRemoved( const QString& ) ) );

	connect( this->listView(), SIGNAL( doubleClicked( const QModelIndex&) ), this, SLOT( slotActivated( const QModelIndex& ) ) );
	connect( this->listView(), SIGNAL( returnPressed( const QModelIndex& ) ), this, SLOT( slotActivated( const QModelIndex& ) ) );
}

void KEditListBoxManager::readNames()
{
	int number = 0;

	this->clear();
	while( _config->hasGroup( _groupName->arg( number ) ) )
	{
		_config->setGroup( _groupName->arg( number ) );
		this->insertItem( _config->readEntry( "name", QString() ) );
		++number;
	}

	_prevCount = this->count();
}

void KEditListBoxManager::slotChanged()
{
	/* Three thing could be hapened:
	 * 1. the text is changed;
	 * 2. the item has moved up;
	 * 3. the item has moved down.
	 */

	//_prevCount is invariant under all of these operation
	//if _prevCount is changed, is wasn't one of those operations.

	if( _prevCount != this->count() )
		return;

	 if( !_config || !_groupName )
	 	return;

	//First check if the item was moved up

	_config->setGroup( _groupName->arg( this->currentItem() ) );

        int ci = currentItem();
	if( ci > 0 && this->text( ci - 1 ) == _config->readEntry( "name", QString() ) )
		changeItem( ci - 1, ci ); //moved down
	else if( ci >= 0 && ci < this->count() - 1 &&
		 this->text( ci + 1 ) == _config->readEntry( "name", QString() ) )
		changeItem( ci, ci + 1 );  //moved up
	else if( this->currentText() != _config->readEntry( "name", QString() ) )
		changedText(); //changed
}

void KEditListBoxManager::slotAdded( const QString& name )
{
	//Update _prevCount
	_prevCount = this->count();

	if( !_config || !_groupName )
	 	return;

	int number = 0;
	while( _config->hasGroup( _groupName->arg( number ) ) )
		++number;

	_config->setGroup( _groupName->arg( number ) );
	_config->writeEntry( "name", name );

	emit setDefaults( name, number, _config );
}

void KEditListBoxManager::slotRemoved( const QString& name )
{
	//Update prevCount
	_prevCount = this->count();

	if( !_config || !_groupName )
	 	return;

	//First: search the item number.
	int number = 0;
	int subnumber = 0;
	while( true )
	{
		if( !_config->hasGroup( _groupName->arg( number ) ) )
		{
			number = -1; //not found
			break;
		}
		_config->setGroup( _groupName->arg( number ) );
		if( name == _config->readEntry( "name", QString() ) )
			break; //found

		++number; //Try next group
	}

	if( number < 0 ) //failure
		return; //do nothing

	_config->deleteGroup( _groupName->arg( number ), KConfig::NLS );
	emit elementDeleted( number );
	while( _subGroupName && _config->hasGroup( _subGroupName->arg( number ).arg( subnumber ) ) )
	{
		_config->deleteGroup( _subGroupName->arg( number ).arg( subnumber ) );
		++subnumber;
	}

	//rotate groups
	while( _config->hasGroup( _groupName->arg( number + 1 ) ) )
	{
		moveItem( number + 1, number );

		++number;
	}
}

void KEditListBoxManager::slotActivated( const QModelIndex& item )
{
	emit activated( item );
}

void KEditListBoxManager::moveItem( int src, int dest )
{
	QMap<QString, QString> *srcList = new QMap<QString, QString >;
	QMap<QString, QString>::iterator it;
	int subnumber = 0;

	*srcList = _config->entryMap( _groupName->arg( src ) );
	_config->deleteGroup( _groupName->arg( src ) );

	_config->setGroup( _groupName->arg( dest ) );
	for( it = srcList->begin(); it != srcList->end(); ++it )
		_config->writeEntry( it.key(), it.value() );

	while( _subGroupName && _config->hasGroup( _subGroupName->arg( src ).arg( subnumber ) ) )
	{
		_config->deleteGroup( _subGroupName->arg( dest ).arg( subnumber ) );
		_config->setGroup( _subGroupName->arg( dest ).arg( subnumber ) );
		for( it = srcList->begin(); it != srcList->end(); ++it )
			_config->writeEntry( it.key(), it.value() );

		++subnumber;
	}

	emit elementsSwapped( src, dest );

	delete srcList;
}

void KEditListBoxManager::changeItem( int first, int last )
{
	QMap<QString, QString> *firstList = new QMap<QString, QString >;
	QMap<QString, QString> *lastList = new QMap<QString, QString >;
	QMap<QString, QString>::iterator it;
	int subnumber = 0;

	*firstList = _config->entryMap( _groupName->arg( first ) );
	*lastList = _config->entryMap( _groupName->arg( last ) );
	_config->deleteGroup( _groupName->arg( first ) );
	_config->deleteGroup( _groupName->arg( last ) );

	_config->setGroup( _groupName->arg( last ) );
	for( it = firstList->begin(); it != firstList->end(); ++it )
		_config->writeEntry( it.key(), it.value() );

	_config->setGroup( _groupName->arg( first ) );
	for( it = lastList->begin(); it != lastList->end(); ++it )
		_config->writeEntry( it.key(), it.value() );

	while( _subGroupName && (
		_config->hasGroup( _subGroupName->arg( first ).arg( subnumber ) ) ||
		_config->hasGroup( _subGroupName->arg( last ).arg( subnumber ) ) ) )
	{
		*firstList = _config->entryMap( _subGroupName->arg( first ).arg( subnumber ) );
		*lastList = _config->entryMap( _subGroupName->arg( last ).arg( subnumber ) );
		_config->deleteGroup( _subGroupName->arg( first ).arg( subnumber ) );
		_config->deleteGroup( _subGroupName->arg( last ).arg( subnumber ) );

		_config->setGroup( _subGroupName->arg( last ).arg( subnumber ) );
		for( it = firstList->begin(); it != firstList->end(); ++it )
			_config->writeEntry( it.key(), it.value() );

		_config->setGroup( _subGroupName->arg( first ).arg( subnumber ) );
		for( it = lastList->begin(); it != lastList->end(); ++it )
			_config->writeEntry( it.key(), it.value() );

		++subnumber;
	}

	emit elementsSwapped( first, last );

	delete firstList;
	delete lastList;
}

void KEditListBoxManager::changedText()
{
	_config->setGroup( _groupName->arg( this->currentItem() ) );
	_config->writeEntry( "name", this->currentText() );
}

#include "keditlistboxman.moc"
<commit_msg>fix negative returns (CID 1356)<commit_after>/*
 * Copyright (C) 2004, Mart Kelder (mart.kde@hccnet.nl)
 *
 * 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 "keditlistboxman.h"

#include <kconfig.h>
#include <kdebug.h>

#include <qmap.h>
#include <qlistview.h>
#include <qstring.h>

KEditListBoxManager::KEditListBoxManager(	QWidget *parent, const char *name,
						bool checkAtEntering, KEditListBox::Buttons buttons )
	: KEditListBox( parent, name, checkAtEntering, buttons ),
	_config( 0 ),
	_groupName( 0 ),
	_subGroupName( 0 ),
	_prevCount( 0 )
{
	init();
}

KEditListBoxManager::KEditListBoxManager(	const QString& title, QWidget *parent,
						const char *name, bool checkAtEntering,
						KEditListBox::Buttons buttons)
	: KEditListBox( title, parent, name, checkAtEntering, buttons ),
	_config( 0 ),
	_groupName( 0 ),
	_subGroupName( 0 ),
	_prevCount( 0 )
{
	init();
}

KEditListBoxManager::KEditListBoxManager(	const QString& title,
						const KEditListBox::CustomEditor &customEditor,
						QWidget *parent, const char *name,
						bool checkAtEntering, KEditListBox::Buttons buttons )
	: KEditListBox( title, customEditor, parent, name, checkAtEntering, buttons ),
	_config( 0 ),
	_groupName( 0 ),
	_subGroupName( 0 ),
	_prevCount( 0 )
{
	init();
}

KEditListBoxManager::~KEditListBoxManager()
{
	delete _groupName;
}

void KEditListBoxManager::setConfig( KConfig* config )
{
	_config = config;
	if( _groupName )
		readNames();
}

void KEditListBoxManager::setGroupName( const QString& name )
{
	if( _groupName )
		*_groupName = name;
	else
		_groupName = new QString( name );

	if( _config )
		readNames();
}

void KEditListBoxManager::setSubGroupName( const QString& name )
{
	if( _subGroupName )
		*_subGroupName = name;
	else
		_subGroupName = new QString( name );

	if( _config && _groupName )
		readNames();
}

void KEditListBoxManager::init()
{
	connect( this, SIGNAL( changed() ), this, SLOT( slotChanged() ) );
	connect( this, SIGNAL( added( const QString& ) ), this, SLOT( slotAdded( const QString& ) ) );
	connect( this, SIGNAL( removed( const QString& ) ), this, SLOT( slotRemoved( const QString& ) ) );

	connect( this->listView(), SIGNAL( doubleClicked( const QModelIndex&) ), this, SLOT( slotActivated( const QModelIndex& ) ) );
	connect( this->listView(), SIGNAL( returnPressed( const QModelIndex& ) ), this, SLOT( slotActivated( const QModelIndex& ) ) );
}

void KEditListBoxManager::readNames()
{
	int number = 0;

	this->clear();
	while( _config->hasGroup( _groupName->arg( number ) ) )
	{
		_config->setGroup( _groupName->arg( number ) );
		this->insertItem( _config->readEntry( "name", QString() ) );
		++number;
	}

	_prevCount = this->count();
}

void KEditListBoxManager::slotChanged()
{
	/* Three thing could be hapened:
	 * 1. the text is changed;
	 * 2. the item has moved up;
	 * 3. the item has moved down.
	 */

	//_prevCount is invariant under all of these operation
	//if _prevCount is changed, is wasn't one of those operations.

	if( _prevCount != this->count() )
		return;

	 if( !_config || !_groupName )
	 	return;

	//First check if the item was moved up

        int ci = currentItem();
        if (ci >= 0)
 		_config->setGroup( _groupName->arg( ci ) );

	if( ci > 0 && this->text( ci - 1 ) == _config->readEntry( "name", QString() ) )
		changeItem( ci - 1, ci ); //moved down
	else if( ci >= 0 && ci < this->count() - 1 &&
		 this->text( ci + 1 ) == _config->readEntry( "name", QString() ) )
		changeItem( ci, ci + 1 );  //moved up
	else if( this->currentText() != _config->readEntry( "name", QString() ) )
		changedText(); //changed
}

void KEditListBoxManager::slotAdded( const QString& name )
{
	//Update _prevCount
	_prevCount = this->count();

	if( !_config || !_groupName )
	 	return;

	int number = 0;
	while( _config->hasGroup( _groupName->arg( number ) ) )
		++number;

	_config->setGroup( _groupName->arg( number ) );
	_config->writeEntry( "name", name );

	emit setDefaults( name, number, _config );
}

void KEditListBoxManager::slotRemoved( const QString& name )
{
	//Update prevCount
	_prevCount = this->count();

	if( !_config || !_groupName )
	 	return;

	//First: search the item number.
	int number = 0;
	int subnumber = 0;
	while( true )
	{
		if( !_config->hasGroup( _groupName->arg( number ) ) )
		{
			number = -1; //not found
			break;
		}
		_config->setGroup( _groupName->arg( number ) );
		if( name == _config->readEntry( "name", QString() ) )
			break; //found

		++number; //Try next group
	}

	if( number < 0 ) //failure
		return; //do nothing

	_config->deleteGroup( _groupName->arg( number ), KConfig::NLS );
	emit elementDeleted( number );
	while( _subGroupName && _config->hasGroup( _subGroupName->arg( number ).arg( subnumber ) ) )
	{
		_config->deleteGroup( _subGroupName->arg( number ).arg( subnumber ) );
		++subnumber;
	}

	//rotate groups
	while( _config->hasGroup( _groupName->arg( number + 1 ) ) )
	{
		moveItem( number + 1, number );

		++number;
	}
}

void KEditListBoxManager::slotActivated( const QModelIndex& item )
{
	emit activated( item );
}

void KEditListBoxManager::moveItem( int src, int dest )
{
	QMap<QString, QString> *srcList = new QMap<QString, QString >;
	QMap<QString, QString>::iterator it;
	int subnumber = 0;

	*srcList = _config->entryMap( _groupName->arg( src ) );
	_config->deleteGroup( _groupName->arg( src ) );

	_config->setGroup( _groupName->arg( dest ) );
	for( it = srcList->begin(); it != srcList->end(); ++it )
		_config->writeEntry( it.key(), it.value() );

	while( _subGroupName && _config->hasGroup( _subGroupName->arg( src ).arg( subnumber ) ) )
	{
		_config->deleteGroup( _subGroupName->arg( dest ).arg( subnumber ) );
		_config->setGroup( _subGroupName->arg( dest ).arg( subnumber ) );
		for( it = srcList->begin(); it != srcList->end(); ++it )
			_config->writeEntry( it.key(), it.value() );

		++subnumber;
	}

	emit elementsSwapped( src, dest );

	delete srcList;
}

void KEditListBoxManager::changeItem( int first, int last )
{
	QMap<QString, QString> *firstList = new QMap<QString, QString >;
	QMap<QString, QString> *lastList = new QMap<QString, QString >;
	QMap<QString, QString>::iterator it;
	int subnumber = 0;

	*firstList = _config->entryMap( _groupName->arg( first ) );
	*lastList = _config->entryMap( _groupName->arg( last ) );
	_config->deleteGroup( _groupName->arg( first ) );
	_config->deleteGroup( _groupName->arg( last ) );

	_config->setGroup( _groupName->arg( last ) );
	for( it = firstList->begin(); it != firstList->end(); ++it )
		_config->writeEntry( it.key(), it.value() );

	_config->setGroup( _groupName->arg( first ) );
	for( it = lastList->begin(); it != lastList->end(); ++it )
		_config->writeEntry( it.key(), it.value() );

	while( _subGroupName && (
		_config->hasGroup( _subGroupName->arg( first ).arg( subnumber ) ) ||
		_config->hasGroup( _subGroupName->arg( last ).arg( subnumber ) ) ) )
	{
		*firstList = _config->entryMap( _subGroupName->arg( first ).arg( subnumber ) );
		*lastList = _config->entryMap( _subGroupName->arg( last ).arg( subnumber ) );
		_config->deleteGroup( _subGroupName->arg( first ).arg( subnumber ) );
		_config->deleteGroup( _subGroupName->arg( last ).arg( subnumber ) );

		_config->setGroup( _subGroupName->arg( last ).arg( subnumber ) );
		for( it = firstList->begin(); it != firstList->end(); ++it )
			_config->writeEntry( it.key(), it.value() );

		_config->setGroup( _subGroupName->arg( first ).arg( subnumber ) );
		for( it = lastList->begin(); it != lastList->end(); ++it )
			_config->writeEntry( it.key(), it.value() );

		++subnumber;
	}

	emit elementsSwapped( first, last );

	delete firstList;
	delete lastList;
}

void KEditListBoxManager::changedText()
{
	_config->setGroup( _groupName->arg( this->currentItem() ) );
	_config->writeEntry( "name", this->currentText() );
}

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