<commit_before>/*
 * Copyright 2010 Martin Hebnes Pedersen, martinhpedersen @ "google mail"
 * All rights reserved. Distributed under the terms of the MIT License.
 */

#include "HTGTweetTextView.h"

static size_t WriteUrlCallback(void *ptr, size_t size, size_t nmemb, void *data);
status_t _threadDownloadLinkIconURLs(void *data);

HTGTweetTextView::HTGTweetTextView(BRect frame, const char *name, BRect textRect, uint32 resizingMode, uint32 flags) : BTextView(frame, name, textRect, resizingMode, flags) {
		tweetId = std::string("");
		urls = new BList();
}

HTGTweetTextView::HTGTweetTextView(BRect frame, const char *name, BRect textRect, const BFont* font, const rgb_color* color, uint32 resizingMode, uint32 flags) : BTextView(frame, name, textRect, font, color, resizingMode, flags) {
		tweetId = std::string("");
}

void HTGTweetTextView::setTweetId(const char* tweetId) {
	this->tweetId = std::string(tweetId);
}

/*This function is not in use, but I'm keeping it around for now*/
void HTGTweetTextView::parseForUrlsAndDownloadIcons() {
	/*Kill the update thread and clean up*/
	kill_thread(currentThread);
	for(int i = 0; i < urls->CountItems(); i++) {
		delete (HTGTweetMenuItem* )urls->RemoveItem(i);
	}
	delete urls;

	urls = getUrls();
	currentThread = spawn_thread(_threadDownloadLinkIconURLs, "favIcon downloader", 10, this);
	resume_thread(currentThread);
}

void HTGTweetTextView::MouseDown(BPoint point) {
	int32 buttons;
	Window()->CurrentMessage()->FindInt32("buttons", &buttons);
	if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {

		ConvertToScreen(&point);

		BPopUpMenu *myPopUp = new BPopUpMenu("TweetOptions", false, true, B_ITEMS_IN_COLUMN);

		int32 selectionStart;
		int32 selectionFinish;
		GetSelection(&selectionStart, &selectionFinish);
		if((selectionFinish - selectionStart) > 0) {
			myPopUp->AddItem(new HTGTweetMenuItem("Copy", new BMessage(B_COPY)));
			myPopUp->AddSeparatorItem();
		}

		myPopUp->AddItem(new HTGTweetMenuItem("Retweet...", new BMessage(GO_RETWEET)));
		myPopUp->AddItem(new HTGTweetMenuItem("Reply...", new BMessage(GO_REPLY)));
		myPopUp->AddSeparatorItem();

		BList *screenNameList = this->getScreenNames();
		for(int i = 0; i < screenNameList->CountItems(); i++)
			myPopUp->AddItem((HTGTweetMenuItem *)screenNameList->ItemAt(i));

		//urls = getUrls();
		//currentThread = spawn_thread(_threadDownloadLinkIconURLs, "favIcon downloader", 10, this);
		//resume_thread(currentThread);
		if(urls->CountItems() > 0)
			myPopUp->AddSeparatorItem();
		for(int i = 0; i < urls->CountItems(); i++) {
			myPopUp->AddItem((HTGTweetMenuItem *)urls->ItemAt(i));
		}

		BList *tagList = this->getTags();
		if(tagList->CountItems() > 0)
			myPopUp->AddSeparatorItem();
		for(int i = 0; i < tagList->CountItems(); i++)
			myPopUp->AddItem((HTGTweetMenuItem *)tagList->ItemAt(i));

		myPopUp->SetAsyncAutoDestruct(true);
		myPopUp->SetTargetForItems(BMessenger(this));
		myPopUp->Go(point+BPoint(1,1), true, true, true);
	}
	else
		BTextView::MouseDown(point);
}

BList* HTGTweetTextView::getScreenNames() {
	BList *theList = new BList();

	std::string tweetersName(this->Name());
	tweetersName.insert(0, "@");
	tweetersName.append("...");
	BMessage *firstMessage = new BMessage(GO_USER);
	firstMessage->AddString("text", this->Name());
	theList->AddItem(new HTGTweetMenuItem(tweetersName.c_str(), firstMessage));

	for(int i = 0; Text()[i] != '\0'; i++) {
		if(Text()[i] == '@') {
			i++; //Skip leading '@'
			std::string newName("");
			while(isValidScreenNameChar(Text()[i])) {
				newName.append(1, Text()[i]);
				i++;
			}
			BMessage *theMessage = new BMessage(GO_USER);
			theMessage->AddString("text", newName.c_str());
			newName.insert(0, "@");
			newName.append("...");
			theList->AddItem(new HTGTweetMenuItem(newName.c_str(), theMessage));
		}
	}

	return theList;
}

BList* HTGTweetTextView::getUrls() {
	BList *theList = new BList();
	size_t pos = 0;
	std::string theText(this->Text());

	/*Search for :// (URIs)*/
	while(pos != std::string::npos) {
		pos = theText.find("://", pos);
		if(pos != std::string::npos) {
			int start = pos;
			int end = pos;
			while(start >= 0 && theText[start] != ' ' && theText[start] != '\n' && theText[start] > 0) {
				start--;
			}
			while(end < theText.length() && theText[end] != ' ') {
				end++;
			}
			BMessage *theMessage = new BMessage(GO_TO_URL);
			theMessage->AddString("url", theText.substr(start+1, end-start-1).c_str());
			theList->AddItem(new HTGTweetMenuItem(theText.substr(start+1, end-start-1).c_str(), theMessage));
			pos = end;
		}
	}

	/*Search for www.*/
	pos = 0;
	while(pos != std::string::npos) {
		pos = theText.find("www.", pos);
		if(theText.find("://", pos-3, 3) != std::string::npos) //So we don't add URL's detected from the method above.
			pos++;
		else if (pos != std::string::npos) {
			int start = pos;
			int end = pos;
			while(end < theText.length() && theText[end] != ' ') {
				end++;
			}
			BMessage *theMessage = new BMessage(GO_TO_URL);
			std::string httpString(theText.substr(start, end-start).c_str());
			httpString.insert(0, "http://"); //Add the http:// prefix.
			theMessage->AddString("url", httpString.c_str());
			theList->AddItem(new HTGTweetMenuItem(httpString.c_str(), theMessage));
			pos = end;
		}
	}

	return theList;
}

BList* HTGTweetTextView::getTags() {
	BList *theList = new BList();
	size_t pos = 0;
	std::string theText(this->Text());

	while(pos != std::string::npos) {
		pos = theText.find("#", pos);
		if(pos != std::string::npos) {
			int start = pos;
			int end = pos;
			while(end < theText.length() && theText[end] != ' ' && theText[end] != '\n') {
				end++;
			}
			if(end == theText.length()-2) //For some reason, we have to do this.
				end--;
			BMessage *theMessage = new BMessage(GO_SEARCH);
			theMessage->AddString("text", theText.substr(start, end-start).c_str());
			theList->AddItem(new HTGTweetMenuItem(theText.substr(start, end-start).c_str(), theMessage));
			pos = end;
		}
	}

	return theList;
}

bool HTGTweetTextView::isValidScreenNameChar(const char& c) {
	if(c <= 'z' && c >= 'a')
		return true;
	if(c <= 'Z' && c >= 'A')
		return true;
	if(c <= '9' && c >= '0')
		return true;
	if(c == '_')
		return true;

	return false;
}

void HTGTweetTextView::sendRetweetMsgToParent() {
	BMessage *retweetMsg = new BMessage(NEW_TWEET);
	std::string RTString(this->Text());
	RTString.insert(0, ": ");
	RTString.insert(0, this->Name());
	RTString.insert(0, "@");
	RTString.insert(0, "♺ ");
	retweetMsg->AddString("text", RTString.c_str());
	retweetMsg->AddString("reply_to_id", tweetId.c_str());
	BTextView::MessageReceived(retweetMsg);
}

void HTGTweetTextView::sendReplyMsgToParent() {
	BMessage *replyMsg = new BMessage(NEW_TWEET);
	std::string theString(" ");
	theString.insert(0, this->Name());
	theString.insert(0, "@");
	replyMsg->AddString("text", theString.c_str());
	replyMsg->AddString("reply_to_id", tweetId.c_str());
	BTextView::MessageReceived(replyMsg);
}

void HTGTweetTextView::MessageReceived(BMessage *msg) {
	const char* url_label = "url";
	const char* name_label = "screenName";
	std::string newTweetAppend(" ");
	switch(msg->what) {
		case GO_RETWEET:
			this->sendRetweetMsgToParent();
			break;
		case GO_REPLY:
			this->sendReplyMsgToParent();
			break;
		case GO_TO_URL:
			this->openUrl(msg->FindString(url_label, (int32)0));
			break;
		default:
			BTextView::MessageReceived(msg);
	}
}

void HTGTweetTextView::openUrl(const char *url) {
	// be lazy and let /bin/open open the URL
	entry_ref ref;
	if (get_ref_for_path("/bin/open", &ref))
		return;

	const char* args[] = { "/bin/open", url, NULL };
	be_roster->Launch(&ref, 2, args);
}

HTGTweetTextView::~HTGTweetTextView() {
	/*Kill the update thread*/
	kill_thread(currentThread);
}

status_t _threadDownloadLinkIconURLs(void *data) {
	HTGTweetTextView *super = (HTGTweetTextView*)data;
	CURL *curl_handle;
	BMallocIO *mallocIO = NULL;

	HTGTweetMenuItem* currentItem = NULL;
	for(int i = 0; i < super->urls->CountItems(); i++) {
		currentItem = (HTGTweetMenuItem *)super->urls->ItemAt(i);
		char hei[1000];

		curl_global_init(CURL_GLOBAL_ALL);
		curl_handle = curl_easy_init();
		curl_easy_setopt(curl_handle, CURLOPT_URL, currentItem->Label());
		curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
		curl_easy_setopt(curl_handle, CURLOPT_HEADER, 1);

		/*send all data to this function*/
		curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteUrlCallback);

		/*we pass out 'mallocIO' object to the callback function*/
		mallocIO = new BMallocIO();
		curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)mallocIO);

		curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "haikutwitter-agent/1.0");

		/*get the data*/
		if(curl_easy_perform(curl_handle) < 0)
			std::cout << "libcURL: Download of linked page failed." << std::endl;

		/*cleanup curl stuff*/
		curl_easy_cleanup(curl_handle);

		char *rawData = (char *)mallocIO->Buffer();
		rawData[mallocIO->BufferLength()-1] = '\0';
		std::string replyMsg(rawData);

		/*Parse for base-url*/
		std::string location(currentItem->Label());
		int pos = 0;
		while(pos != std::string::npos) {
		pos = location.find("http://", pos);
			if(pos != std::string::npos) {
				int end = location.find("/", pos+8);
				location = location.substr(pos, end-pos);
				pos = end;
				i++;
			}
		}

		/*Parse for redirects (Location: http://)*/
		const char *queryTag = "Location: http://";
		pos = 0;
		while(pos != std::string::npos) {
		pos = replyMsg.find(queryTag, pos);
			if(pos != std::string::npos) {
				int start = pos+strlen(queryTag)-7;
				int end = replyMsg.find("/", start+8);
				location = replyMsg.substr(start, end-start);
				pos = end;
				i++;
			}
		}

		/*Parse for url to favIcon*/ //<link rel="shortcut icon" href="http://static.ak.fbcdn.net/rsrc.php/z9Q0Q/hash/8yhim1ep.ico" />
		queryTag = "shortcut icon\" href=\"";
		pos = 0;
		while(pos != std::string::npos) {
		pos = replyMsg.find(queryTag, pos);
			if(pos != std::string::npos) {
				int start = pos+strlen(queryTag);
				int end = replyMsg.find(".ico", start)+4;
				if(end == std::string::npos+4)
					break;
				std::string searchQuery(replyMsg.substr(start, end-start));
				if(searchQuery[0] != 'h') { //URL is relative, add the guessed location from above
					searchQuery.insert(0, "/");
					searchQuery.insert(0, location);
					std::cout << searchQuery << std::endl;
				}
				currentItem->setLinkIconUrl(searchQuery);
				std::cout << "Detected icon at: " << searchQuery << std::endl;
				pos = end;
				i++;
			}
		}

		/*Delete the buffer*/
		delete mallocIO;
	}

	return B_OK;
}

/*Callback function for cURL (favIcon download)*/
static size_t WriteUrlCallback(void *ptr, size_t size, size_t nmemb, void *data) {
	size_t realsize = size *nmemb;
	BMallocIO *mallocIO = (BMallocIO *)data;
	size_t written = mallocIO->Write(ptr, realsize);

	/*Only download head*/
	char *rawData = (char *)mallocIO->Buffer();
	std::string replyMsg(rawData, mallocIO->BufferLength());
	if(replyMsg.find("</head>") != std::string::npos)
		return 0;

	if(mallocIO->BufferLength() > 10000) {//We don't want to download large files.
		std::cout << "Aborting search for URL icon: Too large file" << std::endl;
		return 0;
	}
	else
		return written;
}
<commit_msg>Woops, forgot to uncomment.<commit_after>/*
 * Copyright 2010 Martin Hebnes Pedersen, martinhpedersen @ "google mail"
 * All rights reserved. Distributed under the terms of the MIT License.
 */

#include "HTGTweetTextView.h"

static size_t WriteUrlCallback(void *ptr, size_t size, size_t nmemb, void *data);
status_t _threadDownloadLinkIconURLs(void *data);

HTGTweetTextView::HTGTweetTextView(BRect frame, const char *name, BRect textRect, uint32 resizingMode, uint32 flags) : BTextView(frame, name, textRect, resizingMode, flags) {
		tweetId = std::string("");
		urls = new BList();
}

HTGTweetTextView::HTGTweetTextView(BRect frame, const char *name, BRect textRect, const BFont* font, const rgb_color* color, uint32 resizingMode, uint32 flags) : BTextView(frame, name, textRect, font, color, resizingMode, flags) {
		tweetId = std::string("");
}

void HTGTweetTextView::setTweetId(const char* tweetId) {
	this->tweetId = std::string(tweetId);
}

/*This function is not in use, but I'm keeping it around for now*/
void HTGTweetTextView::parseForUrlsAndDownloadIcons() {
	/*Kill the update thread and clean up*/
	kill_thread(currentThread);
	for(int i = 0; i < urls->CountItems(); i++) {
		delete (HTGTweetMenuItem* )urls->RemoveItem(i);
	}
	delete urls;

	urls = getUrls();
	currentThread = spawn_thread(_threadDownloadLinkIconURLs, "favIcon downloader", 10, this);
	resume_thread(currentThread);
}

void HTGTweetTextView::MouseDown(BPoint point) {
	int32 buttons;
	Window()->CurrentMessage()->FindInt32("buttons", &buttons);
	if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {

		ConvertToScreen(&point);

		BPopUpMenu *myPopUp = new BPopUpMenu("TweetOptions", false, true, B_ITEMS_IN_COLUMN);

		int32 selectionStart;
		int32 selectionFinish;
		GetSelection(&selectionStart, &selectionFinish);
		if((selectionFinish - selectionStart) > 0) {
			myPopUp->AddItem(new HTGTweetMenuItem("Copy", new BMessage(B_COPY)));
			myPopUp->AddSeparatorItem();
		}

		myPopUp->AddItem(new HTGTweetMenuItem("Retweet...", new BMessage(GO_RETWEET)));
		myPopUp->AddItem(new HTGTweetMenuItem("Reply...", new BMessage(GO_REPLY)));
		myPopUp->AddSeparatorItem();

		BList *screenNameList = this->getScreenNames();
		for(int i = 0; i < screenNameList->CountItems(); i++)
			myPopUp->AddItem((HTGTweetMenuItem *)screenNameList->ItemAt(i));

		urls = getUrls();
		currentThread = spawn_thread(_threadDownloadLinkIconURLs, "favIcon downloader", 10, this);
		resume_thread(currentThread);
		if(urls->CountItems() > 0)
			myPopUp->AddSeparatorItem();
		for(int i = 0; i < urls->CountItems(); i++) {
			myPopUp->AddItem((HTGTweetMenuItem *)urls->ItemAt(i));
		}

		BList *tagList = this->getTags();
		if(tagList->CountItems() > 0)
			myPopUp->AddSeparatorItem();
		for(int i = 0; i < tagList->CountItems(); i++)
			myPopUp->AddItem((HTGTweetMenuItem *)tagList->ItemAt(i));

		myPopUp->SetAsyncAutoDestruct(true);
		myPopUp->SetTargetForItems(BMessenger(this));
		myPopUp->Go(point+BPoint(1,1), true, true, true);
	}
	else
		BTextView::MouseDown(point);
}

BList* HTGTweetTextView::getScreenNames() {
	BList *theList = new BList();

	std::string tweetersName(this->Name());
	tweetersName.insert(0, "@");
	tweetersName.append("...");
	BMessage *firstMessage = new BMessage(GO_USER);
	firstMessage->AddString("text", this->Name());
	theList->AddItem(new HTGTweetMenuItem(tweetersName.c_str(), firstMessage));

	for(int i = 0; Text()[i] != '\0'; i++) {
		if(Text()[i] == '@') {
			i++; //Skip leading '@'
			std::string newName("");
			while(isValidScreenNameChar(Text()[i])) {
				newName.append(1, Text()[i]);
				i++;
			}
			BMessage *theMessage = new BMessage(GO_USER);
			theMessage->AddString("text", newName.c_str());
			newName.insert(0, "@");
			newName.append("...");
			theList->AddItem(new HTGTweetMenuItem(newName.c_str(), theMessage));
		}
	}

	return theList;
}

BList* HTGTweetTextView::getUrls() {
	BList *theList = new BList();
	size_t pos = 0;
	std::string theText(this->Text());

	/*Search for :// (URIs)*/
	while(pos != std::string::npos) {
		pos = theText.find("://", pos);
		if(pos != std::string::npos) {
			int start = pos;
			int end = pos;
			while(start >= 0 && theText[start] != ' ' && theText[start] != '\n' && theText[start] > 0) {
				start--;
			}
			while(end < theText.length() && theText[end] != ' ') {
				end++;
			}
			BMessage *theMessage = new BMessage(GO_TO_URL);
			theMessage->AddString("url", theText.substr(start+1, end-start-1).c_str());
			theList->AddItem(new HTGTweetMenuItem(theText.substr(start+1, end-start-1).c_str(), theMessage));
			pos = end;
		}
	}

	/*Search for www.*/
	pos = 0;
	while(pos != std::string::npos) {
		pos = theText.find("www.", pos);
		if(theText.find("://", pos-3, 3) != std::string::npos) //So we don't add URL's detected from the method above.
			pos++;
		else if (pos != std::string::npos) {
			int start = pos;
			int end = pos;
			while(end < theText.length() && theText[end] != ' ') {
				end++;
			}
			BMessage *theMessage = new BMessage(GO_TO_URL);
			std::string httpString(theText.substr(start, end-start).c_str());
			httpString.insert(0, "http://"); //Add the http:// prefix.
			theMessage->AddString("url", httpString.c_str());
			theList->AddItem(new HTGTweetMenuItem(httpString.c_str(), theMessage));
			pos = end;
		}
	}

	return theList;
}

BList* HTGTweetTextView::getTags() {
	BList *theList = new BList();
	size_t pos = 0;
	std::string theText(this->Text());

	while(pos != std::string::npos) {
		pos = theText.find("#", pos);
		if(pos != std::string::npos) {
			int start = pos;
			int end = pos;
			while(end < theText.length() && theText[end] != ' ' && theText[end] != '\n') {
				end++;
			}
			if(end == theText.length()-2) //For some reason, we have to do this.
				end--;
			BMessage *theMessage = new BMessage(GO_SEARCH);
			theMessage->AddString("text", theText.substr(start, end-start).c_str());
			theList->AddItem(new HTGTweetMenuItem(theText.substr(start, end-start).c_str(), theMessage));
			pos = end;
		}
	}

	return theList;
}

bool HTGTweetTextView::isValidScreenNameChar(const char& c) {
	if(c <= 'z' && c >= 'a')
		return true;
	if(c <= 'Z' && c >= 'A')
		return true;
	if(c <= '9' && c >= '0')
		return true;
	if(c == '_')
		return true;

	return false;
}

void HTGTweetTextView::sendRetweetMsgToParent() {
	BMessage *retweetMsg = new BMessage(NEW_TWEET);
	std::string RTString(this->Text());
	RTString.insert(0, ": ");
	RTString.insert(0, this->Name());
	RTString.insert(0, "@");
	RTString.insert(0, "♺ ");
	retweetMsg->AddString("text", RTString.c_str());
	retweetMsg->AddString("reply_to_id", tweetId.c_str());
	BTextView::MessageReceived(retweetMsg);
}

void HTGTweetTextView::sendReplyMsgToParent() {
	BMessage *replyMsg = new BMessage(NEW_TWEET);
	std::string theString(" ");
	theString.insert(0, this->Name());
	theString.insert(0, "@");
	replyMsg->AddString("text", theString.c_str());
	replyMsg->AddString("reply_to_id", tweetId.c_str());
	BTextView::MessageReceived(replyMsg);
}

void HTGTweetTextView::MessageReceived(BMessage *msg) {
	const char* url_label = "url";
	const char* name_label = "screenName";
	std::string newTweetAppend(" ");
	switch(msg->what) {
		case GO_RETWEET:
			this->sendRetweetMsgToParent();
			break;
		case GO_REPLY:
			this->sendReplyMsgToParent();
			break;
		case GO_TO_URL:
			this->openUrl(msg->FindString(url_label, (int32)0));
			break;
		default:
			BTextView::MessageReceived(msg);
	}
}

void HTGTweetTextView::openUrl(const char *url) {
	// be lazy and let /bin/open open the URL
	entry_ref ref;
	if (get_ref_for_path("/bin/open", &ref))
		return;

	const char* args[] = { "/bin/open", url, NULL };
	be_roster->Launch(&ref, 2, args);
}

HTGTweetTextView::~HTGTweetTextView() {
	/*Kill the update thread*/
	kill_thread(currentThread);
}

status_t _threadDownloadLinkIconURLs(void *data) {
	HTGTweetTextView *super = (HTGTweetTextView*)data;
	CURL *curl_handle;
	BMallocIO *mallocIO = NULL;

	HTGTweetMenuItem* currentItem = NULL;
	for(int i = 0; i < super->urls->CountItems(); i++) {
		currentItem = (HTGTweetMenuItem *)super->urls->ItemAt(i);
		char hei[1000];

		curl_global_init(CURL_GLOBAL_ALL);
		curl_handle = curl_easy_init();
		curl_easy_setopt(curl_handle, CURLOPT_URL, currentItem->Label());
		curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
		curl_easy_setopt(curl_handle, CURLOPT_HEADER, 1);

		/*send all data to this function*/
		curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteUrlCallback);

		/*we pass out 'mallocIO' object to the callback function*/
		mallocIO = new BMallocIO();
		curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)mallocIO);

		curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "haikutwitter-agent/1.0");

		/*get the data*/
		if(curl_easy_perform(curl_handle) < 0)
			std::cout << "libcURL: Download of linked page failed." << std::endl;

		/*cleanup curl stuff*/
		curl_easy_cleanup(curl_handle);

		char *rawData = (char *)mallocIO->Buffer();
		rawData[mallocIO->BufferLength()-1] = '\0';
		std::string replyMsg(rawData);

		/*Parse for base-url*/
		std::string location(currentItem->Label());
		int pos = 0;
		while(pos != std::string::npos) {
		pos = location.find("http://", pos);
			if(pos != std::string::npos) {
				int end = location.find("/", pos+8);
				location = location.substr(pos, end-pos);
				pos = end;
				i++;
			}
		}

		/*Parse for redirects (Location: http://)*/
		const char *queryTag = "Location: http://";
		pos = 0;
		while(pos != std::string::npos) {
		pos = replyMsg.find(queryTag, pos);
			if(pos != std::string::npos) {
				int start = pos+strlen(queryTag)-7;
				int end = replyMsg.find("/", start+8);
				location = replyMsg.substr(start, end-start);
				pos = end;
				i++;
			}
		}

		/*Parse for url to favIcon*/ //<link rel="shortcut icon" href="http://static.ak.fbcdn.net/rsrc.php/z9Q0Q/hash/8yhim1ep.ico" />
		queryTag = "shortcut icon\" href=\"";
		pos = 0;
		while(pos != std::string::npos) {
		pos = replyMsg.find(queryTag, pos);
			if(pos != std::string::npos) {
				int start = pos+strlen(queryTag);
				int end = replyMsg.find(".ico", start)+4;
				if(end == std::string::npos+4)
					break;
				std::string searchQuery(replyMsg.substr(start, end-start));
				if(searchQuery[0] != 'h') { //URL is relative, add the guessed location from above
					searchQuery.insert(0, "/");
					searchQuery.insert(0, location);
					std::cout << searchQuery << std::endl;
				}
				currentItem->setLinkIconUrl(searchQuery);
				std::cout << "Detected icon at: " << searchQuery << std::endl;
				pos = end;
				i++;
			}
		}

		/*Delete the buffer*/
		delete mallocIO;
	}

	return B_OK;
}

/*Callback function for cURL (favIcon download)*/
static size_t WriteUrlCallback(void *ptr, size_t size, size_t nmemb, void *data) {
	size_t realsize = size *nmemb;
	BMallocIO *mallocIO = (BMallocIO *)data;
	size_t written = mallocIO->Write(ptr, realsize);

	/*Only download head*/
	char *rawData = (char *)mallocIO->Buffer();
	std::string replyMsg(rawData, mallocIO->BufferLength());
	if(replyMsg.find("</head>") != std::string::npos)
		return 0;

	if(mallocIO->BufferLength() > 10000) {//We don't want to download large files.
		std::cout << "Aborting search for URL icon: Too large file" << std::endl;
		return 0;
	}
	else
		return written;
}
<|endoftext|>


<commit_before><commit_msg>cppcheck: redundantAssignment<commit_after><|endoftext|>


<commit_before>// Copyright (c) Microsoft. All rights reserved.

//
// i2ctesttool
//
//   Utility to read and write I2C devices from the command line.
//   Shows how to use C++/CX in console applications.
//

#include <ppltasks.h>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <cwctype>

using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Devices::I2c;

class wexception
{
public:
    explicit wexception (const std::wstring &msg) : msg_(msg) { }
    virtual ~wexception () { /*empty*/ }

    virtual const wchar_t *wwhat () const
    {
        return msg_.c_str();
    }

private:
    std::wstring msg_;
};

I2cDevice^ MakeDevice (int slaveAddress, _In_opt_ String^ friendlyName)
{
    using namespace Windows::Devices::Enumeration;

    String^ aqs;
    if (friendlyName)
        aqs = I2cDevice::GetDeviceSelector(friendlyName);
    else
        aqs = I2cDevice::GetDeviceSelector();

    auto dis = concurrency::create_task(DeviceInformation::FindAllAsync(aqs)).get();
    if (dis->Size != 1) {
        throw wexception(L"I2C bus not found");
    }

    String^ id = dis->GetAt(0)->Id;
    auto device = concurrency::create_task(I2cDevice::FromIdAsync(
                    id,
                    ref new I2cConnectionSettings(slaveAddress))).get();

    if (!device) {
        std::wostringstream msg;
        msg << L"Slave address 0x" << std::hex << slaveAddress << L" on bus " << id->Data() <<
            L" is in use. Please ensure that no other applications are using I2C.";
        throw wexception(msg.str());
    }

    return device;
}

std::wostream& operator<< (std::wostream& os, const I2cTransferResult& result)
{
    switch (result.Status) {
    case I2cTransferStatus::FullTransfer: break;
    case I2cTransferStatus::PartialTransfer:
        os << L"Partial Transfer. Transferred " <<
            result.BytesTransferred << L" bytes\n";
        break;
    case I2cTransferStatus::SlaveAddressNotAcknowledged:
        os << L"Slave address was not acknowledged\n";
        break;
    default:
        throw wexception(L"Invalid transfer status value");
    }
    return os;
}

std::wistream& expect (std::wistream& is, wchar_t delim)
{
    wchar_t ch;
    while (is.get(ch)) {
        if (ch == delim) return is;
        if (!isspace(ch)) {
            is.clear(is.failbit);
            break;
        }
    }
    return is;
}

std::wistream& operator>> (std::wistream& is, std::vector<BYTE>& bytes)
{
    bytes.clear();

    if (!expect(is, L'{')) {
        std::wcout << L"Syntax error: expecting '{'\n";
        return is;
    }

    // get a sequence of bytes, e.g.
    //   write { 0 1 2 3 4 aa bb cc dd }
    unsigned int byte;
    while (is >> std::hex >> byte) {
        if (byte > 0xff) {
            std::wcout << L"Out of range [0, 0xff]: " << std::hex << byte << L"\n";
            is.clear(is.failbit);
            return is;
        }
        bytes.push_back(static_cast<BYTE>(byte));
    }

    if (bytes.empty()) {
        std::wcout << L"Zero-length buffers are not allowed\n";
        is.clear(is.failbit);
        return is;
    }

    is.clear();
    if (!expect(is, L'}')) {
        std::wcout << L"Syntax error: expecting '}'\n";
        return is;
    }
    return is;
}

std::wostream& operator<< (std::wostream& os, const Platform::Array<BYTE>^ bytes)
{
    for (auto byte : bytes)
        os << L" " << std::hex << byte;
    return os;
}

std::wostream& operator<< (std::wostream& os, I2cBusSpeed busSpeed)
{
    switch (busSpeed) {
    case I2cBusSpeed::StandardMode:
        return os << L"StandardMode (100Khz)";
    case I2cBusSpeed::FastMode:
        return os << L"FastMode (400kHz)";
    default:
        return os << L"[Invalid bus speed]";
    }
}

PCWSTR Help =
    L"Commands:\n"
    L" > write { 00 11 22 .. FF }         Write bytes to device\n"
    L" > read N                           Read N bytes\n"
    L" > writeread { 00 11 .. FF } N      Write bytes, restart, read N bytes\n"
    L" > info                             Display device information\n"
    L" > help                             Display this help message\n"
    L" > quit                             Quit\n\n";

void ShowPrompt (I2cDevice^ device)
{
    while (std::wcin) {
        std::wcout << L"> ";

        std::wstring line;
        if (!std::getline(std::wcin, line)) {
            return;
        }
        std::wistringstream linestream(line);

        std::wstring command;
        linestream >> command;
        if ((command == L"q") || (command == L"quit")) {
            return;
        } else if ((command == L"h") || (command == L"help")) {
            std::wcout << Help;
        } else if (command == L"write") {
            std::vector<BYTE> writeBuf;
            if (!(linestream >> writeBuf)) {
                std::wcout << L"Usage: write { 55 a0 ... ff }\n";
                continue;
            }

            I2cTransferResult result = device->WritePartial(
                ArrayReference<BYTE>(
                    writeBuf.data(),
                    static_cast<unsigned int>(writeBuf.size())));

            switch (result.Status) {
            case I2cTransferStatus::FullTransfer:
                break;
            case I2cTransferStatus::PartialTransfer:
                std::wcout << L"Partial Transfer. Transferred " <<
                    result.BytesTransferred << L" bytes\n";
                break;
            case I2cTransferStatus::SlaveAddressNotAcknowledged:
                std::wcout << L"Slave address was not acknowledged\n";
                break;
            default:
                throw wexception(L"Invalid transfer status value");
            }
        } else if (command == L"read") {
            // expecting a single int, number of bytes to read
            unsigned int bytesToRead;
            if (!(linestream >> std::dec >> bytesToRead)) {
                std::wcout << L"Expecting integer. e.g: read 4\n";
                continue;
            }

            auto readBuf = ref new Platform::Array<BYTE>(bytesToRead);
            I2cTransferResult result = device->ReadPartial(readBuf);

            switch (result.Status) {
            case I2cTransferStatus::FullTransfer:
                std::wcout << readBuf << L"\n";
                break;
            case I2cTransferStatus::PartialTransfer:
                std::wcout << L"Partial Transfer. Transferred " <<
                    result.BytesTransferred << L" bytes\n";
                std::wcout << readBuf << L"\n";
                break;
            case I2cTransferStatus::SlaveAddressNotAcknowledged:
                std::wcout << L"Slave address was not acknowledged\n";
                break;
            default:
                throw wexception(L"Invalid transfer status value");
            }
        } else if (command == L"writeread") {
            // get a sequence of bytes, e.g.
            //   write 0 1 2 3 4 aa bb cc dd
            std::vector<BYTE> writeBuf;
            if (!(linestream >> writeBuf)) {
                std::wcout << L"Usage: writeread { 55 a0 ... ff } 4\n";
                continue;
            }

            unsigned int bytesToRead;
            if (!(linestream >> std::dec >> bytesToRead)) {
                std::wcout << L"Syntax error: expecting integer\n";
                std::wcout << L"Usage: writeread { 55 a0 ... ff } 4\n";
                continue;
            }
            auto readBuf = ref new Array<BYTE>(bytesToRead);

            I2cTransferResult result = device->WriteReadPartial(
                ArrayReference<BYTE>(
                    writeBuf.data(),
                    static_cast<unsigned int>(writeBuf.size())),
                readBuf);

            switch (result.Status) {
            case I2cTransferStatus::FullTransfer:
                std::wcout << readBuf << L"\n";
                break;
            case I2cTransferStatus::PartialTransfer:
            {
                std::wcout << L"Partial Transfer. Transferred " <<
                    result.BytesTransferred << L" bytes\n";
                int bytesRead = result.BytesTransferred - int(writeBuf.size());
                if (bytesRead > 0) {
                    std::wcout << readBuf << L"\n";
                }
                break;
            }
            case I2cTransferStatus::SlaveAddressNotAcknowledged:
                std::wcout << L"Slave address was not acknowledged\n";
                break;
            default:
                throw wexception(L"Invalid transfer status value");
            }
        } else if (command == L"info") {
            int slaveAddress = device->ConnectionSettings->SlaveAddress;
            I2cBusSpeed busSpeed = device->ConnectionSettings->BusSpeed;

            std::wcout << L"       DeviceId: " << device->DeviceId->Data() << "\n";
            std::wcout << L"  Slave address: 0x" << std::hex << slaveAddress << L"\n";
            std::wcout << L"      Bus Speed: " << busSpeed << L"\n";
        } else if (command.empty()) {
            // ignore
        } else {
            std::wcout << L"Unrecognized command: " << command <<
                L". Type 'help' for command usage.\n";
        }
    }
}

void PrintUsage (PCWSTR name)
{
    wprintf(
        L"I2cTestTool: Command line I2C testing utility\n"
        L"Usage: %s SlaveAddress [FriendlyName]\n"
        L"\n"
        L"  SlaveAddress   The slave address of the device with which you\n"
        L"                 wish to communicate. This is a required parameter.\n"
        L"  FriendlyName   The friendly name of the I2C controller over\n"
        L"                 which you wish to communicate. This parameter is\n"
        L"                 optional and defaults to the first enumerated\n"
        L"                 I2C controller.\n"
        L"\n"
        L"Examples:\n"
        L"  %s 0x57\n"
        L"  %s 0x57 I2C1\n",
        name,
        name,
        name);
}

int main (Platform::Array<Platform::String^>^ args)
{
    unsigned int optind = 1;
    if (optind < args->Length) {
        if ((args->get(optind) == L"-h") || (args->get(optind) == L"-?")) {
            PrintUsage(args->get(0)->Data());
            return 0;
        }
    } else {
        std::wcerr << L"Missing required command line parameter SlaveAddress\n\n";
        PrintUsage(args->get(0)->Data());
        return 1;
    }

    int slaveAddress;
    {
        String^ arg = args->get(optind++);
        wchar_t *endptr;
        slaveAddress = int(wcstoul(arg->Data(), &endptr, 0));
        if (endptr != arg->End()) {
            std::wcerr << L"Expecting integer: " << arg->Data() << L"\n";
            std::wcerr << L"Type '" << args->get(0)->Data() << " -h' for usage\n";
            return 1;
        }
    }

    String^ friendlyName;
    if (optind < args->Length) {
        friendlyName = args->get(optind++);
    }

    try {
        auto device = MakeDevice(slaveAddress, friendlyName);

        std::wcout << L"  Type 'help' for a list of commands\n";
        ShowPrompt(device);
    } catch (const wexception& ex) {
        std::wcerr << L"Error: " << ex.wwhat() << L"\n";
        return 1;
    } catch (Platform::Exception^ ex) {
        std::wcerr << L"Error: " << ex->Message->Data() << L"\n";
        return 1;
    }

    return 0;
}
<commit_msg>Enable I2cTestTool to work with first enumerated device.<commit_after>// Copyright (c) Microsoft. All rights reserved.

//
// i2ctesttool
//
//   Utility to read and write I2C devices from the command line.
//   Shows how to use C++/CX in console applications.
//

#include <ppltasks.h>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <cwctype>

using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Devices::I2c;

class wexception
{
public:
    explicit wexception (const std::wstring &msg) : msg_(msg) { }
    virtual ~wexception () { /*empty*/ }

    virtual const wchar_t *wwhat () const
    {
        return msg_.c_str();
    }

private:
    std::wstring msg_;
};

I2cDevice^ MakeDevice (int slaveAddress, _In_opt_ String^ friendlyName)
{
    using namespace Windows::Devices::Enumeration;

    String^ aqs;
    if (friendlyName)
        aqs = I2cDevice::GetDeviceSelector(friendlyName);
    else
        aqs = I2cDevice::GetDeviceSelector();

    auto dis = concurrency::create_task(DeviceInformation::FindAllAsync(aqs)).get();
    if (dis->Size < 1) {
        throw wexception(L"I2C bus not found");
    }

    String^ id = dis->GetAt(0)->Id;
    auto device = concurrency::create_task(I2cDevice::FromIdAsync(
                    id,
                    ref new I2cConnectionSettings(slaveAddress))).get();

    if (!device) {
        std::wostringstream msg;
        msg << L"Slave address 0x" << std::hex << slaveAddress << L" on bus " << id->Data() <<
            L" is in use. Please ensure that no other applications are using I2C.";
        throw wexception(msg.str());
    }

    return device;
}

std::wostream& operator<< (std::wostream& os, const I2cTransferResult& result)
{
    switch (result.Status) {
    case I2cTransferStatus::FullTransfer: break;
    case I2cTransferStatus::PartialTransfer:
        os << L"Partial Transfer. Transferred " <<
            result.BytesTransferred << L" bytes\n";
        break;
    case I2cTransferStatus::SlaveAddressNotAcknowledged:
        os << L"Slave address was not acknowledged\n";
        break;
    default:
        throw wexception(L"Invalid transfer status value");
    }
    return os;
}

std::wistream& expect (std::wistream& is, wchar_t delim)
{
    wchar_t ch;
    while (is.get(ch)) {
        if (ch == delim) return is;
        if (!isspace(ch)) {
            is.clear(is.failbit);
            break;
        }
    }
    return is;
}

std::wistream& operator>> (std::wistream& is, std::vector<BYTE>& bytes)
{
    bytes.clear();

    if (!expect(is, L'{')) {
        std::wcout << L"Syntax error: expecting '{'\n";
        return is;
    }

    // get a sequence of bytes, e.g.
    //   write { 0 1 2 3 4 aa bb cc dd }
    unsigned int byte;
    while (is >> std::hex >> byte) {
        if (byte > 0xff) {
            std::wcout << L"Out of range [0, 0xff]: " << std::hex << byte << L"\n";
            is.clear(is.failbit);
            return is;
        }
        bytes.push_back(static_cast<BYTE>(byte));
    }

    if (bytes.empty()) {
        std::wcout << L"Zero-length buffers are not allowed\n";
        is.clear(is.failbit);
        return is;
    }

    is.clear();
    if (!expect(is, L'}')) {
        std::wcout << L"Syntax error: expecting '}'\n";
        return is;
    }
    return is;
}

std::wostream& operator<< (std::wostream& os, const Platform::Array<BYTE>^ bytes)
{
    for (auto byte : bytes)
        os << L" " << std::hex << byte;
    return os;
}

std::wostream& operator<< (std::wostream& os, I2cBusSpeed busSpeed)
{
    switch (busSpeed) {
    case I2cBusSpeed::StandardMode:
        return os << L"StandardMode (100Khz)";
    case I2cBusSpeed::FastMode:
        return os << L"FastMode (400kHz)";
    default:
        return os << L"[Invalid bus speed]";
    }
}

PCWSTR Help =
    L"Commands:\n"
    L" > write { 00 11 22 .. FF }         Write bytes to device\n"
    L" > read N                           Read N bytes\n"
    L" > writeread { 00 11 .. FF } N      Write bytes, restart, read N bytes\n"
    L" > info                             Display device information\n"
    L" > help                             Display this help message\n"
    L" > quit                             Quit\n\n";

void ShowPrompt (I2cDevice^ device)
{
    while (std::wcin) {
        std::wcout << L"> ";

        std::wstring line;
        if (!std::getline(std::wcin, line)) {
            return;
        }
        std::wistringstream linestream(line);

        std::wstring command;
        linestream >> command;
        if ((command == L"q") || (command == L"quit")) {
            return;
        } else if ((command == L"h") || (command == L"help")) {
            std::wcout << Help;
        } else if (command == L"write") {
            std::vector<BYTE> writeBuf;
            if (!(linestream >> writeBuf)) {
                std::wcout << L"Usage: write { 55 a0 ... ff }\n";
                continue;
            }

            I2cTransferResult result = device->WritePartial(
                ArrayReference<BYTE>(
                    writeBuf.data(),
                    static_cast<unsigned int>(writeBuf.size())));

            switch (result.Status) {
            case I2cTransferStatus::FullTransfer:
                break;
            case I2cTransferStatus::PartialTransfer:
                std::wcout << L"Partial Transfer. Transferred " <<
                    result.BytesTransferred << L" bytes\n";
                break;
            case I2cTransferStatus::SlaveAddressNotAcknowledged:
                std::wcout << L"Slave address was not acknowledged\n";
                break;
            default:
                throw wexception(L"Invalid transfer status value");
            }
        } else if (command == L"read") {
            // expecting a single int, number of bytes to read
            unsigned int bytesToRead;
            if (!(linestream >> std::dec >> bytesToRead)) {
                std::wcout << L"Expecting integer. e.g: read 4\n";
                continue;
            }

            auto readBuf = ref new Platform::Array<BYTE>(bytesToRead);
            I2cTransferResult result = device->ReadPartial(readBuf);

            switch (result.Status) {
            case I2cTransferStatus::FullTransfer:
                std::wcout << readBuf << L"\n";
                break;
            case I2cTransferStatus::PartialTransfer:
                std::wcout << L"Partial Transfer. Transferred " <<
                    result.BytesTransferred << L" bytes\n";
                std::wcout << readBuf << L"\n";
                break;
            case I2cTransferStatus::SlaveAddressNotAcknowledged:
                std::wcout << L"Slave address was not acknowledged\n";
                break;
            default:
                throw wexception(L"Invalid transfer status value");
            }
        } else if (command == L"writeread") {
            // get a sequence of bytes, e.g.
            //   write 0 1 2 3 4 aa bb cc dd
            std::vector<BYTE> writeBuf;
            if (!(linestream >> writeBuf)) {
                std::wcout << L"Usage: writeread { 55 a0 ... ff } 4\n";
                continue;
            }

            unsigned int bytesToRead;
            if (!(linestream >> std::dec >> bytesToRead)) {
                std::wcout << L"Syntax error: expecting integer\n";
                std::wcout << L"Usage: writeread { 55 a0 ... ff } 4\n";
                continue;
            }
            auto readBuf = ref new Array<BYTE>(bytesToRead);

            I2cTransferResult result = device->WriteReadPartial(
                ArrayReference<BYTE>(
                    writeBuf.data(),
                    static_cast<unsigned int>(writeBuf.size())),
                readBuf);

            switch (result.Status) {
            case I2cTransferStatus::FullTransfer:
                std::wcout << readBuf << L"\n";
                break;
            case I2cTransferStatus::PartialTransfer:
            {
                std::wcout << L"Partial Transfer. Transferred " <<
                    result.BytesTransferred << L" bytes\n";
                int bytesRead = result.BytesTransferred - int(writeBuf.size());
                if (bytesRead > 0) {
                    std::wcout << readBuf << L"\n";
                }
                break;
            }
            case I2cTransferStatus::SlaveAddressNotAcknowledged:
                std::wcout << L"Slave address was not acknowledged\n";
                break;
            default:
                throw wexception(L"Invalid transfer status value");
            }
        } else if (command == L"info") {
            int slaveAddress = device->ConnectionSettings->SlaveAddress;
            I2cBusSpeed busSpeed = device->ConnectionSettings->BusSpeed;

            std::wcout << L"       DeviceId: " << device->DeviceId->Data() << "\n";
            std::wcout << L"  Slave address: 0x" << std::hex << slaveAddress << L"\n";
            std::wcout << L"      Bus Speed: " << busSpeed << L"\n";
        } else if (command.empty()) {
            // ignore
        } else {
            std::wcout << L"Unrecognized command: " << command <<
                L". Type 'help' for command usage.\n";
        }
    }
}

void PrintUsage (PCWSTR name)
{
    wprintf(
        L"I2cTestTool: Command line I2C testing utility\n"
        L"Usage: %s SlaveAddress [FriendlyName]\n"
        L"\n"
        L"  SlaveAddress   The slave address of the device with which you\n"
        L"                 wish to communicate. This is a required parameter.\n"
        L"  FriendlyName   The friendly name of the I2C controller over\n"
        L"                 which you wish to communicate. This parameter is\n"
        L"                 optional and defaults to the first enumerated\n"
        L"                 I2C controller.\n"
        L"\n"
        L"Examples:\n"
        L"  %s 0x57\n"
        L"  %s 0x57 I2C1\n",
        name,
        name,
        name);
}

int main (Platform::Array<Platform::String^>^ args)
{
    unsigned int optind = 1;
    if (optind < args->Length) {
        if ((args->get(optind) == L"-h") || (args->get(optind) == L"-?")) {
            PrintUsage(args->get(0)->Data());
            return 0;
        }
    } else {
        std::wcerr << L"Missing required command line parameter SlaveAddress\n\n";
        PrintUsage(args->get(0)->Data());
        return 1;
    }

    int slaveAddress;
    {
        String^ arg = args->get(optind++);
        wchar_t *endptr;
        slaveAddress = int(wcstoul(arg->Data(), &endptr, 0));
        if (endptr != arg->End()) {
            std::wcerr << L"Expecting integer: " << arg->Data() << L"\n";
            std::wcerr << L"Type '" << args->get(0)->Data() << " -h' for usage\n";
            return 1;
        }
    }

    String^ friendlyName;
    if (optind < args->Length) {
        friendlyName = args->get(optind++);
    }

    try {
        auto device = MakeDevice(slaveAddress, friendlyName);

        std::wcout << L"  Type 'help' for a list of commands\n";
        ShowPrompt(device);
    } catch (const wexception& ex) {
        std::wcerr << L"Error: " << ex.wwhat() << L"\n";
        return 1;
    } catch (Platform::Exception^ ex) {
        std::wcerr << L"Error: " << ex->Message->Data() << L"\n";
        return 1;
    }

    return 0;
}
<|endoftext|>


<commit_before>/*=========================================================================

 Program:   openCherry Platform
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) German Cancer Research Center, Division of Medical and
 Biological Informatics. All rights reserved.
 See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/

#include "cherryDefaultSaveable.h"

#include "../cherryIWorkbenchPart.h"
#include "../cherryIWorkbenchPage.h"
#include "../cherryUIException.h"
#include "../cherryImageDescriptor.h"

namespace cherry
{

DefaultSaveable::DefaultSaveable(IWorkbenchPart::Pointer _part) :
 part(_part)
{

}

void DefaultSaveable::DoSave(/*IProgressMonitor monitor*/)
{
  if (part.Cast<ISaveablePart> () != 0)
  {
    part.Cast<ISaveablePart>()->DoSave(/*monitor*/);
  }
}

std::string DefaultSaveable::GetName() const
{
  return part->GetPartName();
}

ImageDescriptor::Pointer DefaultSaveable::GetImageDescriptor() const
{
  //TODO DefaultSaveable GetImageDescriptor
//  Image image = part.getTitleImage();
//  if (image == null)
//  {
//    return null;
//  }
//  return ImageDescriptor.createFromImage(image);
  return ImageDescriptor::Pointer(0);
}

std::string DefaultSaveable::GetToolTipText() const
{
  return part->GetTitleToolTip();
}

bool DefaultSaveable::IsDirty() const
{
  if (part.Cast<ISaveablePart> () != 0)
  {
    return part.Cast<ISaveablePart>()->IsDirty();
  }
  return false;
}

bool DefaultSaveable::operator<(const Saveable* obj) const
{
  if (this == obj)
  return false;
  if (obj == 0)
  return true;

  const DefaultSaveable* other = dynamic_cast<const DefaultSaveable*>(obj);
  if (part == 0)
  {
    if (other->part != 0)
      return true;
  }
  else
    return part < other->part;
}

bool DefaultSaveable::Show(IWorkbenchPage::Pointer page)
{
  IWorkbenchPartReference::Pointer reference = page->GetReference(part);
  if (reference != 0)
  {
    page->Activate(part);
    return true;
  }
  if (part.Cast<IViewPart>() != 0)
  {
    IViewPart::Pointer viewPart = part.Cast<IViewPart>();
    try
    {
      page->ShowView(viewPart->GetViewSite()->GetId(), viewPart
          ->GetViewSite()->GetSecondaryId(),
          IWorkbenchPage::VIEW_ACTIVATE);
    }
    catch (PartInitException& /*e*/)
    {
      return false;
    }
    return true;
  }
  return false;
}

}
<commit_msg>COMP: fixing return value in operator<<commit_after>/*=========================================================================

 Program:   openCherry Platform
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) German Cancer Research Center, Division of Medical and
 Biological Informatics. All rights reserved.
 See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/

#include "cherryDefaultSaveable.h"

#include "../cherryIWorkbenchPart.h"
#include "../cherryIWorkbenchPage.h"
#include "../cherryUIException.h"
#include "../cherryImageDescriptor.h"

namespace cherry
{

DefaultSaveable::DefaultSaveable(IWorkbenchPart::Pointer _part) :
  part(_part)
{

}

void DefaultSaveable::DoSave(/*IProgressMonitor monitor*/)
{
  if (part.Cast<ISaveablePart> () != 0)
  {
    part.Cast<ISaveablePart> ()->DoSave(/*monitor*/);
  }
}

std::string DefaultSaveable::GetName() const
{
  return part->GetPartName();
}

ImageDescriptor::Pointer DefaultSaveable::GetImageDescriptor() const
{
  //TODO DefaultSaveable GetImageDescriptor
  //  Image image = part.getTitleImage();
  //  if (image == null)
  //  {
  //    return null;
  //  }
  //  return ImageDescriptor.createFromImage(image);
  return ImageDescriptor::Pointer(0);
}

std::string DefaultSaveable::GetToolTipText() const
{
  return part->GetTitleToolTip();
}

bool DefaultSaveable::IsDirty() const
{
  if (part.Cast<ISaveablePart> () != 0)
  {
    return part.Cast<ISaveablePart> ()->IsDirty();
  }
  return false;
}

bool DefaultSaveable::operator<(const Saveable* obj) const
{
  if (this == obj)
    return false;
  if (obj == 0)
    return true;

  const DefaultSaveable* other = dynamic_cast<const DefaultSaveable*> (obj);
  if (part == 0)
  {
    return other->part != 0;
  }
  else
    return part < other->part;
}

bool DefaultSaveable::Show(IWorkbenchPage::Pointer page)
{
  IWorkbenchPartReference::Pointer reference = page->GetReference(part);
  if (reference != 0)
  {
    page->Activate(part);
    return true;
  }
  if (part.Cast<IViewPart> () != 0)
  {
    IViewPart::Pointer viewPart = part.Cast<IViewPart> ();
    try
    {
      page->ShowView(viewPart->GetViewSite()->GetId(),
          viewPart ->GetViewSite()->GetSecondaryId(),
          IWorkbenchPage::VIEW_ACTIVATE);
    } catch (PartInitException& /*e*/)
    {
      return false;
    }
    return true;
  }
  return false;
}

}
<|endoftext|>


<commit_before>/* Copyright 2017 The Apollo Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "modules/dreamview/backend/handlers/websocket_handler.h"

#include <chrono>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "modules/common/log.h"

using ::testing::ElementsAre;

namespace apollo {
namespace dreamview {

class MockClient {
 public:
  MockClient(const char *host, int port) {
    conn = mg_connect_websocket_client(host, port, 0, error_buffer, 100,
                                       "/websocket", "", &MockClient::OnMessage,
                                       nullptr, nullptr);
    CHECK_NOTNULL(conn);
  }

  const std::vector<std::string> &GetReceivedMessages() {
    return received_messages_;
  }

 private:
  static int OnMessage(struct mg_connection *conn, int bits, char *data,
                       size_t data_len, void *cbdata) {
    AINFO << "Get " << *data;
    received_messages_.emplace_back(data);
    return 1;
  }

  mg_connection *conn;
  char error_buffer[100];
  static std::vector<std::string> received_messages_;
};
std::vector<std::string> MockClient::received_messages_;

static WebSocketHandler handler("Test");

TEST(WebSocketTest, IntegrationTest) {
  // NOTE: Here a magic number is picked up as the port, which is not ideal but
  // in almost all cases this should be fine for a small integration test.
  CivetServer server({"listening_ports", "32695"});
  server.addWebSocketHandler("/websocket", handler);

  // Wait for a small amount of time to make sure that the server is up.
  std::this_thread::sleep_for(std::chrono::milliseconds(300));

  MockClient client("localhost", 32695);

  // Wait for a small amount of time to make sure that the client is up and
  // connected.
  std::this_thread::sleep_for(std::chrono::milliseconds(300));

  // Send 3 messages.
  for (int i = 0; i < 3; ++i) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    handler.BroadcastData(std::to_string(i));
  }

  std::this_thread::sleep_for(std::chrono::milliseconds(200));

  // Check that the 3 messages are successfully received and processed.
  EXPECT_THAT(client.GetReceivedMessages(), ElementsAre("0", "1", "2"));
}

}  // namespace dreamview
}  // namespace apollo
<commit_msg>add unit test for dreamview web handler (#4900)<commit_after>/* Copyright 2017 The Apollo Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "modules/dreamview/backend/handlers/websocket_handler.h"

#include <chrono>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "modules/common/log.h"

using ::testing::ElementsAre;

namespace apollo {
namespace dreamview {

class MockClient {
 public:
  MockClient(const char *host, int port) {
    conn = mg_connect_websocket_client(host, port, 0, error_buffer, 100,
                                       "/websocket", "", &MockClient::OnMessage,
                                       nullptr, nullptr);
    CHECK_NOTNULL(conn);
  }

  const std::vector<std::string> &GetReceivedMessages() {
    return received_messages_;
  }

 private:
  static int OnMessage(struct mg_connection *conn, int bits, char *data,
                       size_t data_len, void *cbdata) {
    AINFO << "Get " << *data;
    received_messages_.emplace_back(data);
    return 1;
  }

  mg_connection *conn;
  char error_buffer[100];
  static std::vector<std::string> received_messages_;
};
std::vector<std::string> MockClient::received_messages_;

static WebSocketHandler handler("Test");

TEST(WebSocketTest, IntegrationTest) {
  // NOTE: Here a magic number is picked up as the port, which is not ideal but
  // in almost all cases this should be fine for a small integration test.
  CivetServer server({"listening_ports", "32695"});
  server.addWebSocketHandler("/websocket", handler);

  // Wait for a small amount of time to make sure that the server is up.
  std::this_thread::sleep_for(std::chrono::milliseconds(300));

  MockClient client("localhost", 32695);

  // Wait for a small amount of time to make sure that the client is up and
  // connected.
  std::this_thread::sleep_for(std::chrono::milliseconds(300));

  // Send 3 messages.
  for (int i = 0; i < 3; ++i) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    handler.BroadcastData(std::to_string(i));
  }

  std::this_thread::sleep_for(std::chrono::milliseconds(200));

  // Check that the 3 messages are successfully received and processed.
  EXPECT_THAT(client.GetReceivedMessages(), ElementsAre("0", "1", "2"));
}

TEST(WebSocketTest, handleData) {
  // NOTE: Here a magic number is picked up as the port, which is not ideal but
  // in almost all cases this should be fine for a small integration test.
  CivetServer server({"listening_ports", "32695"});
  server.addWebSocketHandler("/websocket", handler);
  handler.RegisterMessageHandler("test",
                                 [this](const WebSocketHandler::Json &json,
                                        WebSocketHandler::Connection *conn) {
                                   AINFO << "Received test request.";
                                 });

  // Wait for a small amount of time to make sure that the server is up.
  std::this_thread::sleep_for(std::chrono::milliseconds(300));

  mg_connection *conn;
  std::string data = "{\"type\":\"test\"}";
  char *data_char = const_cast<char *>(data.c_str());
  EXPECT_TRUE(
      handler.handleData(&server, conn, 0x81, data_char, data.length()));
}

}  // namespace dreamview
}  // namespace apollo
<|endoftext|>


<commit_before>/* Copyright 2007-2015 QReal Research Group
 *
 * 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 "interpreterCore/interpreter/interpreter.h"

#include <QtCore/QCoreApplication>
#include <QtWidgets/QAction>

#include <qrtext/languageToolboxInterface.h>

#include <utils/timelineInterface.h>
#include <kitBase/robotModel/robotModelInterface.h>

using namespace qReal;
using namespace interpreterCore::interpreter;
using namespace kitBase::robotModel;

const Id startingElementType = Id("RobotsMetamodel", "RobotsDiagram", "InitialNode");
const int maxThreadsCount = 100;

Interpreter::Interpreter(const GraphicalModelAssistInterface &graphicalModelApi
		, LogicalModelAssistInterface &logicalModelApi
		, qReal::gui::MainWindowInterpretersInterface &interpretersInterface
		, const qReal::ProjectManagementInterface &projectManager
		, BlocksFactoryManagerInterface &blocksFactoryManager
		, const kitBase::robotModel::RobotModelManagerInterface &robotModelManager
		, qrtext::LanguageToolboxInterface &languageToolbox
		, QAction &connectToRobotAction
		)
	: mGraphicalModelApi(graphicalModelApi)
	, mLogicalModelApi(logicalModelApi)
	, mInterpretersInterface(interpretersInterface)
	, mState(idle)
	, mRobotModelManager(robotModelManager)
	, mBlocksTable(new details::BlocksTable(blocksFactoryManager, robotModelManager))
	, mActionConnectToRobot(connectToRobotAction)
	, mSensorVariablesUpdater(robotModelManager, languageToolbox)
	, mAutoconfigurer(mGraphicalModelApi, *mBlocksTable, *mInterpretersInterface.errorReporter())
	, mLanguageToolbox(languageToolbox)
{
	// Other components may want to subscribe to allDevicesConfigured() signal because
	// it seems to be the only way to perform robot devices additional initialization.
	// We must let them work out before interpretation starts, so creating queued connection.
	connect(
			&mRobotModelManager
			, &kitBase::robotModel::RobotModelManagerInterface::allDevicesConfigured
			, this
			, &Interpreter::devicesConfiguredSlot
			, Qt::QueuedConnection
			);

	connect(
			&mRobotModelManager
			, &kitBase::robotModel::RobotModelManagerInterface::connected
			, this
			, &Interpreter::connectedSlot
			);

	connect(&projectManager, &qReal::ProjectManagementInterface::beforeOpen, this, &Interpreter::userStopRobot);

	connectDevicesConfigurationProvider(&mAutoconfigurer);
}

Interpreter::~Interpreter()
{
	qDeleteAll(mThreads);
	delete mBlocksTable;
}

void Interpreter::interpret()
{
	mInterpretersInterface.errorReporter()->clear();

	if (mRobotModelManager.model().connectionState() != RobotModelInterface::connectedState) {
		mInterpretersInterface.errorReporter()->addInformation(tr("No connection to robot"));
		return;
	}

	if (mState != idle) {
		mInterpretersInterface.errorReporter()->addInformation(tr("Interpreter is already running"));
		return;
	}

	mRobotModelManager.model().stopRobot();
	mBlocksTable->clear();
	mState = waitingForDevicesConfiguredToLaunch;

	if (!mAutoconfigurer.configure(mGraphicalModelApi.children(Id::rootId()), mRobotModelManager.model().robotId())) {
		return;
	}

	mLanguageToolbox.clear();

	/// @todo Temporarily loading initial configuration from a network of SensorConfigurationProviders.
	///       To be done more adequately.
	const QString modelName = mRobotModelManager.model().robotId();
	for (const PortInfo &port : mRobotModelManager.model().configurablePorts()) {
		const DeviceInfo deviceInfo = currentConfiguration(modelName, port);
		mRobotModelManager.model().configureDevice(port, deviceInfo);
	}

	mRobotModelManager.model().applyConfiguration();
}

void Interpreter::stopRobot(qReal::interpretation::StopReason reason)
{
	mSensorVariablesUpdater.suspend();
	mRobotModelManager.model().stopRobot();
	mState = idle;
	qDeleteAll(mThreads);
	mThreads.clear();
	mBlocksTable->setFailure();
	emit stopped(reason);
}

int Interpreter::timeElapsed() const
{
	return mState == interpreting
			? mRobotModelManager.model().timeline().timestamp() - mInterpretationStartedTimestamp
			: 0;
}

void Interpreter::connectedSlot(bool success, const QString &errorString)
{
	if (success) {
		if (mRobotModelManager.model().needsConnection()) {
			mInterpretersInterface.errorReporter()->addInformation(tr("Connected successfully"));
		}
	} else {
		if (errorString.isEmpty()) {
			mInterpretersInterface.errorReporter()->addError(tr("Can't connect to a robot."));
		} else {
			mInterpretersInterface.errorReporter()->addError(errorString);
		}
	}

	mActionConnectToRobot.setChecked(success);
}

void Interpreter::devicesConfiguredSlot()
{
	if (mRobotModelManager.model().connectionState() != RobotModelInterface::connectedState) {
		mInterpretersInterface.errorReporter()->addInformation(tr("No connection to robot"));
		mState = idle;
		return;
	}

	if (mState == waitingForDevicesConfiguredToLaunch) {
		mState = interpreting;
		mInterpretationStartedTimestamp = mRobotModelManager.model().timeline().timestamp();

		mSensorVariablesUpdater.run();

		const Id &currentDiagramId = mInterpretersInterface.activeDiagram();

		qReal::interpretation::Thread * const initialThread = new qReal::interpretation::Thread(&mGraphicalModelApi
				, mInterpretersInterface, startingElementType, currentDiagramId, *mBlocksTable, "main");

		emit started();

		addThread(initialThread, "main");
	}
}

void Interpreter::threadStopped(qReal::interpretation::StopReason reason)
{
	qReal::interpretation::Thread * const thread = static_cast<qReal::interpretation::Thread *>(sender());

	mThreads.remove(thread->id());
	delete thread;

	if (mThreads.isEmpty()) {
		stopRobot(reason);
	}
}

void Interpreter::newThread(const Id &startBlockId, const QString &threadId)
{
	if (mThreads.contains(threadId)) {
		reportError(tr("Cannot create new thread with already occupied id %1").arg(threadId));
		stopRobot(qReal::interpretation::StopReason::error);
		return;
	}

	qReal::interpretation::Thread * const thread = new qReal::interpretation::Thread(&mGraphicalModelApi
			, mInterpretersInterface, startingElementType, *mBlocksTable, startBlockId, threadId);

	addThread(thread, threadId);
}

void Interpreter::addThread(qReal::interpretation::Thread * const thread, const QString &threadId)
{
	if (mThreads.count() >= maxThreadsCount) {
		reportError(tr("Threads limit exceeded. Maximum threads count is %1").arg(maxThreadsCount));
		stopRobot(qReal::interpretation::StopReason::error);
	}

	mThreads[threadId] = thread;
	connect(thread, &interpretation::Thread::stopped, this, &Interpreter::threadStopped);

	connect(thread, &qReal::interpretation::Thread::newThread, this, &Interpreter::newThread);
	connect(thread, &qReal::interpretation::Thread::killThread, this, &Interpreter::killThread);
	connect(thread, &qReal::interpretation::Thread::sendMessage, this, &Interpreter::sendMessage);

	QCoreApplication::processEvents();
	if (mState != idle) {
		thread->interpret();
	}
}

void Interpreter::killThread(const QString &threadId)
{
	if (mThreads.contains(threadId)) {
		mThreads[threadId]->stop();
	} else {
		reportError(tr("Killing non-existent thread %1").arg(threadId));
	}
}

void Interpreter::sendMessage(const QString &threadId, const QString &message)
{
	if (mThreads.contains(threadId)) {
		mThreads[threadId]->newMessage(message);
	}
}

void Interpreter::connectToRobot()
{
	if (mState == interpreting) {
		return;
	}

	if (mRobotModelManager.model().connectionState() == RobotModelInterface::connectedState) {
		mRobotModelManager.model().stopRobot();
		mRobotModelManager.model().disconnectFromRobot();
	} else {
		mRobotModelManager.model().connectToRobot();
	}

	mActionConnectToRobot.setChecked(
			mRobotModelManager.model().connectionState() == RobotModelInterface::connectedState);
}

void Interpreter::reportError(const QString &message)
{
	mInterpretersInterface.errorReporter()->addError(message);
}
<commit_msg>Fixed interpreter is already running error after sensors configuration conflict<commit_after>/* Copyright 2007-2015 QReal Research Group
 *
 * 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 "interpreterCore/interpreter/interpreter.h"

#include <QtCore/QCoreApplication>
#include <QtWidgets/QAction>

#include <qrtext/languageToolboxInterface.h>

#include <utils/timelineInterface.h>
#include <kitBase/robotModel/robotModelInterface.h>

using namespace qReal;
using namespace interpreterCore::interpreter;
using namespace kitBase::robotModel;

const Id startingElementType = Id("RobotsMetamodel", "RobotsDiagram", "InitialNode");
const int maxThreadsCount = 100;

Interpreter::Interpreter(const GraphicalModelAssistInterface &graphicalModelApi
		, LogicalModelAssistInterface &logicalModelApi
		, qReal::gui::MainWindowInterpretersInterface &interpretersInterface
		, const qReal::ProjectManagementInterface &projectManager
		, BlocksFactoryManagerInterface &blocksFactoryManager
		, const kitBase::robotModel::RobotModelManagerInterface &robotModelManager
		, qrtext::LanguageToolboxInterface &languageToolbox
		, QAction &connectToRobotAction
		)
	: mGraphicalModelApi(graphicalModelApi)
	, mLogicalModelApi(logicalModelApi)
	, mInterpretersInterface(interpretersInterface)
	, mState(idle)
	, mRobotModelManager(robotModelManager)
	, mBlocksTable(new details::BlocksTable(blocksFactoryManager, robotModelManager))
	, mActionConnectToRobot(connectToRobotAction)
	, mSensorVariablesUpdater(robotModelManager, languageToolbox)
	, mAutoconfigurer(mGraphicalModelApi, *mBlocksTable, *mInterpretersInterface.errorReporter())
	, mLanguageToolbox(languageToolbox)
{
	// Other components may want to subscribe to allDevicesConfigured() signal because
	// it seems to be the only way to perform robot devices additional initialization.
	// We must let them work out before interpretation starts, so creating queued connection.
	connect(
			&mRobotModelManager
			, &kitBase::robotModel::RobotModelManagerInterface::allDevicesConfigured
			, this
			, &Interpreter::devicesConfiguredSlot
			, Qt::QueuedConnection
			);

	connect(
			&mRobotModelManager
			, &kitBase::robotModel::RobotModelManagerInterface::connected
			, this
			, &Interpreter::connectedSlot
			);

	connect(&projectManager, &qReal::ProjectManagementInterface::beforeOpen, this, &Interpreter::userStopRobot);

	connectDevicesConfigurationProvider(&mAutoconfigurer);
}

Interpreter::~Interpreter()
{
	qDeleteAll(mThreads);
	delete mBlocksTable;
}

void Interpreter::interpret()
{
	mInterpretersInterface.errorReporter()->clear();

	if (mRobotModelManager.model().connectionState() != RobotModelInterface::connectedState) {
		mInterpretersInterface.errorReporter()->addInformation(tr("No connection to robot"));
		return;
	}

	if (mState != idle) {
		mInterpretersInterface.errorReporter()->addInformation(tr("Interpreter is already running"));
		return;
	}

	mRobotModelManager.model().stopRobot();
	mBlocksTable->clear();
	mState = waitingForDevicesConfiguredToLaunch;

	if (!mAutoconfigurer.configure(mGraphicalModelApi.children(Id::rootId()), mRobotModelManager.model().robotId())) {
		mState = idle;
		return;
	}

	mLanguageToolbox.clear();

	/// @todo Temporarily loading initial configuration from a network of SensorConfigurationProviders.
	///       To be done more adequately.
	const QString modelName = mRobotModelManager.model().robotId();
	for (const PortInfo &port : mRobotModelManager.model().configurablePorts()) {
		const DeviceInfo deviceInfo = currentConfiguration(modelName, port);
		mRobotModelManager.model().configureDevice(port, deviceInfo);
	}

	mRobotModelManager.model().applyConfiguration();
}

void Interpreter::stopRobot(qReal::interpretation::StopReason reason)
{
	mSensorVariablesUpdater.suspend();
	mRobotModelManager.model().stopRobot();
	mState = idle;
	qDeleteAll(mThreads);
	mThreads.clear();
	mBlocksTable->setFailure();
	emit stopped(reason);
}

int Interpreter::timeElapsed() const
{
	return mState == interpreting
			? mRobotModelManager.model().timeline().timestamp() - mInterpretationStartedTimestamp
			: 0;
}

void Interpreter::connectedSlot(bool success, const QString &errorString)
{
	if (success) {
		if (mRobotModelManager.model().needsConnection()) {
			mInterpretersInterface.errorReporter()->addInformation(tr("Connected successfully"));
		}
	} else {
		if (errorString.isEmpty()) {
			mInterpretersInterface.errorReporter()->addError(tr("Can't connect to a robot."));
		} else {
			mInterpretersInterface.errorReporter()->addError(errorString);
		}
	}

	mActionConnectToRobot.setChecked(success);
}

void Interpreter::devicesConfiguredSlot()
{
	if (mRobotModelManager.model().connectionState() != RobotModelInterface::connectedState) {
		mInterpretersInterface.errorReporter()->addInformation(tr("No connection to robot"));
		mState = idle;
		return;
	}

	if (mState == waitingForDevicesConfiguredToLaunch) {
		mState = interpreting;
		mInterpretationStartedTimestamp = mRobotModelManager.model().timeline().timestamp();

		mSensorVariablesUpdater.run();

		const Id &currentDiagramId = mInterpretersInterface.activeDiagram();

		qReal::interpretation::Thread * const initialThread = new qReal::interpretation::Thread(&mGraphicalModelApi
				, mInterpretersInterface, startingElementType, currentDiagramId, *mBlocksTable, "main");

		emit started();

		addThread(initialThread, "main");
	}
}

void Interpreter::threadStopped(qReal::interpretation::StopReason reason)
{
	qReal::interpretation::Thread * const thread = static_cast<qReal::interpretation::Thread *>(sender());

	mThreads.remove(thread->id());
	delete thread;

	if (mThreads.isEmpty()) {
		stopRobot(reason);
	}
}

void Interpreter::newThread(const Id &startBlockId, const QString &threadId)
{
	if (mThreads.contains(threadId)) {
		reportError(tr("Cannot create new thread with already occupied id %1").arg(threadId));
		stopRobot(qReal::interpretation::StopReason::error);
		return;
	}

	qReal::interpretation::Thread * const thread = new qReal::interpretation::Thread(&mGraphicalModelApi
			, mInterpretersInterface, startingElementType, *mBlocksTable, startBlockId, threadId);

	addThread(thread, threadId);
}

void Interpreter::addThread(qReal::interpretation::Thread * const thread, const QString &threadId)
{
	if (mThreads.count() >= maxThreadsCount) {
		reportError(tr("Threads limit exceeded. Maximum threads count is %1").arg(maxThreadsCount));
		stopRobot(qReal::interpretation::StopReason::error);
	}

	mThreads[threadId] = thread;
	connect(thread, &interpretation::Thread::stopped, this, &Interpreter::threadStopped);

	connect(thread, &qReal::interpretation::Thread::newThread, this, &Interpreter::newThread);
	connect(thread, &qReal::interpretation::Thread::killThread, this, &Interpreter::killThread);
	connect(thread, &qReal::interpretation::Thread::sendMessage, this, &Interpreter::sendMessage);

	QCoreApplication::processEvents();
	if (mState != idle) {
		thread->interpret();
	}
}

void Interpreter::killThread(const QString &threadId)
{
	if (mThreads.contains(threadId)) {
		mThreads[threadId]->stop();
	} else {
		reportError(tr("Killing non-existent thread %1").arg(threadId));
	}
}

void Interpreter::sendMessage(const QString &threadId, const QString &message)
{
	if (mThreads.contains(threadId)) {
		mThreads[threadId]->newMessage(message);
	}
}

void Interpreter::connectToRobot()
{
	if (mState == interpreting) {
		return;
	}

	if (mRobotModelManager.model().connectionState() == RobotModelInterface::connectedState) {
		mRobotModelManager.model().stopRobot();
		mRobotModelManager.model().disconnectFromRobot();
	} else {
		mRobotModelManager.model().connectToRobot();
	}

	mActionConnectToRobot.setChecked(
			mRobotModelManager.model().connectionState() == RobotModelInterface::connectedState);
}

void Interpreter::reportError(const QString &message)
{
	mInterpretersInterface.errorReporter()->addError(message);
}
<|endoftext|>