<commit_before>#ifndef EPT_PARSER_CPP
#define EPT_PARSER_CPP
#include <iostream>
#include <fstream>
#include <cstring> //Used for strstr()
#include <cstdlib> //atoi()
#include <sstream> //Used for int||floatToAttr() functions

#include "eptParser.hpp"

const int SUPPORTED_VERSION=1;
////////////////////////////////////////////////
std::string eptGroup::getAttribute(const std::string& attrName)
{
	std::map<std::string, std::string>::iterator myIt=attributes.find(attrName);
	if (myIt==attributes.end()) return "";
	else return myIt->second;
}
void eptGroup::setAttribute(std::string name, std::string value)
{
	attributes[name]=value;
}
std::string eptGroup::getAttributeFromIndex(int i, std::string& attributeName)
{
	std::map<std::string, std::string>::iterator it=attributes.begin();
	for (int n=0; n<i; ++n)
	{
		++it;
	}
	if (it !=attributes.end())
	{
		attributeName=it->first;
		return it->second;
	}
	else
	{
		attributeName="";
	}
	return "";
}
int eptGroup::getTotalAttributes()
{
	return attributes.size();
}
////////////////////////////////////////////////
eptFile::eptFile()
{
	version=99;
}
eptFile::~eptFile()
{
	//clearAllData();
}
eptGroup* eptFile::getGroup(const std::string& groupName)
{
	eptGroup* returnValue=NULL;
	std::map<std::string, eptGroup*>::iterator myIt=groups.find(groupName);
	if (myIt!=groups.end()) returnValue=myIt->second;
	return returnValue;
}
void eptFile::addGroup(const std::string& groupName, eptGroup* newGroup)
{
	groups[groupName]=newGroup;
}
int eptFile::getVersion()
{
	return version;
}
///???
void eptFile::clearAllData()
{
	for (std::map<std::string, eptGroup*>::iterator groupIt=groups.begin(); groupIt !=groups.end(); ++groupIt)
	{
		delete groupIt->second;
		//groupIt=groups.erase(groupIt);
	}
}
void eptFile::setVersion(int newVersion)
{
	version=newVersion;
}
//Shows how easy it is to dump EPT stuff
bool eptFile::dumpToFile(std::string fileName, std::string collectionName)
{
	std::ofstream out;
	out.open(fileName.c_str());
	if (!out.is_open()) return false;
	//Header information
	out << "<" << collectionName << "." << version << ">\n\n";
	//Groups
	for (std::map<std::string, eptGroup*>::iterator myIt=groups.begin(); myIt!=groups.end(); ++myIt)
	{
		//Group name
		out << myIt->first << ":\n";
		//Attributes
		for (std::map<std::string, std::string>::iterator attrIt=myIt->second->attributes.begin();
		attrIt !=myIt->second->attributes.end(); ++attrIt)
		{
			out << "\t"<< attrIt->first << "=" << attrIt->second << ";\n";
		}
	}
	out.close();
	return true;
}
eptGroup* eptFile::getGroupFromIndex(int i, std::string& groupName)
{
	std::map<std::string, eptGroup*>::iterator it=groups.begin();
	for (int n=0; n<i; ++n)
	{
		++it;
	}
	if (it !=groups.end())
	{
		groupName=it->first;
		return it->second;
	}
	else
	{
		groupName="";
	}
	return NULL;
}
std::string eptFile::getAttribute(const std::string& location)
{
    unsigned int strPos = location.find(".");
    eptGroup* group = getGroup(location.substr(0, strPos));
    if (group)
    {
        return group->getAttribute(location.substr(strPos + 1, location.length() - 1));
    }
    return "";
}
////////////////////////////////////////////////
eptParser::~eptParser()
{
	clearAllData();
}
eptFile* eptParser::getFile(const std::string& fileName)
{
	eptFile* returnValue=NULL;
	std::map<std::string, eptFile*>::iterator finder=files.find(fileName);
	if (finder!=files.end()) returnValue=finder->second;
	return returnValue;
}
//Ugh, file I/O...
//Now that I see this is so huge, the E part of EPT might be a bit of a misnomer...
bool eptParser::load(const char* fileName)
{
	std::ifstream in;
	in.open(fileName);
	if (in.is_open())
	{
		//Get a new file to work with
		eptFile* newFile=new eptFile;
		std::string line;

		//First line is file header
		getline(in, line);
		//Grab the collection/file name
		unsigned int strPos=line.find(".");
		if (strPos>line.length())
		{
			std::cout << "Incorrect header format; file failed to load (couldn't find '.')\n";
			in.close();
			return false;
		}

        std::string fileInternalName = line.substr(1, strPos-1);
        //Check if the file already exists
        std::map<std::string, eptFile*>::iterator search = files.find(fileInternalName);
        if (search!=files.end())
        {
            std::cout << "WARNING: File '"<< fileName <<"'already loaded\n";
            return true;
        }
        else
        {
            //Insert file into map
            files[fileInternalName]=newFile;
        }
		//newFile=files.find(line.substr(1, strPos-1))->second;
		//Set the file's version
		unsigned int strPosB=line.find(">");
		if (strPosB>line.length())
		{
			std::cout << "Incorrect header format; file failed to load (couldn't find '>')\n";
			in.close();
			return false;
		}
		int newVersion=atoi(line.substr(strPos+1, strPosB-1).c_str());
		if (newVersion !=SUPPORTED_VERSION)
		{
			std::cout << "Version not supported (supports " << SUPPORTED_VERSION << "); file failed to load\n";
			in.close();
			return false;
		}
		newFile->setVersion(newVersion);

		eptGroup* currentGroup=NULL;
		//Go line by line and parse each line individually
		while (in.good())
		{
			getline(in, line);
			//If '//' is found, the line is a comment and should be ignored
			if (line.length()==0 || strstr(line.c_str(), "//"))
			{
				if (!in.eof()) continue;
				else break;
			}

			//Look for a new group definition
			strPos=line.find(":");
			if (strPos < line.length())
			{
				for (strPosB=0; strPosB!=line.length(); ++strPosB)
				{
					if (line[strPosB] !=' ' && line[strPosB] !='\t') break;
				}
				newFile->addGroup(line.substr(strPosB, strPos-strPosB), new eptGroup);
				currentGroup=newFile->getGroup(line.substr(strPosB, strPos-strPosB));
				continue;
			}
			//Look for an attribute definition (if there is no =, there is none)
			strPos=line.find("=");
			if (strPos>line.length()) continue;

			//Trim any spaces etc.
			for (strPosB=0; strPosB!=line.length(); ++strPosB)
			{
				if (line[strPosB] !=' ' && line[strPosB] !='\t') break;
			}
			std::string attrName=line.substr(strPosB, strPos-strPosB);
			//Find the semicolon
			strPosB=line.find(";");
			while (strPosB>line.length())
			{
				//std::cout << "Attribute value does not terminate properly (forget the ';'?). Attr Ignored...\n";
				//continue;
				line+='\n';
				std::string temp;
				temp=line;
				getline(in, line);
				temp+=line;
				line=temp;
				strPosB=line.find(";");
				if (!in.good())
				{
					std::cout << "		EPT: Forget semicolon!\n";
					return false;
				}
			}
			currentGroup->setAttribute(attrName,line.substr(strPos + 1, strPosB - (strPos + 1)));
		}
		in.close();
		return true;
	}
	else return false;
}
void eptParser::clearAllData()
{

}
void eptParser::addFile(std::string collectionName, eptFile* newFile)
{
	files[collectionName]=newFile;
}
eptGroup* eptParser::getGroup(const std::string& location)
{
	eptGroup* group=NULL;
	unsigned int strPos=location.find(".");
	eptFile* file=getFile(location.substr(0, strPos));
	if (file)
	{
		std::string newLocation=location.substr(strPos+1, location.length()-1);
		strPos=newLocation.find(".");
		group=file->getGroup(newLocation.substr(0, strPos));
	}
	return group;
}
std::string eptParser::getAttribute(const std::string& location)
{
	std::string returnString="";
	unsigned int strPos=location.find(".");
	eptFile* file=getFile(location.substr(0, strPos));
	if (file)
	{
		std::string newLocation=location.substr(strPos+1, location.length()-1);
		strPos=newLocation.find(".");
		eptGroup* group=file->getGroup(newLocation.substr(0, strPos));
		if (group)
		{
			newLocation=newLocation.substr(strPos+1, newLocation.length()-1);
			returnString=group->getAttribute(newLocation);
		}
	}
	return returnString;
}

///////////////////////////
/////Utility Functions/////
///////////////////////////
float attrToFloat(const std::string& attr)
{
	if (attr.empty()) return 0;
	return atof(attr.c_str());
}
int attrToInt(const std::string& attr)
{
	if (attr.empty()) return 0;
	return atoi(attr.c_str());
}
bool attrToBool(const std::string& attr)
{
	if (attr.empty()) return false;
	if (attr=="true") return true;
	return false;
}

std::string getArrayValue(const std::string& attr, int index)
{
    unsigned int openPos = attr.find("{");
    unsigned int closePos = attr.find("}");
    std::string inArray = attr.substr(openPos, closePos - openPos);
    //getArrayValue won't do bounds checking or see if it's a malformed
    //array because it needs to be fast. It will trust that getArrayLength was
    //checked first
    if (index == 0)
    {
        //Trim for first element
        unsigned int startPos = 0;
        unsigned int endPos = inArray.length();
        for (unsigned int i = 0; i < inArray.length(); ++i)
        {
            if (inArray[i] != ' ' && startPos==0) startPos = i;
            if (inArray[i] == '}' || (inArray[i] == ',' && inArray[i-1] != '\\'))
            {
                endPos = i;
                break;
            }
        }
        return inArray.substr(startPos, endPos - startPos);
    }
    int counter = 0;
    for (unsigned int i = 0; i < inArray.length(); ++i)
    {
        if (inArray[i] == ',' && inArray[i - 1] != '\\') //Found nondelimited comma
        {
            counter++;
            if (counter == index) //Found the desired element
            {
                unsigned int startPos = i + 1;
                unsigned int endPos = inArray.length();
                for (unsigned int n = i + 1; n < inArray.length(); n++)
                {
                    if (startPos == i + 1 && inArray[n] != ' ') startPos = n;
                    if (inArray[n]=='}' || (inArray[n] == ',' && inArray[n - 1] != '\\'))
                    {
                        endPos = n;
                        break;
                    }
                }
                return inArray.substr(startPos, endPos - i - 2);
            }
        }
    }

    //Item doesn't exist (out of bounds, malformed array, etc.)
    return "";
}
float attrToArrayFloat(const std::string& attr, int index)
{
    return attrToFloat(getArrayValue(attr, index));
}
int attrToArrayInt(const std::string& attr, int index)
{
    return attrToInt(getArrayValue(attr, index));
}
bool attrToArrayBool(const std::string& attr, int index)
{
    return attrToBool(getArrayValue(attr, index));
}
std::string attrToArrayStr(const std::string& attr, int index)
{
    std::string val = getArrayValue(attr, index);
    //Parse out comma delimiters
    for (unsigned int i = 0; i < val.length(); ++i)
    {
        if (val[i]=='\\' && val[i + 1]==',') val.erase(i, 1);
    }
    return val;
}
//Returns 0 if the attribute is not an array
int attrToArrayLength(const std::string& attr)
{
    unsigned int openPos = attr.find("{");
    unsigned int closePos = attr.find("}");
    //Not an array if no curly braces or nothing between the curly braces ( {} )
    if (openPos >= attr.length() || closePos >= attr.length() || closePos - openPos == 1)
    {
        //Malformed or not an array; return 0
        return 0;
    }
    //Length is determined by counting the number of commas
    unsigned int length = 1;
    for (unsigned int i = openPos + 1; i < closePos; i++)
    {
        if (attr[i]==',' && attr[i - 1] != '\\') length++;
    }
    return length;
}
std::string floatToAttr(float in)
{
	std::ostringstream s;
	s << in;
	return s.str();
}
std::string intToAttr(int in)
{
	std::ostringstream s;
	s << in;
	return s.str();
}

#endif
<commit_msg>Fixed strange bug in eptParser<commit_after>#ifndef EPT_PARSER_CPP
#define EPT_PARSER_CPP
#include <iostream>
#include <fstream>
#include <cstring> //Used for strstr()
#include <cstdlib> //atoi()
#include <sstream> //Used for int||floatToAttr() functions

#include "eptParser.hpp"

const int SUPPORTED_VERSION=1;
////////////////////////////////////////////////
std::string eptGroup::getAttribute(const std::string& attrName)
{
	std::map<std::string, std::string>::iterator myIt=attributes.find(attrName);
	if (myIt==attributes.end()) return "";
	else return myIt->second;
}
void eptGroup::setAttribute(std::string name, std::string value)
{
	attributes[name]=value;
}
std::string eptGroup::getAttributeFromIndex(int i, std::string& attributeName)
{
	std::map<std::string, std::string>::iterator it=attributes.begin();
	for (int n=0; n<i; ++n)
	{
		++it;
	}
	if (it !=attributes.end())
	{
		attributeName=it->first;
		return it->second;
	}
	else
	{
		attributeName="";
	}
	return "";
}
int eptGroup::getTotalAttributes()
{
	return attributes.size();
}
////////////////////////////////////////////////
eptFile::eptFile()
{
	version=99;
}
eptFile::~eptFile()
{
	//clearAllData();
}
eptGroup* eptFile::getGroup(const std::string& groupName)
{
	eptGroup* returnValue=NULL;
	std::map<std::string, eptGroup*>::iterator myIt=groups.find(groupName);
	if (myIt!=groups.end()) returnValue=myIt->second;
	return returnValue;
}
void eptFile::addGroup(const std::string& groupName, eptGroup* newGroup)
{
	groups[groupName]=newGroup;
}
int eptFile::getVersion()
{
	return version;
}
///???
void eptFile::clearAllData()
{
	for (std::map<std::string, eptGroup*>::iterator groupIt=groups.begin(); groupIt !=groups.end(); ++groupIt)
	{
		delete groupIt->second;
		//groupIt=groups.erase(groupIt);
	}
}
void eptFile::setVersion(int newVersion)
{
	version=newVersion;
}
//Shows how easy it is to dump EPT stuff
bool eptFile::dumpToFile(std::string fileName, std::string collectionName)
{
	std::ofstream out;
	out.open(fileName.c_str());
	if (!out.is_open()) return false;
	//Header information
	out << "<" << collectionName << "." << version << ">\n\n";
	//Groups
	for (std::map<std::string, eptGroup*>::iterator myIt=groups.begin(); myIt!=groups.end(); ++myIt)
	{
		//Group name
		out << myIt->first << ":\n";
		//Attributes
		for (std::map<std::string, std::string>::iterator attrIt=myIt->second->attributes.begin();
		attrIt !=myIt->second->attributes.end(); ++attrIt)
		{
			out << "\t"<< attrIt->first << "=" << attrIt->second << ";\n";
		}
	}
	out.close();
	return true;
}
eptGroup* eptFile::getGroupFromIndex(int i, std::string& groupName)
{
	std::map<std::string, eptGroup*>::iterator it=groups.begin();
	for (int n=0; n<i; ++n)
	{
		++it;
	}
	if (it !=groups.end())
	{
		groupName=it->first;
		return it->second;
	}
	else
	{
		groupName="";
	}
	return NULL;
}
std::string eptFile::getAttribute(const std::string& location)
{
    unsigned int strPos = location.find(".");
    eptGroup* group = getGroup(location.substr(0, strPos));
    if (group)
    {
        return group->getAttribute(location.substr(strPos + 1, location.length() - 1));
    }
    return "";
}
////////////////////////////////////////////////
eptParser::~eptParser()
{
	clearAllData();
}
eptFile* eptParser::getFile(const std::string& fileName)
{
	eptFile* returnValue=NULL;
	std::map<std::string, eptFile*>::iterator finder=files.find(fileName);
	if (finder!=files.end()) returnValue=finder->second;
	return returnValue;
}
//Ugh, file I/O...
//Now that I see this is so huge, the E part of EPT might be a bit of a misnomer...
bool eptParser::load(const char* fileName)
{
	std::ifstream in;
	in.open(fileName);
	if (in.is_open())
	{
		//Get a new file to work with
		eptFile* newFile=new eptFile;
		std::string line;

		//First line is file header
		getline(in, line);
		//Grab the collection/file name
		unsigned int strPos=line.find(".");
		if (strPos>line.length())
		{
			std::cout << "Incorrect header format; file failed to load (couldn't find '.')\n";
			in.close();
			return false;
		}

        std::string fileInternalName = line.substr(1, strPos-1);
        //Check if the file already exists
        std::map<std::string, eptFile*>::iterator search = files.find(fileInternalName);
        if (search!=files.end())
        {
            std::cout << "WARNING: File '"<< fileName <<"'already loaded\n";
            return true;
        }
        else
        {
            //Insert file into map
            files[fileInternalName]=newFile;
        }
		//newFile=files.find(line.substr(1, strPos-1))->second;
		//Set the file's version
		unsigned int strPosB=line.find(">");
		if (strPosB>line.length())
		{
			std::cout << "Incorrect header format; file failed to load (couldn't find '>')\n";
			in.close();
			return false;
		}
		int newVersion=atoi(line.substr(strPos+1, strPosB-1).c_str());
		if (newVersion !=SUPPORTED_VERSION)
		{
			std::cout << "Version not supported (supports " << SUPPORTED_VERSION << "); file failed to load\n";
			in.close();
			return false;
		}
		newFile->setVersion(newVersion);

		eptGroup* currentGroup=NULL;
		//Go line by line and parse each line individually
		while (in.good())
		{
			getline(in, line);
			//If '//' is found, the line is a comment and should be ignored
			if (line.length()==0 || strstr(line.c_str(), "//"))
			{
				if (!in.eof()) continue;
				else break;
			}

			//Look for a new group definition
			strPos=line.find(":");
			if (strPos < line.length())
			{
				for (strPosB=0; strPosB!=line.length(); ++strPosB)
				{
					if (line[strPosB] !=' ' && line[strPosB] !='\t') break;
				}
				newFile->addGroup(line.substr(strPosB, strPos-strPosB), new eptGroup);
				currentGroup=newFile->getGroup(line.substr(strPosB, strPos-strPosB));
				continue;
			}
			//Look for an attribute definition (if there is no =, there is none)
			strPos=line.find("=");
			if (strPos>line.length()) continue;

			//Trim any spaces etc.
			for (strPosB=0; strPosB!=line.length(); ++strPosB)
			{
				if (line[strPosB] !=' ' && line[strPosB] !='\t') break;
			}
			std::string attrName=line.substr(strPosB, strPos-strPosB);
			//Find the semicolon
			strPosB=line.find(";");
			while (strPosB>line.length())
			{
				//std::cout << "Attribute value does not terminate properly (forget the ';'?). Attr Ignored...\n";
				//continue;
				line+='\n';
				std::string temp;
				temp=line;
				getline(in, line);
				temp+=line;
				line=temp;
				strPosB=line.find(";");
				if (!in.good())
				{
					std::cout << "		EPT: Forget semicolon!\n";
					return false;
				}
			}
			currentGroup->setAttribute(attrName,line.substr(strPos + 1, strPosB - (strPos + 1)));
		}
		in.close();
		return true;
	}
	else return false;
}
void eptParser::clearAllData()
{

}
void eptParser::addFile(std::string collectionName, eptFile* newFile)
{
	files[collectionName]=newFile;
}
eptGroup* eptParser::getGroup(const std::string& location)
{
	eptGroup* group=NULL;
	unsigned int strPos=location.find(".");
	eptFile* file=getFile(location.substr(0, strPos));
	if (file)
	{
		std::string newLocation=location.substr(strPos+1, location.length()-1);
		strPos=newLocation.find(".");
		group=file->getGroup(newLocation.substr(0, strPos));
	}
	return group;
}
std::string eptParser::getAttribute(const std::string& location)
{
	std::string returnString="";
	unsigned int strPos=location.find(".");
	eptFile* file=getFile(location.substr(0, strPos));
	if (file)
	{
		std::string newLocation=location.substr(strPos+1, location.length()-1);
		strPos=newLocation.find(".");
		eptGroup* group=file->getGroup(newLocation.substr(0, strPos));
		if (group)
		{
			newLocation=newLocation.substr(strPos+1, newLocation.length()-1);
			returnString=group->getAttribute(newLocation);
		}
	}
	return returnString;
}

///////////////////////////
/////Utility Functions/////
///////////////////////////
float attrToFloat(const std::string& attr)
{
	if (attr.empty()) return 0;
	return atof(attr.c_str());
}
int attrToInt(const std::string& attr)
{
	if (attr.empty()) return 0;
	return atoi(attr.c_str());
}
bool attrToBool(const std::string& attr)
{
	if (attr.empty()) return false;
	if (attr=="true") return true;
	return false;
}

std::string getArrayValue(const std::string& attr, int index)
{
    unsigned int openPos = attr.find("{");
    unsigned int closePos = attr.find("}");
    std::string inArray = attr.substr(openPos, closePos - openPos);
    //getArrayValue won't do bounds checking or see if it's a malformed
    //array because it needs to be fast. It will trust that getArrayLength was
    //checked first
    if (index == 0)
    {
        //Trim for first element
        unsigned int startPos = 0;
        unsigned int endPos = inArray.length();
        for (unsigned int i = 0; i < inArray.length(); ++i)
        {
            if (inArray[i] != ' ' && startPos==0) startPos = i;
            if (inArray[i] == '}' || (inArray[i] == ',' && inArray[i-1] != '\\'))
            {
                endPos = i;
                break;
            }
        }
        return inArray.substr(startPos, endPos - startPos);
    }
    int counter = 0;
    for (unsigned int i = 0; i < inArray.length(); ++i)
    {
        if (inArray[i] == ',' && inArray[i - 1] != '\\') //Found nondelimited comma
        {
            counter++;
            if (counter == index) //Found the desired element
            {
                unsigned int startPos = i + 1;
                unsigned int endPos = inArray.length();
                for (unsigned int n = i + 1; n < inArray.length(); n++)
                {
                    if (startPos == i + 1 && inArray[n] != ' ') startPos = n;
                    if (inArray[n]=='}' || (inArray[n] == ',' && inArray[n - 1] != '\\'))
                    {
                        endPos = n;
                        break;
                    }
                }
                return inArray.substr(startPos, endPos - i - 2);
            }
        }
    }

    //Item doesn't exist (out of bounds, malformed array, etc.)
    return "";
}
float attrToArrayFloat(const std::string& attr, int index)
{
    return attrToFloat(getArrayValue(attr, index));
}
int attrToArrayInt(const std::string& attr, int index)
{
    return attrToInt(getArrayValue(attr, index));
}
bool attrToArrayBool(const std::string& attr, int index)
{
    return attrToBool(getArrayValue(attr, index));
}
std::string attrToArrayStr(const std::string& attr, int index)
{
    std::string val = getArrayValue(attr, index);
    //Parse out comma delimiters
    for (unsigned int i = 0; i < val.length(); ++i)
    {
        if (val[i]=='\\' && val[i + 1]==',') val.erase(i, 1);
    }
    return val;
}
//Returns 0 if the attribute is not an array
int attrToArrayLength(const std::string& attr)
{
    unsigned int openPos = attr.find("{");
    unsigned int closePos = attr.find("}");
    //Not an array if no curly braces or nothing between the curly braces ( {} )
    if (openPos >= attr.length() || closePos >= attr.length() || closePos - openPos == 1)
    {
        //Malformed or not an array; return 0
        return 0;
    }
    //Length is determined by counting the number of commas
    unsigned int length = 1;
    for (unsigned int i = openPos + 1; i < closePos; i++)
    {
        if (attr[i]==',' && attr[i - 1] != '\\') length++;
    }
    return length;
}

/*int main()
{
    std::string arr = "{2, 50}";
    std::cout << "Length: " << attrToArrayLength(arr) << "\n";
    for (int i = 0; i < attrToArrayLength(arr); ++i)
    {
        std::cout << attrToArrayInt(arr, i) << "\n";
    }
}*/
std::string floatToAttr(float in)
{
	std::ostringstream s;
	s << in;
	return s.str();
}
std::string intToAttr(int in)
{
	std::ostringstream s;
	s << in;
	return s.str();
}

#endif
<|endoftext|>


<commit_before>#ifndef PRESETEDITOR_HPP
#define PRESETEDITOR_HPP

// stdlib
#include <string>
#include <functional>

// Libslic3r
#include "libslic3r.h"
#include "ConfigBase.hpp"
#include "Config.hpp"

// GUI
#include "misc_ui.hpp"

// Wx
#include <wx/treectrl.h>
#include <wx/imaglist.h>
#include <wx/panel.h>

using namespace std::string_literals;
namespace Slic3r { namespace GUI {

class PresetEditor : public wxPanel {

public:
    /// Member function to retrieve a list of options
    /// that this preset governs. Subclasses should
    /// call their own static method.
    virtual t_config_option_keys my_options() = 0;
    static t_config_option_keys options() { return t_config_option_keys {}; }

    wxSizer* sizer() { return _sizer; };
    PresetEditor(wxWindow* parent, t_config_option_keys options = {});
    PresetEditor() : PresetEditor(nullptr, {}) {};

    bool prompt_unsaved_changes();
    void select_preset_by_name(const wxString& name, bool force = false);

    /// suppress the callback when the tree selection is changed.
    bool disable_tree_sel_changed_event {false};

    void save_preset();
    std::function<void ()> on_save_preset {};
    std::function<void ()> on_value_change {};

    config_ptr config;

    virtual wxString title() = 0;
    virtual std::string name() = 0;
protected:
    // Main sizer
    wxSizer* _sizer {nullptr};
    wxString presets;
    wxImageList* _icons {nullptr};
    wxTreeCtrl* _treectrl {nullptr};
    wxBitmapButton* _btn_save_preset {nullptr};
    wxBitmapButton* _btn_delete_preset {nullptr};
    wxChoice* _presets_choice {nullptr};
    int _iconcount {-1};

    std::vector<wxString> _pages {};

    const unsigned int left_col_width {150};
    void _update_tree();
    void load_presets();

    virtual void _build() = 0;
    virtual void _update() = 0;
    virtual void _on_preset_loaded() = 0;
    void set_tooltips() {
        this->_btn_save_preset->SetToolTip(wxString(_("Save current ")) + this->title());
        this->_btn_delete_preset->SetToolTip(_("Delete this preset."));
    }
};

class PrintEditor : public PresetEditor {
public:

    PrintEditor(wxWindow* parent, t_config_option_keys options = {});
    PrintEditor() : PrintEditor(nullptr, {}) {};

    wxString title() override { return _("Print Settings"); }
    std::string name() override { return "print"s; }

    /// Static method to retrieve list of options that this preset governs.
    static t_config_option_keys options() {
        return t_config_option_keys
        {
            "layer_height"s, "first_layer_height"s,
            "adaptive_slicing"s, "adaptive_slicing_quality"s, "match_horizontal_surfaces"s,
            "perimeters"s, "spiral_vase"s,
            "top_solid_layers"s, "bottom_solid_layers"s,
            "extra_perimeters"s, "avoid_crossing_perimeters"s, "thin_walls"s, "overhangs"s,
            "seam_position"s, "external_perimeters_first"s,
            "fill_density"s, "fill_pattern"s, "top_infill_pattern"s, "bottom_infill_pattern"s, "fill_gaps"s,
            "infill_every_layers"s, "infill_only_where_needed"s,
            "solid_infill_every_layers"s, "fill_angle"s, "solid_infill_below_area"s, ""s,
            "only_retract_when_crossing_perimeters"s, "infill_first"s,
            "max_print_speed"s, "max_volumetric_speed"s,
            "perimeter_speed"s, "small_perimeter_speed"s, "external_perimeter_speed"s, "infill_speed"s, ""s,
            "solid_infill_speed"s, "top_solid_infill_speed"s, "support_material_speed"s,
            "support_material_interface_speed"s, "bridge_speed"s, "gap_fill_speed"s,
            "travel_speed"s,
            "first_layer_speed"s,
            "perimeter_acceleration"s, "infill_acceleration"s, "bridge_acceleration"s,
            "first_layer_acceleration"s, "default_acceleration"s,
            "skirts"s, "skirt_distance"s, "skirt_height"s, "min_skirt_length"s,
            "brim_connections_width"s, "brim_width"s, "interior_brim_width"s,
            "support_material"s, "support_material_threshold"s, "support_material_max_layers"s, "support_material_enforce_layers"s,
            "raft_layers"s,
            "support_material_pattern"s, "support_material_spacing"s, "support_material_angle"s, ""s,
            "support_material_interface_layers"s, "support_material_interface_spacing"s,
            "support_material_contact_distance"s, "support_material_buildplate_only"s, "dont_support_bridges"s,
            "notes"s,
            "complete_objects"s, "extruder_clearance_radius"s, "extruder_clearance_height"s,
            "gcode_comments"s, "output_filename_format"s,
            "post_process"s,
            "perimeter_extruder"s, "infill_extruder"s, "solid_infill_extruder"s,
            "support_material_extruder"s, "support_material_interface_extruder"s,
            "ooze_prevention"s, "standby_temperature_delta"s,
            "interface_shells"s, "regions_overlap"s,
            "extrusion_width"s, "first_layer_extrusion_width"s, "perimeter_extrusion_width"s, ""s,
            "external_perimeter_extrusion_width"s, "infill_extrusion_width"s, "solid_infill_extrusion_width"s,
            "top_infill_extrusion_width"s, "support_material_extrusion_width"s,
            "support_material_interface_extrusion_width"s, "infill_overlap"s, "bridge_flow_ratio"s,
            "xy_size_compensation"s, "resolution"s, "shortcuts"s, "compatible_printers"s,
            "print_settings_id"s
        };
    }

    t_config_option_keys my_options() override { return PrintEditor::options(); }

protected:
    void _update() override;
    void _build() override;
};

class PrinterEditor : public PresetEditor {
public:
    PrinterEditor(wxWindow* parent, t_config_option_keys options = {});
    PrinterEditor() : PrinterEditor(nullptr, {}) {};

    wxString title() override { return _("Printer Settings"); }
    std::string name() override { return "printer"s; }
    static t_config_option_keys overridable_options() { return t_config_option_keys
    {
        "pressure_advance"s,
        "retract_length"s, "retract_lift"s, "retract_speed"s, "retract_restart_extra"s,
        "retract_before_travel"s, "retract_layer_change"s, "wipe"s
    }; };

    static t_config_option_keys options() {
        return t_config_option_keys
        {
            "bed_shape"s, "z_offset"s, "z_steps_per_mm"s, "has_heatbed"s,
            "gcode_flavor"s, "use_relative_e_distances"s,
            "serial_port"s, "serial_speed"s,
            "host_type"s, "print_host"s, "octoprint_apikey"s,
            "use_firmware_retraction"s, "pressure_advance"s, "vibration_limit"s,
            "use_volumetric_e"s,
            "start_gcode"s, "end_gcode"s, "before_layer_gcode"s, "layer_gcode"s, "toolchange_gcode"s, "between_objects_gcode"s,
            "nozzle_diameter"s, "extruder_offset"s, "min_layer_height"s, "max_layer_height"s,
            "retract_length"s, "retract_lift"s, "retract_speed"s, "retract_restart_extra"s, "retract_before_travel"s, "retract_layer_change"s, "wipe"s,
            "retract_length_toolchange"s, "retract_restart_extra_toolchange"s, "retract_lift_above"s, "retract_lift_below"s,
            "printer_settings_id"s,
            "printer_notes"s,
            "use_set_and_wait_bed"s, "use_set_and_wait_extruder"s
        };
    }

    t_config_option_keys my_options() override { return PrinterEditor::options(); }
protected:
    void _update() override;
    void _build() override;
    const std::string LogChannel() override {return "PrinterEditor"s;} //< Which log these messages should go to.
};

class MaterialEditor : public PresetEditor {
public:

    wxString title() override { return _("Material Settings"); }
    std::string name() override { return "material"s; }
    preset_t type() override  { return preset_t::Material; };
    int typeId() override  { return static_cast<int>(preset_t::Material); };
    MaterialEditor(wxWindow* parent, t_config_option_keys options = {});
    MaterialEditor() : MaterialEditor(nullptr, {}) {};

    static t_config_option_keys options() {
        return t_config_option_keys
        {
            "filament_colour"s, "filament_diameter"s, "filament_notes"s, "filament_max_volumetric_speed"s, "extrusion_multiplier"s, "filament_density"s, "filament_cost"s,
            "temperature"s, "first_layer_temperature"s, "bed_temperature"s, "first_layer_bed_temperature"s,
            "fan_always_on"s, "cooling"s, "compatible_printers"s,
            "min_fan_speed"s, "max_fan_speed"s, "bridge_fan_speed"s, "disable_fan_first_layers"s,
            "fan_below_layer_time"s, "slowdown_below_layer_time"s, "min_print_speed"s,
            "start_filament_gcode"s, "end_filament_gcode"s,
            "filament_settings_id"s
        };
    }

    t_config_option_keys my_options() override { return MaterialEditor::options(); }
protected:
    void _update() override;
    void _build() override;
    const std::string LogChannel() override {return "MaterialEditor"s;} //< Which log these messages should go to.
};

}} // namespace Slic3r::GUI
#endif // PRESETEDITOR_HPP
<commit_msg>Added overriding and overridable options.<commit_after>#ifndef PRESETEDITOR_HPP
#define PRESETEDITOR_HPP

// stdlib
#include <string>
#include <functional>

// Libslic3r
#include "libslic3r.h"
#include "ConfigBase.hpp"
#include "Config.hpp"

// GUI
#include "misc_ui.hpp"

// Wx
#include <wx/treectrl.h>
#include <wx/imaglist.h>
#include <wx/panel.h>

using namespace std::string_literals;
namespace Slic3r { namespace GUI {

class PresetEditor : public wxPanel {

public:
    /// Member function to retrieve a list of options
    /// that this preset governs. Subclasses should
    /// call their own static method.
    virtual t_config_option_keys my_options() = 0;
    static t_config_option_keys options() { return t_config_option_keys {}; }

    static t_config_option_keys overridable_options() { return t_config_option_keys {}; };
    static t_config_option_keys overriding_options() { return t_config_option_keys {}; };

    virtual t_config_option_keys my_overridable_options() = 0;
    virtual t_config_option_keys my_overriding_options() = 0;

    wxSizer* sizer() { return _sizer; };
    PresetEditor(wxWindow* parent, t_config_option_keys options = {});
    PresetEditor() : PresetEditor(nullptr, {}) {};

    bool prompt_unsaved_changes();
    void select_preset_by_name(const wxString& name, bool force = false);

    /// suppress the callback when the tree selection is changed.
    bool disable_tree_sel_changed_event {false};

    void save_preset();
    std::function<void ()> on_save_preset {};
    std::function<void ()> on_value_change {};

    config_ptr config;

    virtual wxString title() = 0;
    virtual std::string name() = 0;
protected:
    // Main sizer
    wxSizer* _sizer {nullptr};
    wxString presets;
    wxImageList* _icons {nullptr};
    wxTreeCtrl* _treectrl {nullptr};
    wxBitmapButton* _btn_save_preset {nullptr};
    wxBitmapButton* _btn_delete_preset {nullptr};
    wxChoice* _presets_choice {nullptr};
    int _iconcount {-1};

    std::vector<wxString> _pages {};

    const unsigned int left_col_width {150};
    void _update_tree();
    void load_presets();

    virtual void _build() = 0;
    virtual void _update() = 0;
    virtual void _on_preset_loaded() = 0;
    void set_tooltips() {
        this->_btn_save_preset->SetToolTip(wxString(_("Save current ")) + this->title());
        this->_btn_delete_preset->SetToolTip(_("Delete this preset."));
    }
};

class PrintEditor : public PresetEditor {
public:

    PrintEditor(wxWindow* parent, t_config_option_keys options = {});
    PrintEditor() : PrintEditor(nullptr, {}) {};

    wxString title() override { return _("Print Settings"); }
    std::string name() override { return "print"s; }

    t_config_option_keys my_overridable_options() override { return PresetEditor::overridable_options(); };
    static t_config_option_keys overridable_options() { return PresetEditor::overridable_options(); };

    t_config_option_keys my_overriding_options() override { return PresetEditor::overriding_options(); };
    static t_config_option_keys overriding_options() { return PresetEditor::overriding_options(); };

    /// Static method to retrieve list of options that this preset governs.
    static t_config_option_keys options() {
        return t_config_option_keys
        {
            "layer_height"s, "first_layer_height"s,
            "adaptive_slicing"s, "adaptive_slicing_quality"s, "match_horizontal_surfaces"s,
            "perimeters"s, "spiral_vase"s,
            "top_solid_layers"s, "bottom_solid_layers"s,
            "extra_perimeters"s, "avoid_crossing_perimeters"s, "thin_walls"s, "overhangs"s,
            "seam_position"s, "external_perimeters_first"s,
            "fill_density"s, "fill_pattern"s, "top_infill_pattern"s, "bottom_infill_pattern"s, "fill_gaps"s,
            "infill_every_layers"s, "infill_only_where_needed"s,
            "solid_infill_every_layers"s, "fill_angle"s, "solid_infill_below_area"s, ""s,
            "only_retract_when_crossing_perimeters"s, "infill_first"s,
            "max_print_speed"s, "max_volumetric_speed"s,
            "perimeter_speed"s, "small_perimeter_speed"s, "external_perimeter_speed"s, "infill_speed"s, ""s,
            "solid_infill_speed"s, "top_solid_infill_speed"s, "support_material_speed"s,
            "support_material_interface_speed"s, "bridge_speed"s, "gap_fill_speed"s,
            "travel_speed"s,
            "first_layer_speed"s,
            "perimeter_acceleration"s, "infill_acceleration"s, "bridge_acceleration"s,
            "first_layer_acceleration"s, "default_acceleration"s,
            "skirts"s, "skirt_distance"s, "skirt_height"s, "min_skirt_length"s,
            "brim_connections_width"s, "brim_width"s, "interior_brim_width"s,
            "support_material"s, "support_material_threshold"s, "support_material_max_layers"s, "support_material_enforce_layers"s,
            "raft_layers"s,
            "support_material_pattern"s, "support_material_spacing"s, "support_material_angle"s, ""s,
            "support_material_interface_layers"s, "support_material_interface_spacing"s,
            "support_material_contact_distance"s, "support_material_buildplate_only"s, "dont_support_bridges"s,
            "notes"s,
            "complete_objects"s, "extruder_clearance_radius"s, "extruder_clearance_height"s,
            "gcode_comments"s, "output_filename_format"s,
            "post_process"s,
            "perimeter_extruder"s, "infill_extruder"s, "solid_infill_extruder"s,
            "support_material_extruder"s, "support_material_interface_extruder"s,
            "ooze_prevention"s, "standby_temperature_delta"s,
            "interface_shells"s, "regions_overlap"s,
            "extrusion_width"s, "first_layer_extrusion_width"s, "perimeter_extrusion_width"s, ""s,
            "external_perimeter_extrusion_width"s, "infill_extrusion_width"s, "solid_infill_extrusion_width"s,
            "top_infill_extrusion_width"s, "support_material_extrusion_width"s,
            "support_material_interface_extrusion_width"s, "infill_overlap"s, "bridge_flow_ratio"s,
            "xy_size_compensation"s, "resolution"s, "shortcuts"s, "compatible_printers"s,
            "print_settings_id"s
        };
    }

    t_config_option_keys my_options() override { return PrintEditor::options(); }

protected:
    void _update() override;
    void _build() override;
};

class PrinterEditor : public PresetEditor {
public:
    PrinterEditor(wxWindow* parent, t_config_option_keys options = {});
    PrinterEditor() : PrinterEditor(nullptr, {}) {};

    wxString title() override { return _("Printer Settings"); }
    std::string name() override { return "printer"s; }
    static t_config_option_keys overridable_options() { return t_config_option_keys
    {
        "pressure_advance"s,
        "retract_length"s, "retract_lift"s, "retract_speed"s, "retract_restart_extra"s,
        "retract_before_travel"s, "retract_layer_change"s, "wipe"s
    }; };
    static t_config_option_keys overriding_options() { return PresetEditor::overriding_options(); };

    t_config_option_keys my_overridable_options() override { return PrinterEditor::overridable_options(); };
    t_config_option_keys my_overriding_options() override { return PrinterEditor::overriding_options(); };

    static t_config_option_keys options() {
        return t_config_option_keys
        {
            "bed_shape"s, "z_offset"s, "z_steps_per_mm"s, "has_heatbed"s,
            "gcode_flavor"s, "use_relative_e_distances"s,
            "serial_port"s, "serial_speed"s,
            "host_type"s, "print_host"s, "octoprint_apikey"s,
            "use_firmware_retraction"s, "pressure_advance"s, "vibration_limit"s,
            "use_volumetric_e"s,
            "start_gcode"s, "end_gcode"s, "before_layer_gcode"s, "layer_gcode"s, "toolchange_gcode"s, "between_objects_gcode"s,
            "nozzle_diameter"s, "extruder_offset"s, "min_layer_height"s, "max_layer_height"s,
            "retract_length"s, "retract_lift"s, "retract_speed"s, "retract_restart_extra"s, "retract_before_travel"s, "retract_layer_change"s, "wipe"s,
            "retract_length_toolchange"s, "retract_restart_extra_toolchange"s, "retract_lift_above"s, "retract_lift_below"s,
            "printer_settings_id"s,
            "printer_notes"s,
            "use_set_and_wait_bed"s, "use_set_and_wait_extruder"s
        };
    }

    t_config_option_keys my_options() override { return PrinterEditor::options(); }
protected:
    void _update() override;
    void _build() override;
    const std::string LogChannel() override {return "PrinterEditor"s;} //< Which log these messages should go to.
};

class MaterialEditor : public PresetEditor {
public:

    wxString title() override { return _("Material Settings"); }
    std::string name() override { return "material"s; }
    preset_t type() override  { return preset_t::Material; };
    int typeId() override  { return static_cast<int>(preset_t::Material); };
    MaterialEditor(wxWindow* parent, t_config_option_keys options = {});
    MaterialEditor() : MaterialEditor(nullptr, {}) {};

    t_config_option_keys my_overridable_options() override { return PresetEditor::overridable_options(); };
    t_config_option_keys my_overriding_options() override { return PrinterEditor::overridable_options(); };

    static t_config_option_keys overriding_options() { return PrinterEditor::overridable_options(); };
    static t_config_option_keys overridable_options() { return PresetEditor::overridable_options(); };

    static t_config_option_keys options() {
        return t_config_option_keys
        {
            "filament_colour"s, "filament_diameter"s, "filament_notes"s, "filament_max_volumetric_speed"s, "extrusion_multiplier"s, "filament_density"s, "filament_cost"s,
            "temperature"s, "first_layer_temperature"s, "bed_temperature"s, "first_layer_bed_temperature"s,
            "fan_always_on"s, "cooling"s, "compatible_printers"s,
            "min_fan_speed"s, "max_fan_speed"s, "bridge_fan_speed"s, "disable_fan_first_layers"s,
            "fan_below_layer_time"s, "slowdown_below_layer_time"s, "min_print_speed"s,
            "start_filament_gcode"s, "end_filament_gcode"s,
            "filament_settings_id"s
        };
    }

    t_config_option_keys my_options() override { return MaterialEditor::options(); }
protected:
    void _update() override;
    void _build() override;
    const std::string LogChannel() override {return "MaterialEditor"s;} //< Which log these messages should go to.
};

}} // namespace Slic3r::GUI
#endif // PRESETEDITOR_HPP
<|endoftext|>


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

#include "GafferUI/ContainerGadget.h"

#include "OpenEXR/ImathBoxAlgo.h"

#include "boost/bind.hpp"
#include "boost/bind/placeholders.hpp"

using namespace Imath;
using namespace GafferUI;

IE_CORE_DEFINERUNTIMETYPED( ContainerGadget );

ContainerGadget::ContainerGadget( const std::string &name )
	:	Gadget( name ), m_padding( Box3f( V3f( 0 ), V3f( 0 ) ) )
{
	childAddedSignal().connect( boost::bind( &ContainerGadget::childAdded, this, ::_1, ::_2 ) );
	childRemovedSignal().connect( boost::bind( &ContainerGadget::childRemoved, this, ::_1, ::_2 )  );
}

ContainerGadget::~ContainerGadget()
{
}

bool ContainerGadget::acceptsChild( const Gaffer::GraphComponent *potentialChild ) const
{
	return potentialChild->isInstanceOf( Gadget::staticTypeId() );
}

Imath::Box3f ContainerGadget::bound() const
{
	Imath::Box3f result;
	for( ChildContainer::const_iterator it=children().begin(); it!=children().end(); it++ )
	{
		// cast is safe because of the guarantees acceptsChild() gives us
		ConstGadgetPtr c = IECore::staticPointerCast<const Gadget>( *it );
		Imath::Box3f b = c->bound();
		b = Imath::transform( b, c->getTransform() );
		result.extendBy( b );
	}
	result.min += m_padding.min;
	result.max += m_padding.max;
	return result;
}

void ContainerGadget::setPadding( const Imath::Box3f &padding )
{
	if( padding == m_padding )
	{
		return;
	}
	m_padding = padding;
	renderRequestSignal()( this );
}

const Imath::Box3f &ContainerGadget::getPadding() const
{
	return m_padding;
}

void ContainerGadget::doRender( const Style *style ) const
{
	for( ChildContainer::const_iterator it=children().begin(); it!=children().end(); it++ )
	{
		// cast is safe because of the guarantees acceptsChild() gives us
		ConstGadgetPtr c = IECore::staticPointerCast<const Gadget>( *it );
		c->render( style );
	}
}

void ContainerGadget::childAdded( GraphComponent *parent, GraphComponent *child )
{
	assert( parent==this );
	static_cast<Gadget *>( child )->renderRequestSignal().connect( boost::bind( &ContainerGadget::childRenderRequest, this, ::_1 ) );
	renderRequestSignal()( this );
}

void ContainerGadget::childRemoved( GraphComponent *parent, GraphComponent *child )
{
	assert( parent==this );
	static_cast<Gadget *>( child )->renderRequestSignal().disconnect( &ContainerGadget::childRenderRequest );
	renderRequestSignal()( this );
}

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

#include "GafferUI/ContainerGadget.h"

#include "OpenEXR/ImathBoxAlgo.h"

#include "boost/bind.hpp"
#include "boost/bind/placeholders.hpp"

using namespace Imath;
using namespace GafferUI;

IE_CORE_DEFINERUNTIMETYPED( ContainerGadget );

ContainerGadget::ContainerGadget( const std::string &name )
	:	Gadget( name ), m_padding( Box3f( V3f( 0 ), V3f( 0 ) ) )
{
	childAddedSignal().connect( boost::bind( &ContainerGadget::childAdded, this, ::_1, ::_2 ) );
	childRemovedSignal().connect( boost::bind( &ContainerGadget::childRemoved, this, ::_1, ::_2 )  );
}

ContainerGadget::~ContainerGadget()
{
}

bool ContainerGadget::acceptsChild( const Gaffer::GraphComponent *potentialChild ) const
{
	return potentialChild->isInstanceOf( Gadget::staticTypeId() );
}

Imath::Box3f ContainerGadget::bound() const
{
	Imath::Box3f result;
	for( ChildContainer::const_iterator it=children().begin(); it!=children().end(); it++ )
	{
		// cast is safe because of the guarantees acceptsChild() gives us
		const Gadget *c = static_cast<const Gadget *>( it->get() );
		Imath::Box3f b = c->bound();
		b = Imath::transform( b, c->getTransform() );
		result.extendBy( b );
	}
	result.min += m_padding.min;
	result.max += m_padding.max;
	return result;
}

void ContainerGadget::setPadding( const Imath::Box3f &padding )
{
	if( padding == m_padding )
	{
		return;
	}
	m_padding = padding;
	renderRequestSignal()( this );
}

const Imath::Box3f &ContainerGadget::getPadding() const
{
	return m_padding;
}

void ContainerGadget::doRender( const Style *style ) const
{
	for( ChildContainer::const_iterator it=children().begin(); it!=children().end(); it++ )
	{
		// cast is safe because of the guarantees acceptsChild() gives us
		const Gadget *c = static_cast<const Gadget *>( it->get() );
		c->render( style );
	}
}

void ContainerGadget::childAdded( GraphComponent *parent, GraphComponent *child )
{
	assert( parent==this );
	static_cast<Gadget *>( child )->renderRequestSignal().connect( boost::bind( &ContainerGadget::childRenderRequest, this, ::_1 ) );
	renderRequestSignal()( this );
}

void ContainerGadget::childRemoved( GraphComponent *parent, GraphComponent *child )
{
	assert( parent==this );
	static_cast<Gadget *>( child )->renderRequestSignal().disconnect( &ContainerGadget::childRenderRequest );
	renderRequestSignal()( this );
}

void ContainerGadget::childRenderRequest( Gadget *child )
{
	renderRequestSignal()( this );
}
<|endoftext|>


<commit_before>/*
 * filter_ext.cc
 *
 *  Copyright (C) 2013 Diamond Light Source
 *
 *  Author: James Parkhurst
 *
 *  This code is distributed under the BSD license, a copy of which is
 *  included in the root directory of this package.
 */
#include <boost/python.hpp>
#include <boost/python/def.hpp>
#include <dials/algorithms/integration/filter.h>

namespace dials { namespace algorithms { namespace filter {
    namespace boost_python {

  using namespace boost::python;

  void export_is_zeta_valid()
  {
    def("is_zeta_valid",
      (bool(*)(vec3<double>, vec3<double>, vec3<double>, double))
      &is_zeta_valid, (
        arg("m2"), arg("s0"), arg("s1"), arg("zeta_min")));
    def("is_zeta_valid",
      (bool(*)(const CoordinateSystem&, double))
      &is_zeta_valid, (
        arg("cs"), arg("zeta_min")));
    def("is_zeta_valid",
      (bool(*)(vec3<double>, vec3<double>, const Reflection&, double))
      &is_zeta_valid, (
        arg("m2"), arg("s0"), arg("r"), arg("zeta_min")));
    def("is_zeta_valid",
      (bool(*)(const Goniometer&, const Beam&, const Reflection&, double))
      &is_zeta_valid, (
        arg("g"), arg("b"), arg("r"), arg("zeta_min")));
  }

  void export_is_xds_small_angle_valid()
  {
    def("is_xds_small_angle_valid",
      (bool(*)(vec3<double>, vec3<double>, vec3<double>, double))
      &is_xds_small_angle_valid, (
        arg("m2"), arg("s0"), arg("s1"), arg("delta_m")));
    def("is_xds_small_angle_valid",
      (bool(*)(const CoordinateSystem&, double))
      &is_xds_small_angle_valid, (
        arg("cs"), arg("delta_m")));
    def("is_xds_small_angle_valid",
      (bool(*)(vec3<double>, vec3<double>, const Reflection&, double))
      &is_xds_small_angle_valid, (
        arg("m2"), arg("s0"), arg("r"), arg("delta_m")));
    def("is_xds_small_angle_valid",
      (bool(*)(const Goniometer&, const Beam&, const Reflection&, double))
      &is_xds_small_angle_valid, (
        arg("g"), arg("b"), arg("r"), arg("delta_m")));
  }

  void export_is_xds_angle_valid()
  {
    def("is_xds_angle_valid",
      (bool(*)(vec3<double>, vec3<double>, vec3<double>, double))
      &is_xds_angle_valid, (
        arg("m2"), arg("s0"), arg("s1"), arg("delta_m")));
    def("is_xds_angle_valid",
      (bool(*)(const CoordinateSystem&, double))
      &is_xds_angle_valid, (
        arg("cs"), arg("delta_m")));
    def("is_xds_angle_valid",
      (bool(*)(vec3<double>, vec3<double>, const Reflection&, double))
      &is_xds_angle_valid, (
        arg("m2"), arg("s0"), arg("r"), arg("delta_m")));
    def("is_xds_angle_valid",
      (bool(*)(const Goniometer&, const Beam&, const Reflection&, double))
      &is_xds_angle_valid, (
        arg("g"), arg("b"), arg("r"), arg("delta_m")));
  }

  BOOST_PYTHON_MODULE(dials_algorithms_integration_ext)
  {
    export_is_zeta_valid();
    export_is_xds_small_angle_valid();
    export_is_xds_angle_valid();
  }

}}}} // namespace = dials::algorithms::filter::boost_python
<commit_msg>Fixed module name<commit_after>/*
 * filter_ext.cc
 *
 *  Copyright (C) 2013 Diamond Light Source
 *
 *  Author: James Parkhurst
 *
 *  This code is distributed under the BSD license, a copy of which is
 *  included in the root directory of this package.
 */
#include <boost/python.hpp>
#include <boost/python/def.hpp>
#include <dials/algorithms/integration/filter.h>

namespace dials { namespace algorithms { namespace filter {
    namespace boost_python {

  using namespace boost::python;

  void export_is_zeta_valid()
  {
    def("is_zeta_valid",
      (bool(*)(vec3<double>, vec3<double>, vec3<double>, double))
      &is_zeta_valid, (
        arg("m2"), arg("s0"), arg("s1"), arg("zeta_min")));
    def("is_zeta_valid",
      (bool(*)(const CoordinateSystem&, double))
      &is_zeta_valid, (
        arg("cs"), arg("zeta_min")));
    def("is_zeta_valid",
      (bool(*)(vec3<double>, vec3<double>, const Reflection&, double))
      &is_zeta_valid, (
        arg("m2"), arg("s0"), arg("r"), arg("zeta_min")));
    def("is_zeta_valid",
      (bool(*)(const Goniometer&, const Beam&, const Reflection&, double))
      &is_zeta_valid, (
        arg("g"), arg("b"), arg("r"), arg("zeta_min")));
  }

  void export_is_xds_small_angle_valid()
  {
    def("is_xds_small_angle_valid",
      (bool(*)(vec3<double>, vec3<double>, vec3<double>, double))
      &is_xds_small_angle_valid, (
        arg("m2"), arg("s0"), arg("s1"), arg("delta_m")));
    def("is_xds_small_angle_valid",
      (bool(*)(const CoordinateSystem&, double))
      &is_xds_small_angle_valid, (
        arg("cs"), arg("delta_m")));
    def("is_xds_small_angle_valid",
      (bool(*)(vec3<double>, vec3<double>, const Reflection&, double))
      &is_xds_small_angle_valid, (
        arg("m2"), arg("s0"), arg("r"), arg("delta_m")));
    def("is_xds_small_angle_valid",
      (bool(*)(const Goniometer&, const Beam&, const Reflection&, double))
      &is_xds_small_angle_valid, (
        arg("g"), arg("b"), arg("r"), arg("delta_m")));
  }

  void export_is_xds_angle_valid()
  {
    def("is_xds_angle_valid",
      (bool(*)(vec3<double>, vec3<double>, vec3<double>, double))
      &is_xds_angle_valid, (
        arg("m2"), arg("s0"), arg("s1"), arg("delta_m")));
    def("is_xds_angle_valid",
      (bool(*)(const CoordinateSystem&, double))
      &is_xds_angle_valid, (
        arg("cs"), arg("delta_m")));
    def("is_xds_angle_valid",
      (bool(*)(vec3<double>, vec3<double>, const Reflection&, double))
      &is_xds_angle_valid, (
        arg("m2"), arg("s0"), arg("r"), arg("delta_m")));
    def("is_xds_angle_valid",
      (bool(*)(const Goniometer&, const Beam&, const Reflection&, double))
      &is_xds_angle_valid, (
        arg("g"), arg("b"), arg("r"), arg("delta_m")));
  }

  BOOST_PYTHON_MODULE(dials_algorithms_integration_filter_ext)
  {
    export_is_zeta_valid();
    export_is_xds_small_angle_valid();
    export_is_xds_angle_valid();
  }

}}}} // namespace = dials::algorithms::filter::boost_python
<|endoftext|>


<commit_before>#include <cmath>
#include "search.h"
#include <iostream>
using namespace std;

/**
* Returns left bound of interval.
* Searches input string (S) for suffixes having "cmp_char" at "q_offset",
* using suffix array (SA).
*/
int binary_search_left (char cmp_char, interval_t interval, string &S, int *SA) {
	int depth = interval.depth;
	int start = interval.start;
	int end = interval.end;

	//cout << "BSEARCH_LEFT" << endl;
	if (cmp_char == S[SA[start] + depth]) {
		return start;
	}

	int middle;
	while ((end - start) > 1) {
		middle = (end + start) / 2;
		if (cmp_char <= S[SA[middle] + depth]) {
			end = middle;
		} else {
			start = middle;
		}
	}

	return end;
}

/**
* Returns right bound of interval.
* Searches input string (S) for suffixes having "cmp_char" at "q_offset",
* using suffix array (SA).
*/
int binary_search_right (char cmp_char, interval_t interval, string &S, int *SA) {
	int depth = interval.depth;
	int start = interval.start;
	int end = interval.end;

	if (cmp_char == S[SA[end] + depth]){
		return end;
	}

	//cout << "BSEARCH_RIGHT" << endl;

	int middle;
	while ((end - start) > 1) {
	  middle = (end + start) / 2;
	  /*
	  cout << "middle: " << middle << endl;
	  cout << "chr: " << cmp_char << endl;
	  cout << "depth: " << depth << endl;
	  cout << "S[SA[middle] + depth]: " << S[SA[middle] + depth] << endl;
	  */
		if (cmp_char < S[SA[middle] + depth]) {
			end = middle;
		} else {
			start = middle;
		}
	}

	return start;
}

/**
* Returns interval containing "cmp_char" if it exists, else returns not_found
* It uses binary_search to find both boundaries (in suffix array).
*/

interval_t topdown(char cmp_char, interval_t interval, string &S, int *SA) {
	int offset = interval.depth;
	int start = interval.start;
	int end = interval.end;
	int lower_bound, upper_bound;

	//cout << "topdown" << endl;

	if (cmp_char < S[SA[start] + offset]){
		return {-1, 0, 0};
	}
	if (cmp_char > S[SA[end] + offset]){
		return {-1, 0, 0};
	}
  //cout  <<"interval: " << interval.depth <<" " << interval.start << " " << interval.end << endl;
	lower_bound = binary_search_left (cmp_char, interval, S, SA);
  //cout << "lower bound " << lower_bound << endl;
	upper_bound = binary_search_right (cmp_char, interval, S, SA);
	//cout << "upper bound " << upper_bound << endl;
	if (lower_bound <= upper_bound) {
	  //cout << "return values: " << offset + 1 <<  " " << lower_bound << " " << upper_bound << " " << endl;
		return {offset + 1, lower_bound, upper_bound}; // ITERATION
	}

	return {-1, 0, 0};
}

/*
* Builds suffix links for a (sparse) suffix array
*/
interval_t suffix_link (interval_t interval, int *ISA, int *SA, int *LCP, int K, int N) {
	int offset = interval.depth;
	int start = interval.start;
	int end = interval.end;

	offset = offset -  K;
	if (offset <= 0) return {-1, 0, 0};

	start = ISA[SA[start] / K];
	end = ISA[SA[end] / K]; // BUG! bio ovdje

	return expand_link({offset, start, end}, LCP, K, N);
}
/*
* Addition function to suffix_link.
* Tries to build a interval by looking only at
*/
interval_t expand_link (interval_t interval, int *LCP, int K, int N) {
	int offset = interval.depth;
	int start = interval.start;
	int end = interval.end;

	if (offset == 0) return {0, 0, N - 1};

	int T = 2 * offset * log(N/K) / log(2.0);
	int e = 0;

	while (start >= 0 and LCP[start] >= offset) {
		e += 1;
		if (e >= T)
			return 	{-1, 0, 0};
		start -= 1;
	}

	while (end <= (N - 1) and LCP[end + 1] >= offset) {
		end += 1;
		if (e >= T)
			return 	{-1, 0, 0};
		e += 1;
	}

	return {offset, start, end};
}

/*
* Computes interval d:[s..e] of Suffix array that contains query string.
* d = depth = character's found (triplet.depth)
* s = start = starting index of Suffix array that contains character on query_index location in query_string
* e = end = ending index of suffix array
* -1 == character (interval) not found
*/
interval_t traverse(int query_index, interval_t interval, int size, string &S, int *SA, string &query) {
	interval_t triplet_tmp;
  /*
  cout << "\nTravese\n";
  cout << "query_index: " << query_index <<   "\n";
  cout << "string: " << S <<"\n";
  cout << "query: " << query << "\n";
  cout << "size: " << size << endl ;
  cout << "interval: " << interval.depth <<" " << interval.start << " " << interval.end << endl;
  */
  int i = 0;
	while ((query_index + interval.depth) < query.length()) {
	  //cout << "\n[" << i  << "] " <<"interval: " << triplet_tmp.depth <<" " << triplet_tmp.start << " " << triplet_tmp.end << endl;
		triplet_tmp = topdown (query [query_index + interval.depth], interval, S, SA);
    //cout << "\n[" << i++  << "] " <<"interval: " << triplet_tmp.depth <<" " << triplet_tmp.start << " " << triplet_tmp.end << endl;
		if (triplet_tmp.depth == -1 )
			return interval;

		interval = triplet_tmp;
		if (interval.depth >= size)
			break;
	}

	return interval;
}

/*
* Prints out all maximal exact matches of at least L characters
*/
void print_MEM (MEM_t mem){
  cout << "\t" << mem.string_index << "\t" << mem.query_index << "\t" << mem.length << endl;
}

/*
* Tries to expand matched query  (to the left)
*/
void findL (int query_index, int ref_string_index, int length, string &S, string &query, int K, int L, std::vector<MEM_t> &mems) { // K is step, K-SA
	for (int k = 0; k < K ; k += 1){
		if ((query_index == 0 or ref_string_index == 0) and length >= L) {
			mems.push_back({ref_string_index + 1, query_index + 1, length});
			return ;
		}

		if (query[query_index - 1] != S[ref_string_index - 1] and length >= L){
			mems.push_back({ref_string_index + 1, query_index + 1, length});
			return ;
		}

		query_index -= 1;
		ref_string_index -= 1;
		length += 1;
	}
}

/*
* Collects all the matches (Finds the maximum string that ccan be expanded to the right, and tests if for Lmatch)
*/
void collect_MEMs (int curr_index, interval_t SA_i, interval_t MEM_i, string &S, string &query, int *SA, int *LCP, int K, int N, int L, vector<MEM_t> &mems) {
	int SA_index = SA_i.depth;
	int MEM_start = MEM_i.start;
	int MEM_end = MEM_i.end;
	int MEM_index = MEM_i.depth;

	for (int i = MEM_start; i <= MEM_end; i += 1)
		findL (curr_index, SA[i], MEM_index, S, query, K, L, mems);

	while (MEM_index >= SA_index) {
		if (MEM_end + 1 < N/K) { //changed
			MEM_index = max (LCP[MEM_start], LCP[MEM_end + 1]);
		} else {
		  MEM_index = LCP[MEM_start];
		}

		if (MEM_index >= SA_index) {
			while (LCP[MEM_start] >= MEM_index) {
				MEM_start -= 1;
				findL (curr_index, SA[MEM_start], MEM_index, S, query, K, L, mems);
			}
			while ((MEM_end + 1) < N/K and LCP[MEM_end + 1] >= MEM_index) { // changed
				MEM_end += 1;
				findL (curr_index, SA[MEM_end], MEM_index, S, query, K, L, mems);
			}
		}
  }
	return ;
}
/*
* Main functions for finding Maximal Exact Matches.
* It uses 2 triplets (intervals): SA_interval and MEM_interval for to locate indexes in Suffix Array which
* contain query string (traverse function).
* Collect_MEMs functions is used to locate maximal matches in using these intervals (and auxillary arrays:
* LCP (longest common prefix) and ISA (inverse Suffix Array)
* Function suffix_link is used to narrow down intervals (looks for 'missing' suffixes in sparse arrays)
* by building suffix links during search time (instead of build it before search - like in suffix trees)
*/
void MEM(int query_index, string &S, int *ISA, int *LCP, int *SA, string &query, int K, int N, int L) {
	interval_t SA_interval = {0, 0, N / K - 1};
	interval_t MEM_interval = {0, 0, N / K - 1};
	int curr_index = query_index;
	std::vector<MEM_t> mems;

  //cout << "\nMEM\n";
  /*cout << "query_index: " << query_index <<   "\n";
  cout << "string: " << S <<"\n";
  cout << "query: " << query << "\n";
  cout << "K: " << K << " N:" << N << " L: " << L <<endl ;
  */
	if (L < K) return;

	while (curr_index < (query.length() - (K - query_index))) {
		SA_interval = traverse (curr_index, SA_interval, L - (K - 1), S, SA, query);
		//cout << "[SA_interval] depth: " << SA_interval.depth <<" start: " <<SA_interval.start << " end: " << SA_interval.end << endl;
		MEM_interval = traverse (curr_index, MEM_interval, query.length(), S, SA, query);
		//cout << "[MEM_interval] depth: " << MEM_interval.depth <<" start: " <<MEM_interval.start << " end: " << MEM_interval.end << endl;
		if (SA_interval.depth <= 1) {
			SA_interval = MEM_interval = {0, 0, N / K - 1};
			curr_index ++;
			continue;
		}

		if (SA_interval.depth >= (L - (K - 1)))
			collect_MEMs(curr_index, SA_interval, MEM_interval, S, query, SA, LCP, K, N, L, mems);

		curr_index ++;

		SA_interval = suffix_link (SA_interval, ISA, SA, LCP, K, N);
		MEM_interval = suffix_link (MEM_interval, ISA, SA, LCP, K, N);

		if (SA_interval.depth == -1) {
			SA_interval = MEM_interval = {0,  0, N / K - 1};
			continue;
		}
	}

	for (int i = 0; i < mems.size(); ++i) {
		print_MEM(mems[i]);
	}

	return ; // MEMs;
}

<commit_msg>Fixed result for some inputs<commit_after>#include <cmath>
#include "search.h"
#include <iostream>
using namespace std;

/**
* Returns left bound of interval.
* Searches input string (S) for suffixes having "cmp_char" at "q_offset",
* using suffix array (SA).
*/
int binary_search_left (char cmp_char, interval_t interval, string &S, int *SA) {
	int depth = interval.depth;
	int start = interval.start;
	int end = interval.end;

	//cout << "BSEARCH_LEFT" << endl;
	if (cmp_char == S[SA[start] + depth]) {
		return start;
	}

	int middle;
	while ((end - start) > 1) {
		middle = (end + start) / 2;
		if (cmp_char <= S[SA[middle] + depth]) {
			end = middle;
		} else {
			start = middle;
		}
	}

	return end;
}

/**
* Returns right bound of interval.
* Searches input string (S) for suffixes having "cmp_char" at "q_offset",
* using suffix array (SA).
*/
int binary_search_right (char cmp_char, interval_t interval, string &S, int *SA) {
	int depth = interval.depth;
	int start = interval.start;
	int end = interval.end;

	if (cmp_char == S[SA[end] + depth]){
		return end;
	}

	//cout << "BSEARCH_RIGHT" << endl;

	int middle;
	while ((end - start) > 1) {
	  middle = (end + start) / 2;
	  /*
	  cout << "middle: " << middle << endl;
	  cout << "chr: " << cmp_char << endl;
	  cout << "depth: " << depth << endl;
	  cout << "S[SA[middle] + depth]: " << S[SA[middle] + depth] << endl;
	  */
		if (cmp_char < S[SA[middle] + depth]) {
			end = middle;
		} else {
			start = middle;
		}
	}

	return start;
}

/**
* Returns interval containing "cmp_char" if it exists, else returns not_found
* It uses binary_search to find both boundaries (in suffix array).
*/

interval_t topdown(char cmp_char, interval_t interval, string &S, int *SA) {
	int offset = interval.depth;
	int start = interval.start;
	int end = interval.end;
	int lower_bound, upper_bound;

	//cout << "topdown" << endl;

	if (cmp_char < S[SA[start] + offset]){
		return {-1, 0, 0};
	}
	if (cmp_char > S[SA[end] + offset]){
		return {-1, 0, 0};
	}
  //cout  <<"interval: " << interval.depth <<" " << interval.start << " " << interval.end << endl;
	lower_bound = binary_search_left (cmp_char, interval, S, SA);
  //cout << "lower bound " << lower_bound << endl;
	upper_bound = binary_search_right (cmp_char, interval, S, SA);
	//cout << "upper bound " << upper_bound << endl;
	if (lower_bound <= upper_bound) {
	  //cout << "return values: " << offset + 1 <<  " " << lower_bound << " " << upper_bound << " " << endl;
		return {offset + 1, lower_bound, upper_bound}; // ITERATION
	}

	return {-1, 0, 0};
}

/*
* Builds suffix links for a (sparse) suffix array
*/
interval_t suffix_link (interval_t interval, int *ISA, int *SA, int *LCP, int K, int N) {
	int offset = interval.depth;
	int start = interval.start;
	int end = interval.end;

	offset = offset -  K;
	if (offset <= 0) return {-1, 0, 0};

	start = ISA[SA[start] / K];
	end = ISA[SA[end] / K]; // BUG! bio ovdje

	return expand_link({offset, start, end}, LCP, K, N);
}
/*
* Addition function to suffix_link.
* Tries to build a interval by looking only at
*/
interval_t expand_link (interval_t interval, int *LCP, int K, int N) {
	int offset = interval.depth;
	int start = interval.start;
	int end = interval.end;

	if (offset == 0) return {0, 0, N - 1};

	int T = 2 * offset * log(N/K) / log(2.0);
	int e = 0;

	while (start >= 0 and LCP[start] >= offset) {
		e += 1;
		if (e >= T)
			return 	{-1, 0, 0};
		start -= 1;
	}

	while (end <= (N - 1) and LCP[end + 1] >= offset) {
		end += 1;
		if (e >= T)
			return 	{-1, 0, 0};
		e += 1;
	}

	return {offset, start, end};
}

/*
* Computes interval d:[s..e] of Suffix array that contains query string.
* d = depth = character's found (triplet.depth)
* s = start = starting index of Suffix array that contains character on query_index location in query_string
* e = end = ending index of suffix array
* -1 == character (interval) not found
*/
interval_t traverse(int query_index, interval_t interval, int size, string &S, int *SA, string &query) {
	interval_t triplet_tmp;
  /*
  cout << "\nTravese\n";
  cout << "query_index: " << query_index <<   "\n";
  cout << "string: " << S <<"\n";
  cout << "query: " << query << "\n";
  cout << "size: " << size << endl ;
  cout << "interval: " << interval.depth <<" " << interval.start << " " << interval.end << endl;
  */
  int i = 0;
	while ((query_index + interval.depth) < query.length()) {
	  //cout << "\n[" << i  << "] " <<"interval: " << triplet_tmp.depth <<" " << triplet_tmp.start << " " << triplet_tmp.end << endl;
		triplet_tmp = topdown (query [query_index + interval.depth], interval, S, SA);
    //cout << "\n[" << i++  << "] " <<"interval: " << triplet_tmp.depth <<" " << triplet_tmp.start << " " << triplet_tmp.end << endl;
		if (triplet_tmp.depth == -1 )
			return interval;

		interval = triplet_tmp;
		if (interval.depth >= size)
			break;
	}

	return interval;
}

/*
* Prints out all maximal exact matches of at least L characters
*/
void print_MEM (MEM_t mem){
  cout << "\t" << mem.string_index << "\t" << mem.query_index << "\t" << mem.length << endl;
}

/*
* Tries to expand matched query  (to the left)
*/
void findL (int query_index, int ref_string_index, int length, string &S, string &query, int K, int L, std::vector<MEM_t> &mems) { // K is step, K-SA
	for (int k = 0; k < K ; k += 1){
		if ((query_index == 0 or ref_string_index == 0) and length >= L) {
			mems.push_back({ref_string_index + 1, query_index + 1, length});
			return ;
		}

		if (query[query_index - 1] != S[ref_string_index - 1] and length >= L){
			mems.push_back({ref_string_index + 1, query_index + 1, length});
			return ;
		}

		query_index -= 1;
		ref_string_index -= 1;
		length += 1;
	}
}

/*
* Collects all the matches (Finds the maximum string that ccan be expanded to the right, and tests if for Lmatch)
*/
void collect_MEMs (int curr_index, interval_t SA_i, interval_t MEM_i, string &S, string &query, int *SA, int *LCP, int K, int N, int L, vector<MEM_t> &mems) {
	int SA_index = SA_i.depth;
	int MEM_start = MEM_i.start;
	int MEM_end = MEM_i.end;
	int MEM_index = MEM_i.depth;

	for (int i = MEM_start; i <= MEM_end; i += 1)
		findL (curr_index, SA[i], MEM_index, S, query, K, L, mems);

	while (MEM_index >= SA_index) {
		if (MEM_end + 1 < N/K) { //changed
			MEM_index = max (LCP[MEM_start], LCP[MEM_end + 1]);
		} else {
		  MEM_index = LCP[MEM_start];
		}

		if (MEM_index >= SA_index) {
			while (LCP[MEM_start] >= MEM_index) {
				MEM_start -= 1;
				findL (curr_index, SA[MEM_start], MEM_index, S, query, K, L, mems);
			}
			while ((MEM_end + 1) < N/K and LCP[MEM_end + 1] >= MEM_index) { // changed
				MEM_end += 1;
				findL (curr_index, SA[MEM_end], MEM_index, S, query, K, L, mems);
			}
		}
  }
	return ;
}
/*
* Main functions for finding Maximal Exact Matches.
* It uses 2 triplets (intervals): SA_interval and MEM_interval for to locate indexes in Suffix Array which
* contain query string (traverse function).
* Collect_MEMs functions is used to locate maximal matches in using these intervals (and auxillary arrays:
* LCP (longest common prefix) and ISA (inverse Suffix Array)
* Function suffix_link is used to narrow down intervals (looks for 'missing' suffixes in sparse arrays)
* by building suffix links during search time (instead of build it before search - like in suffix trees)
*/
void MEM(int query_index, string &S, int *ISA, int *LCP, int *SA, string &query, int K, int N, int L) {
	interval_t SA_interval = {0, 0, N / K - 1};
	interval_t MEM_interval = {0, 0, N / K - 1};
	int curr_index = query_index;
	std::vector<MEM_t> mems;

  //cout << "\nMEM\n";
  /*cout << "query_index: " << query_index <<   "\n";
  cout << "string: " << S <<"\n";
  cout << "query: " << query << "\n";
  cout << "K: " << K << " N:" << N << " L: " << L <<endl ;
  */
	if (L < K) return;

	while (curr_index < (query.length() - (K - query_index))) {
		SA_interval = traverse (curr_index, SA_interval, L - (K - 1), S, SA, query);
		//cout << "[SA_interval] depth: " << SA_interval.depth <<" start: " <<SA_interval.start << " end: " << SA_interval.end << endl;
		MEM_interval = traverse (curr_index, MEM_interval, query.length(), S, SA, query);
		//cout << "[MEM_interval] depth: " << MEM_interval.depth <<" start: " <<MEM_interval.start << " end: " << MEM_interval.end << endl;
		if (SA_interval.depth <= 1) {
			SA_interval = MEM_interval = {0, 0, N / K - 1};
			curr_index ++;
			continue;
		}

		if (SA_interval.depth >= (L - (K - 1)))
			collect_MEMs(curr_index, SA_interval, MEM_interval, S, query, SA, LCP, K, N, L, mems);

		curr_index ++;

		SA_interval = suffix_link (SA_interval, ISA, SA, LCP, K, N);
		MEM_interval = suffix_link (MEM_interval, ISA, SA, LCP, K, N);

		if (SA_interval.depth == -1) {
			SA_interval = MEM_interval = {0,  0, N / K - 1};
			continue;
		}
	}

	for (int i = 0; i < mems.size(); ++i) {
		bool falsePositive = false;
		for (int j = 0; j < mems.size(); ++j) {
			if (mems[i].string_index == mems[j].string_index and mems[i].length < mems[j].length) {
				falsePositive = true;
				break;
			}
		}
		if(!falsePositive) {
			print_MEM(mems[i]);
		}
	}

	return ; // MEMs;
}

<|endoftext|>


<commit_before>/*
    Class for displaying connection errors
    Copyright (C) 2011  Martin Klapetek <martin.klapetek@gmail.com>

    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 Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "error-handler.h"

#include <QScopedPointer>
#include <QTimer>

#include <KNotification>
#include <KAboutData>
#include <KDebug>

#include <KTp/error-dictionary.h>

#include <TelepathyQt/Account>
#include <TelepathyQt/Connection>

#include <Solid/Networking>

/** Stores the last error message for an account
    For every new error if we're online we wait 30 seconds and show 1 notification for all errors. This will be the only error we show for that account until the user reconnects.
*/

class ConnectionError
{
public:
    ConnectionError(Tp::ConnectionStatusReason connectionStatusReason,
                    const QString &connectionError,
                    const Tp::Connection::ErrorDetails &connectionErrorDetails);

    Tp::ConnectionStatusReason connectionStatusReason() const;
    QString connectionError() const;
    Tp::Connection::ErrorDetails connectionErrorDetails() const;

    bool shown() const;
    void setShown(bool);

    QDateTime errorTime() const;

private:
    bool m_shown;
    Tp::ConnectionStatusReason m_connectionStatusReason;
    Tp::Connection::ErrorDetails m_connectionErrorDetails;
    QString m_connectionError;
    QDateTime m_errorTime;
};

ConnectionError::ConnectionError(Tp::ConnectionStatusReason connectionStatusReason, const QString &connectionError, const Tp::Connection::ErrorDetails &connectionErrorDetails):
    m_connectionStatusReason(connectionStatusReason),
    m_connectionErrorDetails(connectionErrorDetails),
    m_connectionError(connectionError)
{
    m_shown = false;
    m_errorTime = QDateTime::currentDateTime();
}

Tp::ConnectionStatusReason ConnectionError::connectionStatusReason() const
{
    return m_connectionStatusReason;
}

QString ConnectionError::connectionError() const
{
    return m_connectionError;
}

Tp::Connection::ErrorDetails ConnectionError::connectionErrorDetails() const
{
    return m_connectionErrorDetails;
}

QDateTime ConnectionError::errorTime() const
{
    return m_errorTime;
}

bool ConnectionError::shown() const
{
    return m_shown;
}

void ConnectionError::setShown(bool)
{
    m_shown = true;
}

ErrorHandler::ErrorHandler(const Tp::AccountManagerPtr& am, QObject* parent)
    : QObject(parent)
{
    m_accountManager = am;

    Q_FOREACH(const Tp::AccountPtr &account, am->allAccounts()) {
        onNewAccount(account);
    }

    connect(m_accountManager.data(), SIGNAL(newAccount(Tp::AccountPtr)),
            this, SLOT(onNewAccount(Tp::AccountPtr)));
}

ErrorHandler::~ErrorHandler()
{

}

void ErrorHandler::showErrorNotification()
{
    //if we're not currently connected to the network, any older errors were probably related to this, ignore them.
    if (Solid::Networking::status() != Solid::Networking::Connected) {
        return;
    }

    QString errorMessage;

    QHash<Tp::AccountPtr, ConnectionError>::iterator i = m_errorMap.begin();
    while (i != m_errorMap.constEnd()) {
        const Tp::AccountPtr account = i.key();
        ConnectionError &error = i.value();

        //try to group as many error messages as we can, but we still want to give accounts a chance to reconnect
        //only want to show messages that are at least 20 seconds old to give the account a chance to connect.
        if (!error.shown() && error.errorTime().secsTo(QDateTime::currentDateTime()) > 20) {
            switch (error.connectionStatusReason()) {
            case Tp::ConnectionStatusReasonNetworkError:
                errorMessage += i18nc("%1 is the account name", "Could not connect %1. There was a network error, check your connection", account->displayName()) + QLatin1Char('\n');
                break;
            default:
                if (error.connectionErrorDetails().hasServerMessage()) {
                    errorMessage += i18nc("%1 is the account name, %2 the error message", "There was a problem while trying to connect %1 - %2", account->displayName(), error.connectionErrorDetails().serverMessage()) + QLatin1Char('\n');
                } else {
                    errorMessage += i18nc("%1 is the account name, %2 the error message", "There was a problem while trying to connect %1 - %2", account->displayName(), KTp::ErrorDictionary::displayVerboseErrorMessage(error.connectionError())) + QLatin1Char('\n');
                }
                break;
            }
            error.setShown(true);
        }
        ++i;
    }

    if (!errorMessage.isEmpty()) {
        if (errorMessage.endsWith(QLatin1Char('\n'))) {
            errorMessage.chop(1);
        }

        showMessageToUser(errorMessage, ErrorHandler::SystemMessageError);
    }
}

void ErrorHandler::onConnectionStatusChanged(const Tp::ConnectionStatus status)
{
    Tp::AccountPtr account(qobject_cast< Tp::Account* >(sender()));

    //if we're not connected to the network, errors are pointless
    if (Solid::Networking::status() != Solid::Networking::Connected) {
        return;
    }

    if (status == Tp::ConnectionStatusDisconnected) {
        //if this is the first error for this account, store the details of the error to show
        if (account->connectionStatusReason() == Tp::ConnectionStatusReasonRequested) {
            m_errorMap.remove(account);
        }

        if (!m_errorMap.contains(account)) {
            m_errorMap.insert(account, ConnectionError(account->connectionStatusReason(), account->connectionError(), account->connectionErrorDetails()));
            QTimer::singleShot(30 * 1000, this, SLOT(showErrorNotification())); //a timer is kept per account because we want to show 30 seconds after the first still valid error.
        }

    } else  if (status == Tp::ConnectionStatusConnected) {
        //we are now connected, removed pending error messages
        m_errorMap.remove(account);
    }
}

void ErrorHandler::onRequestedPresenceChanged()
{
    Tp::AccountPtr account(qobject_cast< Tp::Account* >(sender()));
    m_errorMap.remove(account);
}

void ErrorHandler::showMessageToUser(const QString &text, const ErrorHandler::SystemMessageType type)
{
    //The pointer is automatically deleted when the event is closed
    KNotification *notification;
    if (type == ErrorHandler::SystemMessageError) {
        notification = new KNotification(QLatin1String("telepathyError"), KNotification::Persistent);
    } else {
        notification = new KNotification(QLatin1String("telepathyInfo"), KNotification::CloseOnTimeout);
    }

    KAboutData aboutData("ktelepathy",0,KLocalizedString(),0);
    notification->setComponentData(KComponentData(aboutData));

    notification->setText(text);
    notification->sendEvent();
}

void ErrorHandler::onNewAccount(const Tp::AccountPtr& account)
{
    connect(account.data(), SIGNAL(connectionStatusChanged(Tp::ConnectionStatus)),
            this, SLOT(onConnectionStatusChanged(Tp::ConnectionStatus)));

    connect(account.data(), SIGNAL(requestedPresenceChanged(Tp::Presence)) , SLOT(onRequestedPresenceChanged()));
    connect(account.data(), SIGNAL(removed()), SLOT(onAccountRemoved()));
}

void ErrorHandler::onAccountRemoved()
{
    Tp::AccountPtr account(qobject_cast<Tp::Account*>(sender()));
    Q_ASSERT(account);
    m_errorMap.remove(account);
}
<commit_msg>Make sure to supress any remaining connection cancelled messages<commit_after>/*
    Class for displaying connection errors
    Copyright (C) 2011  Martin Klapetek <martin.klapetek@gmail.com>

    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 Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "error-handler.h"

#include <QScopedPointer>
#include <QTimer>

#include <KNotification>
#include <KAboutData>
#include <KDebug>

#include <KTp/error-dictionary.h>

#include <TelepathyQt/Account>
#include <TelepathyQt/Connection>

#include <Solid/Networking>

/** Stores the last error message for an account
    For every new error if we're online we wait 30 seconds and show 1 notification for all errors. This will be the only error we show for that account until the user reconnects.
*/

class ConnectionError
{
public:
    ConnectionError(Tp::ConnectionStatusReason connectionStatusReason,
                    const QString &connectionError,
                    const Tp::Connection::ErrorDetails &connectionErrorDetails);

    Tp::ConnectionStatusReason connectionStatusReason() const;
    QString connectionError() const;
    Tp::Connection::ErrorDetails connectionErrorDetails() const;

    bool shown() const;
    void setShown(bool);

    QDateTime errorTime() const;

private:
    bool m_shown;
    Tp::ConnectionStatusReason m_connectionStatusReason;
    Tp::Connection::ErrorDetails m_connectionErrorDetails;
    QString m_connectionError;
    QDateTime m_errorTime;
};

ConnectionError::ConnectionError(Tp::ConnectionStatusReason connectionStatusReason, const QString &connectionError, const Tp::Connection::ErrorDetails &connectionErrorDetails):
    m_connectionStatusReason(connectionStatusReason),
    m_connectionErrorDetails(connectionErrorDetails),
    m_connectionError(connectionError)
{
    m_shown = false;
    m_errorTime = QDateTime::currentDateTime();
}

Tp::ConnectionStatusReason ConnectionError::connectionStatusReason() const
{
    return m_connectionStatusReason;
}

QString ConnectionError::connectionError() const
{
    return m_connectionError;
}

Tp::Connection::ErrorDetails ConnectionError::connectionErrorDetails() const
{
    return m_connectionErrorDetails;
}

QDateTime ConnectionError::errorTime() const
{
    return m_errorTime;
}

bool ConnectionError::shown() const
{
    return m_shown;
}

void ConnectionError::setShown(bool)
{
    m_shown = true;
}

ErrorHandler::ErrorHandler(const Tp::AccountManagerPtr& am, QObject* parent)
    : QObject(parent)
{
    m_accountManager = am;

    Q_FOREACH(const Tp::AccountPtr &account, am->allAccounts()) {
        onNewAccount(account);
    }

    connect(m_accountManager.data(), SIGNAL(newAccount(Tp::AccountPtr)),
            this, SLOT(onNewAccount(Tp::AccountPtr)));
}

ErrorHandler::~ErrorHandler()
{

}

void ErrorHandler::showErrorNotification()
{
    //if we're not currently connected to the network, any older errors were probably related to this, ignore them.
    if (Solid::Networking::status() != Solid::Networking::Connected) {
        return;
    }

    QString errorMessage;

    QHash<Tp::AccountPtr, ConnectionError>::iterator i = m_errorMap.begin();
    while (i != m_errorMap.constEnd()) {
        const Tp::AccountPtr account = i.key();
        ConnectionError &error = i.value();

        //try to group as many error messages as we can, but we still want to give accounts a chance to reconnect
        //only want to show messages that are at least 20 seconds old to give the account a chance to connect.
        if (!error.shown() && error.errorTime().secsTo(QDateTime::currentDateTime()) > 20) {
            switch (error.connectionStatusReason()) {
            case Tp::ConnectionStatusReasonNetworkError:
                errorMessage += i18nc("%1 is the account name", "Could not connect %1. There was a network error, check your connection", account->displayName()) + QLatin1Char('\n');
                break;
            default:
	        if (error.connectionError() == QLatin1String(TP_QT_ERROR_CANCELLED)) {
		    break;
		}
                if (error.connectionErrorDetails().hasServerMessage()) {
                    errorMessage += i18nc("%1 is the account name, %2 the error message", "There was a problem while trying to connect %1 - %2", account->displayName(), error.connectionErrorDetails().serverMessage()) + QLatin1Char('\n');
                } else {
                    errorMessage += i18nc("%1 is the account name, %2 the error message", "There was a problem while trying to connect %1 - %2", account->displayName(), KTp::ErrorDictionary::displayVerboseErrorMessage(error.connectionError())) + QLatin1Char('\n');
                }
                break;
            }
            error.setShown(true);
        }
        ++i;
    }

    if (!errorMessage.isEmpty()) {
        if (errorMessage.endsWith(QLatin1Char('\n'))) {
            errorMessage.chop(1);
        }

        showMessageToUser(errorMessage, ErrorHandler::SystemMessageError);
    }
}

void ErrorHandler::onConnectionStatusChanged(const Tp::ConnectionStatus status)
{
    Tp::AccountPtr account(qobject_cast< Tp::Account* >(sender()));

    //if we're not connected to the network, errors are pointless
    if (Solid::Networking::status() != Solid::Networking::Connected) {
        return;
    }

    if (status == Tp::ConnectionStatusDisconnected) {
        //if this is the first error for this account, store the details of the error to show
        if (account->connectionStatusReason() == Tp::ConnectionStatusReasonRequested) {
            m_errorMap.remove(account);
        }

        if (!m_errorMap.contains(account)) {
            m_errorMap.insert(account, ConnectionError(account->connectionStatusReason(), account->connectionError(), account->connectionErrorDetails()));
            QTimer::singleShot(30 * 1000, this, SLOT(showErrorNotification())); //a timer is kept per account because we want to show 30 seconds after the first still valid error.
        }

    } else  if (status == Tp::ConnectionStatusConnected) {
        //we are now connected, removed pending error messages
        m_errorMap.remove(account);
    }
}

void ErrorHandler::onRequestedPresenceChanged()
{
    Tp::AccountPtr account(qobject_cast< Tp::Account* >(sender()));
    m_errorMap.remove(account);
}

void ErrorHandler::showMessageToUser(const QString &text, const ErrorHandler::SystemMessageType type)
{
    //The pointer is automatically deleted when the event is closed
    KNotification *notification;
    if (type == ErrorHandler::SystemMessageError) {
        notification = new KNotification(QLatin1String("telepathyError"), KNotification::Persistent);
    } else {
        notification = new KNotification(QLatin1String("telepathyInfo"), KNotification::CloseOnTimeout);
    }

    KAboutData aboutData("ktelepathy",0,KLocalizedString(),0);
    notification->setComponentData(KComponentData(aboutData));

    notification->setText(text);
    notification->sendEvent();
}

void ErrorHandler::onNewAccount(const Tp::AccountPtr& account)
{
    connect(account.data(), SIGNAL(connectionStatusChanged(Tp::ConnectionStatus)),
            this, SLOT(onConnectionStatusChanged(Tp::ConnectionStatus)));

    connect(account.data(), SIGNAL(requestedPresenceChanged(Tp::Presence)) , SLOT(onRequestedPresenceChanged()));
    connect(account.data(), SIGNAL(removed()), SLOT(onAccountRemoved()));
}

void ErrorHandler::onAccountRemoved()
{
    Tp::AccountPtr account(qobject_cast<Tp::Account*>(sender()));
    Q_ASSERT(account);
    m_errorMap.remove(account);
}
<|endoftext|>