<commit_before>/************************************
 * file enc : utf8
 * author   : wuyanyi09@gmail.com
************************************/
#include "KeyWordExt.h"

namespace CppJieba
{

	KeyWordExt::KeyWordExt()
	{
	}

	KeyWordExt::~KeyWordExt()
	{
	}

	bool KeyWordExt::init()
	{
		return _segment.init();
	}

	bool KeyWordExt::loadSegDict(const string& filePath)
	{
		return _segment.loadSegDict(filePath);
	}

	bool KeyWordExt::loadPriorSubWords(const string& filePath)
	{
		LogInfo(string_format("loadPriorSubWords(%s) start", filePath.c_str()));
		if(!checkFileExist(filePath.c_str()))
		{
			LogError(string_format("cann't find file[%s].",filePath.c_str()));
			return false;
		}
		if(!_priorSubWords.empty())
		{
			LogError("_priorSubWords has been initted before");
			return false;
		}
		ifstream infile(filePath.c_str());
		string subword;
		while(getline(infile, subword))
		{
			_priorSubWords.push_back(subword);
		}
		LogInfo(string_format("loadPriorSubWords(%s) end", filePath.c_str()));
		infile.close();
		return true;
	}

	bool KeyWordExt::loadStopWords(const string& filePath)
	{

		LogInfo(string_format("loadStopWords(%s) start", filePath.c_str()));
		if(!_stopWords.empty())
		{
			LogError("_stopWords has been loaded before! ");
			return false;
		}
		if(!checkFileExist(filePath.c_str()))
		{
			LogError(string_format("cann't find file[%s].",filePath.c_str()));
			return false;
		}

		ifstream ifile(filePath.c_str());
		string line;
		while(getline(ifile, line))
		{
			_stopWords.insert(line);
		}
		LogInfo(string_format("load stopwords[%d] finished.", _stopWords.size()));

		return true;
	}

	bool KeyWordExt::dispose()
	{
		_segment.dispose();
		return true;
	}

	bool KeyWordExt::_wordInfoCompare(const WordInfo& a, const WordInfo& b)
	{
		return a.weight > b.weight;
	}

	bool KeyWordExt::_sortWLIDF(vector<WordInfo>& wordInfos)
	{
		//size_t wLenSum = 0;
		for(uint i = 0; i < wordInfos.size(); i++)
		{
			wordInfos[i].wLen = gEncoding.getWordLength(wordInfos[i].word);
			if(0 == wordInfos[i].wLen)
			{
				LogFatal("wLen is 0");
				return false;
			}
			//wLenSum += wordInfos[i].wLen;
		}

		/*
		if(0 == wLenSum)
		{
			LogFatal("wLenSum == 0.");
			return false;
		}*/

		for(uint i = 0; i < wordInfos.size(); i++)
		{
			WordInfo& wInfo = wordInfos[i];
			double logWordFreq = _segment.getWordWeight(wInfo.word);
			wInfo.idf = -logWordFreq;
			size_t wLen = gEncoding.getWordLength(wInfo.word);
			if(0 == wLen)
			{
				LogFatal("getUtf8WordLen(%s) return 0");
			}
			wInfo.weight = log(double(wLen + 1)) * wInfo.idf;
		}
		sort(wordInfos.begin(), wordInfos.end(), _wordInfoCompare);
		return true;
	}

	bool KeyWordExt::_extractTopN(const vector<string>& words, vector<string>& keywords, uint topN)
	{
		keywords.clear();
		vector<WordInfo> wordInfos;
		for(uint i = 0; i < words.size(); i++)
		{
			WordInfo wInfo;
			wInfo.word = words[i];
			wordInfos.push_back(wInfo);
		}

		_sortWLIDF(wordInfos);
		LogDebug(string_format("calc weight & sorted:%s",joinWordInfos(wordInfos).c_str()));

		_prioritizeSubWords(wordInfos);
		//LogDebug(string_format("_prioritizeSubWords res:%s", joinWordInfos(wordInfos).c_str()));
		//extract TopN
		for(uint i = 0; i < topN && i < wordInfos.size(); i++)
		{
			keywords.push_back(wordInfos[i].word);
		}
		return true;
	}

	bool KeyWordExt::extract(const string& title, vector<string>& keywords, uint topN)
	{
		LogDebug(string_format("title:[%s]",title.c_str()));

		bool retFlag;
		vector<string> words;
		retFlag = _segment.cutDAG(title, words);
		if(!retFlag)
		{
			LogError(string_format("cutDAG(%s) failed.", title.c_str()));
			return false;
		}
		LogDebug(string_format("cutDAG result:[%s]", joinStr(words, ",").c_str()));

		retFlag = _filter(words);
		if(!retFlag)
		{
			LogError("_filter failed.");
			return false;
		}
		LogDebug(string_format("_filter res:[%s]", joinStr(words, ",").c_str()));

		retFlag = _extractTopN(words, keywords, topN);
		if(!retFlag)
		{
			LogError("_extractTopN failed.");
			return false;
		}
		//LogDebug("_extractTopN finished.");

		LogDebug(string_format("ext res:[%s]", joinStr(keywords, ",").c_str()));
		return true;
	}

	bool KeyWordExt::_filter(vector<string>& strs)
	{
		bool retFlag;
		retFlag = _filterDuplicate(strs);
		if(!retFlag)
		{
			LogError("_filterDuplicate failed.");
			return false;
		}
		//LogDebug(string_format("_filterDuplicate res:[%s]", joinStr(strs, ",").c_str()));

		retFlag = _filterSingleWord(strs);
		if(!retFlag)
		{
			LogError("_filterSingleWord failed.");
			return false;
		}
		//LogDebug(string_format("_filterSingleWord res:[%s]", joinStr(strs, ",").c_str()));

		retFlag = _filterStopWords(strs);
		if(!retFlag)
		{
			LogError("_filterStopWords failed.");
			return false;
		}
		//LogDebug(string_format("_filterStopWords res:[%s]", joinStr(strs, ",").c_str()));

		retFlag = _filterSubstr(strs);
		if(!retFlag)
		{
			LogError("_filterSubstr failed.");
			return false;
		}
		//LogDebug(string_format("_filterSubstr res:[%s]", joinStr(strs, ",").c_str()));

		return true;
	}

	bool KeyWordExt::_filterStopWords(vector<string>& strs)
	{
		if(_stopWords.empty())
		{
			return true;
		}
		for(VSI it = strs.begin(); it != strs.end();)
		{
			if(_stopWords.find(*it) != _stopWords.end())
			{
				it = strs.erase(it);
			}
			else
			{
				it ++;
			}
		}
		return true;
	}

	bool KeyWordExt::_filterDuplicate(vector<string>& strs)
	{
		set<string> st;
		for(VSI it = strs.begin(); it != strs.end(); )
		{
			if(st.find(*it) != st.end())
			{
				it = strs.erase(it);
			}
			else
			{
				st.insert(*it);
				it++;
			}
		}
		return true;
	}

	bool KeyWordExt::_filterSingleWord(vector<string>& strs)
	{
		for(vector<string>::iterator it = strs.begin(); it != strs.end();)
		{

			// filter single word
			if(1 == gEncoding.getWordLength(*it))
			{
				it = strs.erase(it);
			}
			else
			{
				it++;
			}
		}
		return true;
	}

	bool KeyWordExt::_filterSubstr(vector<string>& strs)
	{
		vector<string> tmp = strs;
		set<string> subs;
		for(VSI it = strs.begin(); it != strs.end(); it ++)
		{
			for(uint j = 0; j < tmp.size(); j++)
			{
				if(*it != tmp[j] && string::npos != tmp[j].find(*it, 0))
				{
					subs.insert(*it);
				}
			}
		}

		//erase subs from strs
		for(VSI it = strs.begin(); it != strs.end(); )
		{
			if(subs.end() != subs.find(*it))
			{
				LogDebug(string_format("_filterSubstr filter [%s].", it->c_str()));
				it =  strs.erase(it);
			}
			else
			{
				it ++;
			}
		}
		return true;
	}

	bool KeyWordExt::_isContainSubWords(const string& word)
	{
		for(uint i = 0; i < _priorSubWords.size(); i++)
		{
			if(string::npos != word.find(_priorSubWords[i]))
			{
				return true;
			}
		}
		return false;
	}

	bool KeyWordExt::_prioritizeSubWords(vector<WordInfo>& wordInfos)
	{
		if(2 > wordInfos.size())
		{
			return true;
		}

		WordInfo prior;
		bool flag = false;
		for(vector<WordInfo>::iterator it = wordInfos.begin(); it != wordInfos.end(); )
		{
			if(_isContainSubWords(it->word))
			{
				prior = *it;
				it = wordInfos.erase(it);
				flag = true;
				break;
			}
			else
			{
				it ++;
			}
		}
		if(flag)
		{
			wordInfos.insert(wordInfos.begin(), prior);
		}
		return true;
	}
}

#ifdef KEYWORDEXT_UT

using namespace CppJieba;

int main()
{
	gEncoding.setEncoding(GBKENC);
	KeyWordExt ext;
	ext.init();
	if(!ext.loadSegDict("../dicts/segdict.gbk.v2.1"))
	{
		return 1;
	}
	ext.loadStopWords("stopwords.tmp");

	if(!ext.loadPriorSubWords("prior.gbk"))
	{
		cerr<<"err"<<endl;
		return 1;
	}

	ifstream ifile("testtitle.gbk");
	vector<string> res;
	string line;
	while(getline(ifile, line))
	{
		cout<<line<<endl;
		res.clear();
		ext.extract(line, res, 20);
		PRINT_VECTOR(res);
	}

	ext.dispose();
	return 0;
}

#endif
<commit_msg>remove debug<commit_after>/************************************
 * file enc : utf8
 * author   : wuyanyi09@gmail.com
************************************/
#include "KeyWordExt.h"

namespace CppJieba
{

	KeyWordExt::KeyWordExt()
	{
	}

	KeyWordExt::~KeyWordExt()
	{
	}

	bool KeyWordExt::init()
	{
		return _segment.init();
	}

	bool KeyWordExt::loadSegDict(const string& filePath)
	{
		return _segment.loadSegDict(filePath);
	}

	bool KeyWordExt::loadPriorSubWords(const string& filePath)
	{
		LogInfo(string_format("loadPriorSubWords(%s) start", filePath.c_str()));
		if(!checkFileExist(filePath.c_str()))
		{
			LogError(string_format("cann't find file[%s].",filePath.c_str()));
			return false;
		}
		if(!_priorSubWords.empty())
		{
			LogError("_priorSubWords has been initted before");
			return false;
		}
		ifstream infile(filePath.c_str());
		string subword;
		while(getline(infile, subword))
		{
			_priorSubWords.push_back(subword);
		}
		LogInfo(string_format("loadPriorSubWords(%s) end", filePath.c_str()));
		infile.close();
		return true;
	}

	bool KeyWordExt::loadStopWords(const string& filePath)
	{

		LogInfo(string_format("loadStopWords(%s) start", filePath.c_str()));
		if(!_stopWords.empty())
		{
			LogError("_stopWords has been loaded before! ");
			return false;
		}
		if(!checkFileExist(filePath.c_str()))
		{
			LogError(string_format("cann't find file[%s].",filePath.c_str()));
			return false;
		}

		ifstream ifile(filePath.c_str());
		string line;
		while(getline(ifile, line))
		{
			_stopWords.insert(line);
		}
		LogInfo(string_format("load stopwords[%d] finished.", _stopWords.size()));

		return true;
	}

	bool KeyWordExt::dispose()
	{
		_segment.dispose();
		return true;
	}

	bool KeyWordExt::_wordInfoCompare(const WordInfo& a, const WordInfo& b)
	{
		return a.weight > b.weight;
	}

	bool KeyWordExt::_sortWLIDF(vector<WordInfo>& wordInfos)
	{
		//size_t wLenSum = 0;
		for(uint i = 0; i < wordInfos.size(); i++)
		{
			wordInfos[i].wLen = gEncoding.getWordLength(wordInfos[i].word);
			if(0 == wordInfos[i].wLen)
			{
				LogFatal("wLen is 0");
				return false;
			}
			//wLenSum += wordInfos[i].wLen;
		}

		/*
		if(0 == wLenSum)
		{
			LogFatal("wLenSum == 0.");
			return false;
		}*/

		for(uint i = 0; i < wordInfos.size(); i++)
		{
			WordInfo& wInfo = wordInfos[i];
			double logWordFreq = _segment.getWordWeight(wInfo.word);
			wInfo.idf = -logWordFreq;
			size_t wLen = gEncoding.getWordLength(wInfo.word);
			if(0 == wLen)
			{
				LogFatal("getUtf8WordLen(%s) return 0");
			}
			wInfo.weight = log(double(wLen + 1)) * wInfo.idf;
		}
		sort(wordInfos.begin(), wordInfos.end(), _wordInfoCompare);
		return true;
	}

	bool KeyWordExt::_extractTopN(const vector<string>& words, vector<string>& keywords, uint topN)
	{
		keywords.clear();
		vector<WordInfo> wordInfos;
		for(uint i = 0; i < words.size(); i++)
		{
			WordInfo wInfo;
			wInfo.word = words[i];
			wordInfos.push_back(wInfo);
		}

		_sortWLIDF(wordInfos);
		//LogDebug(string_format("calc weight & sorted:%s",joinWordInfos(wordInfos).c_str()));

		_prioritizeSubWords(wordInfos);
		//LogDebug(string_format("_prioritizeSubWords res:%s", joinWordInfos(wordInfos).c_str()));
		//extract TopN
		for(uint i = 0; i < topN && i < wordInfos.size(); i++)
		{
			keywords.push_back(wordInfos[i].word);
		}
		return true;
	}

	bool KeyWordExt::extract(const string& title, vector<string>& keywords, uint topN)
	{
		//LogDebug(string_format("title:[%s]",title.c_str()));

		bool retFlag;
		vector<string> words;
		retFlag = _segment.cutDAG(title, words);
		if(!retFlag)
		{
			LogError(string_format("cutDAG(%s) failed.", title.c_str()));
			return false;
		}
		//LogDebug(string_format("cutDAG result:[%s]", joinStr(words, ",").c_str()));

		retFlag = _filter(words);
		if(!retFlag)
		{
			LogError("_filter failed.");
			return false;
		}
		//LogDebug(string_format("_filter res:[%s]", joinStr(words, ",").c_str()));

		retFlag = _extractTopN(words, keywords, topN);
		if(!retFlag)
		{
			LogError("_extractTopN failed.");
			return false;
		}
		//LogDebug("_extractTopN finished.");

		//LogDebug(string_format("ext res:[%s]", joinStr(keywords, ",").c_str()));
		return true;
	}

	bool KeyWordExt::_filter(vector<string>& strs)
	{
		bool retFlag;
		retFlag = _filterDuplicate(strs);
		if(!retFlag)
		{
			LogError("_filterDuplicate failed.");
			return false;
		}
		//LogDebug(string_format("_filterDuplicate res:[%s]", joinStr(strs, ",").c_str()));

		retFlag = _filterSingleWord(strs);
		if(!retFlag)
		{
			LogError("_filterSingleWord failed.");
			return false;
		}
		//LogDebug(string_format("_filterSingleWord res:[%s]", joinStr(strs, ",").c_str()));

		retFlag = _filterStopWords(strs);
		if(!retFlag)
		{
			LogError("_filterStopWords failed.");
			return false;
		}
		//LogDebug(string_format("_filterStopWords res:[%s]", joinStr(strs, ",").c_str()));

		retFlag = _filterSubstr(strs);
		if(!retFlag)
		{
			LogError("_filterSubstr failed.");
			return false;
		}
		//LogDebug(string_format("_filterSubstr res:[%s]", joinStr(strs, ",").c_str()));

		return true;
	}

	bool KeyWordExt::_filterStopWords(vector<string>& strs)
	{
		if(_stopWords.empty())
		{
			return true;
		}
		for(VSI it = strs.begin(); it != strs.end();)
		{
			if(_stopWords.find(*it) != _stopWords.end())
			{
				it = strs.erase(it);
			}
			else
			{
				it ++;
			}
		}
		return true;
	}

	bool KeyWordExt::_filterDuplicate(vector<string>& strs)
	{
		set<string> st;
		for(VSI it = strs.begin(); it != strs.end(); )
		{
			if(st.find(*it) != st.end())
			{
				it = strs.erase(it);
			}
			else
			{
				st.insert(*it);
				it++;
			}
		}
		return true;
	}

	bool KeyWordExt::_filterSingleWord(vector<string>& strs)
	{
		for(vector<string>::iterator it = strs.begin(); it != strs.end();)
		{

			// filter single word
			if(1 == gEncoding.getWordLength(*it))
			{
				it = strs.erase(it);
			}
			else
			{
				it++;
			}
		}
		return true;
	}

	bool KeyWordExt::_filterSubstr(vector<string>& strs)
	{
		vector<string> tmp = strs;
		set<string> subs;
		for(VSI it = strs.begin(); it != strs.end(); it ++)
		{
			for(uint j = 0; j < tmp.size(); j++)
			{
				if(*it != tmp[j] && string::npos != tmp[j].find(*it, 0))
				{
					subs.insert(*it);
				}
			}
		}

		//erase subs from strs
		for(VSI it = strs.begin(); it != strs.end(); )
		{
			if(subs.end() != subs.find(*it))
			{
				//LogDebug(string_format("_filterSubstr filter [%s].", it->c_str()));
				it =  strs.erase(it);
			}
			else
			{
				it ++;
			}
		}
		return true;
	}

	bool KeyWordExt::_isContainSubWords(const string& word)
	{
		for(uint i = 0; i < _priorSubWords.size(); i++)
		{
			if(string::npos != word.find(_priorSubWords[i]))
			{
				return true;
			}
		}
		return false;
	}

	bool KeyWordExt::_prioritizeSubWords(vector<WordInfo>& wordInfos)
	{
		if(2 > wordInfos.size())
		{
			return true;
		}

		WordInfo prior;
		bool flag = false;
		for(vector<WordInfo>::iterator it = wordInfos.begin(); it != wordInfos.end(); )
		{
			if(_isContainSubWords(it->word))
			{
				prior = *it;
				it = wordInfos.erase(it);
				flag = true;
				break;
			}
			else
			{
				it ++;
			}
		}
		if(flag)
		{
			wordInfos.insert(wordInfos.begin(), prior);
		}
		return true;
	}
}

#ifdef KEYWORDEXT_UT

using namespace CppJieba;

int main()
{
	gEncoding.setEncoding(GBKENC);
	KeyWordExt ext;
	ext.init();
	if(!ext.loadSegDict("../dicts/segdict.gbk.v2.1"))
	{
		return 1;
	}
	ext.loadStopWords("stopwords.tmp");

	if(!ext.loadPriorSubWords("prior.gbk"))
	{
		cerr<<"err"<<endl;
		return 1;
	}

	ifstream ifile("testtitle.gbk");
	vector<string> res;
	string line;
	while(getline(ifile, line))
	{
		cout<<line<<endl;
		res.clear();
		ext.extract(line, res, 20);
		PRINT_VECTOR(res);
	}

	ext.dispose();
	return 0;
}

#endif
<|endoftext|>


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

#include "main_toolbar.h"

#include <wx/intl.h>
#include <wx/toolbar.h>
#include <wx/xrc/xmlres.h>

class WXMainToolbar : public MainToolbar
{
public:
    WXMainToolbar(wxFrame *parent)
    {
        m_tb = wxXmlResource::Get()->LoadToolBar(parent, "toolbar");
        m_idFuzzy = XRCID("menu_fuzzy");
        m_idUpdate = XRCID("toolbar_update");
    }

    bool IsFuzzy() const override
    {
        return m_tb->GetToolState(m_idFuzzy);
    }

    void SetFuzzy(bool on) override
    {
        m_tb->ToggleTool(m_idFuzzy, on);
    }

    void EnableSyncWithCrowdin(bool on) override
    {
        auto tool = m_tb->FindById(m_idUpdate);

        if (on)
        {
            tool->SetLabel(_("Sync"));
            tool->SetShortHelp(_("Synchronize the translation with Crowdin."));
            m_tb->SetToolNormalBitmap(m_idUpdate, wxArtProvider::GetBitmap("poedit-sync"));
        }
        else
        {
            tool->SetLabel(_("Update"));
            tool->SetShortHelp(_("Update catalog - synchronize it with sources"));
            m_tb->SetToolNormalBitmap(m_idUpdate, wxArtProvider::GetBitmap("poedit-update"));
        }
    }

private:
    wxToolBar *m_tb;
    int m_idFuzzy, m_idUpdate;
};

std::unique_ptr<MainToolbar> MainToolbar::CreateWX(wxFrame *parent)
{
    return std::unique_ptr<MainToolbar>(new WXMainToolbar(parent));
}

std::unique_ptr<MainToolbar> MainToolbar::Create(wxFrame *parent)
{
    return CreateWX(parent);
}
<commit_msg>Remove period from tooltip text<commit_after>/*
 *  This file is part of Poedit (http://poedit.net)
 *
 *  Copyright (C) 2014-2015 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

#include "main_toolbar.h"

#include <wx/intl.h>
#include <wx/toolbar.h>
#include <wx/xrc/xmlres.h>

class WXMainToolbar : public MainToolbar
{
public:
    WXMainToolbar(wxFrame *parent)
    {
        m_tb = wxXmlResource::Get()->LoadToolBar(parent, "toolbar");
        m_idFuzzy = XRCID("menu_fuzzy");
        m_idUpdate = XRCID("toolbar_update");
    }

    bool IsFuzzy() const override
    {
        return m_tb->GetToolState(m_idFuzzy);
    }

    void SetFuzzy(bool on) override
    {
        m_tb->ToggleTool(m_idFuzzy, on);
    }

    void EnableSyncWithCrowdin(bool on) override
    {
        auto tool = m_tb->FindById(m_idUpdate);

        if (on)
        {
            tool->SetLabel(_("Sync"));
            tool->SetShortHelp(_("Synchronize the translation with Crowdin"));
            m_tb->SetToolNormalBitmap(m_idUpdate, wxArtProvider::GetBitmap("poedit-sync"));
        }
        else
        {
            tool->SetLabel(_("Update"));
            tool->SetShortHelp(_("Update catalog - synchronize it with sources"));
            m_tb->SetToolNormalBitmap(m_idUpdate, wxArtProvider::GetBitmap("poedit-update"));
        }
    }

private:
    wxToolBar *m_tb;
    int m_idFuzzy, m_idUpdate;
};

std::unique_ptr<MainToolbar> MainToolbar::CreateWX(wxFrame *parent)
{
    return std::unique_ptr<MainToolbar>(new WXMainToolbar(parent));
}

std::unique_ptr<MainToolbar> MainToolbar::Create(wxFrame *parent)
{
    return CreateWX(parent);
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/autofill_manager.h"

#include "base/string_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/web_contents.h"
#include "chrome/common/pref_names.h"

AutofillManager::AutofillManager(WebContents* web_contents) :
    web_contents_(web_contents),
    pending_query_handle_(0),
    node_id_(0),
    request_id_(0) {
  form_autofill_enabled_.Init(prefs::kFormAutofillEnabled,
      profile()->GetPrefs(), NULL);
}

AutofillManager::~AutofillManager() {
  CancelPendingQuery();
}

void AutofillManager::CancelPendingQuery() {
  if (pending_query_handle_) {
    WebDataService* web_data_service =
        profile()->GetWebDataService(Profile::EXPLICIT_ACCESS);
    if (!web_data_service) {
      NOTREACHED();
      return;
    }
    web_data_service->CancelRequest(pending_query_handle_);
  }
  pending_query_handle_ = 0;
}

Profile* AutofillManager::profile() {
  return web_contents_->profile();
}

void AutofillManager::AutofillFormSubmitted(const AutofillForm& form) {
  StoreFormEntriesInWebDatabase(form);
}

void AutofillManager::FetchValuesForName(const std::wstring& name,
                                         const std::wstring& prefix,
                                         int limit,
                                         int64 node_id,
                                         int request_id) {
  if (!*form_autofill_enabled_)
    return;

  WebDataService* web_data_service =
      profile()->GetWebDataService(Profile::EXPLICIT_ACCESS);
  if (!web_data_service) {
    NOTREACHED();
    return;
  }

  CancelPendingQuery();

  node_id_ = node_id;
  request_id_ = request_id;

  pending_query_handle_ = web_data_service->
      GetFormValuesForElementName(name, prefix, limit, this);
}

void AutofillManager::OnWebDataServiceRequestDone(WebDataService::Handle h,
    const WDTypedResult* result) {
  DCHECK(pending_query_handle_);
  pending_query_handle_ = 0;

  if (!*form_autofill_enabled_)
    return;

  DCHECK(result);
  if (!result)
    return;

  switch (result->GetType()) {
    case AUTOFILL_VALUE_RESULT: {
      RenderViewHost* host = web_contents_->render_view_host();
      if (!host)
        return;
      const WDResult<std::vector<std::wstring> >* r =
          static_cast<const WDResult<std::vector<std::wstring> >*>(result);
      std::vector<std::wstring> suggestions = r->GetValue();
      host->AutofillSuggestionsReturned(suggestions, node_id_, request_id_, -1);
      break;
    }

    default:
      NOTREACHED();
      break;
  }
}

void AutofillManager::StoreFormEntriesInWebDatabase(
    const AutofillForm& form) {
  if (!*form_autofill_enabled_)
    return;

  if (profile()->IsOffTheRecord())
    return;

  profile()->GetWebDataService(Profile::EXPLICIT_ACCESS)->
      AddAutofillFormElements(form.elements);
}
<commit_msg>NO CODE CHANGE. Fix EOL in autofill_manager.cc.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/autofill_manager.h"

#include "base/string_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/web_contents.h"
#include "chrome/common/pref_names.h"

AutofillManager::AutofillManager(WebContents* web_contents) :
    web_contents_(web_contents),
    pending_query_handle_(0),
    node_id_(0),
    request_id_(0) {
  form_autofill_enabled_.Init(prefs::kFormAutofillEnabled,
      profile()->GetPrefs(), NULL);
}

AutofillManager::~AutofillManager() {
  CancelPendingQuery();
}

void AutofillManager::CancelPendingQuery() {
  if (pending_query_handle_) {
    WebDataService* web_data_service =
        profile()->GetWebDataService(Profile::EXPLICIT_ACCESS);
    if (!web_data_service) {
      NOTREACHED();
      return;
    }
    web_data_service->CancelRequest(pending_query_handle_);
  }
  pending_query_handle_ = 0;
}

Profile* AutofillManager::profile() {
  return web_contents_->profile();
}

void AutofillManager::AutofillFormSubmitted(const AutofillForm& form) {
  StoreFormEntriesInWebDatabase(form);
}

void AutofillManager::FetchValuesForName(const std::wstring& name,
                                         const std::wstring& prefix,
                                         int limit,
                                         int64 node_id,
                                         int request_id) {
  if (!*form_autofill_enabled_)
    return;

  WebDataService* web_data_service =
      profile()->GetWebDataService(Profile::EXPLICIT_ACCESS);
  if (!web_data_service) {
    NOTREACHED();
    return;
  }

  CancelPendingQuery();

  node_id_ = node_id;
  request_id_ = request_id;

  pending_query_handle_ = web_data_service->
      GetFormValuesForElementName(name, prefix, limit, this);
}

void AutofillManager::OnWebDataServiceRequestDone(WebDataService::Handle h,
    const WDTypedResult* result) {
  DCHECK(pending_query_handle_);
  pending_query_handle_ = 0;

  if (!*form_autofill_enabled_)
    return;

  DCHECK(result);
  if (!result)
    return;

  switch (result->GetType()) {
    case AUTOFILL_VALUE_RESULT: {
      RenderViewHost* host = web_contents_->render_view_host();
      if (!host)
        return;
      const WDResult<std::vector<std::wstring> >* r =
          static_cast<const WDResult<std::vector<std::wstring> >*>(result);
      std::vector<std::wstring> suggestions = r->GetValue();
      host->AutofillSuggestionsReturned(suggestions, node_id_, request_id_, -1);
      break;
    }

    default:
      NOTREACHED();
      break;
  }
}

void AutofillManager::StoreFormEntriesInWebDatabase(
    const AutofillForm& form) {
  if (!*form_autofill_enabled_)
    return;

  if (profile()->IsOffTheRecord())
    return;

  profile()->GetWebDataService(Profile::EXPLICIT_ACCESS)->
      AddAutofillFormElements(form.elements);
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/string_util.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "chrome/browser/net/url_request_failed_dns_job.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "net/url_request/url_request_unittest.h"

class ErrorPageTest : public UITest {
 protected:
  bool WaitForTitleMatching(const std::wstring& title) {
    for (int i = 0; i < 100; ++i) {
      if (GetActiveTabTitle() == title)
        return true;
      PlatformThread::Sleep(sleep_timeout_ms() / 10);
    }
    return false;
  }
  bool WaitForTitleContaining(const std::string& title_substring) {
    for (int i = 0; i < 100; ++i) {
      std::wstring title = GetActiveTabTitle();
      if (title.find(UTF8ToWide(title_substring)) != std::wstring::npos)
        return true;
      PlatformThread::Sleep(sleep_timeout_ms() / 10);
    }
    return false;
  }
};

TEST_F(ErrorPageTest, DNSError_Basic) {
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);

  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
}

TEST_F(ErrorPageTest, DNSError_GoBack1) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));

  GetActiveTab()->GoBack();

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, DNSError_GoBack2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title3.html"));

  // The first navigation should fail, and the second one should be the error
  // page.
  GetActiveTab()->GoBackBlockUntilNavigationsComplete(2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  GetActiveTab()->GoBack();

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title3.html"));

  // The first navigation should fail, and the second one should be the error
  // page.
  GetActiveTab()->GoBackBlockUntilNavigationsComplete(2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  GetActiveTab()->GoBack();
  // The first navigation should fail, and the second one should be the error
  // page.
  GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2);

  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
}

TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title3.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));

  // The first navigation should fail, and the second one should be the error
  // page.
  GetActiveTab()->GoBackBlockUntilNavigationsComplete(2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  GetActiveTab()->GoBack();
  // The first navigation should fail, and the second one should be the error
  // page.
  GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  GetActiveTab()->GoForward();

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"iframe_dns_error.html"));
  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBack) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"iframe_dns_error.html"));

  GetActiveTab()->GoBack();

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBackAndForward) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"iframe_dns_error.html"));

  GetActiveTab()->GoBack();
  GetActiveTab()->GoForward();

  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

TEST_F(ErrorPageTest, IFrame404) {
  // iframes that have 404 pages should not trigger an alternate error page.
  // In this test, the iframe sets the title of the parent page to "SUCCESS"
  // when the iframe loads.  If the iframe fails to load (because an alternate
  // error page loads instead), then the title will remain as "FAIL".
  scoped_refptr<HTTPTestServer> server =
      HTTPTestServer::CreateServer(L"chrome/test/data", NULL);
  ASSERT_TRUE(NULL != server.get());
  GURL test_url = server->TestServerPage("files/iframe404.html");
  NavigateToURL(test_url);

  EXPECT_TRUE(WaitForTitleMatching(L"SUCCESS"));
}

TEST_F(ErrorPageTest, Page404) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(
      URLRequestMockHTTPJob::GetMockUrl(L"page404.html"), 2);

  EXPECT_TRUE(WaitForTitleContaining("page404.html"));
}

TEST_F(ErrorPageTest, Page404_GoBack) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(
      URLRequestMockHTTPJob::GetMockUrl(L"page404.html"), 2);
  EXPECT_TRUE(WaitForTitleContaining("page404.html"));

  GetActiveTab()->GoBack();

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}
<commit_msg>Get more info in the logs when ErrorPageTest fails.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/string_util.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "chrome/browser/net/url_request_failed_dns_job.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "net/url_request/url_request_unittest.h"

class ErrorPageTest : public UITest {
 protected:
  bool WaitForTitleMatching(const std::wstring& title) {
    for (int i = 0; i < 100; ++i) {
      if (GetActiveTabTitle() == title)
        return true;
      PlatformThread::Sleep(sleep_timeout_ms() / 10);
    }
    EXPECT_EQ(title, GetActiveTabTitle());
    return false;
  }
  bool WaitForTitleContaining(const std::string& title_substring) {
    for (int i = 0; i < 100; ++i) {
      std::wstring title = GetActiveTabTitle();
      if (title.find(UTF8ToWide(title_substring)) != std::wstring::npos)
        return true;
      PlatformThread::Sleep(sleep_timeout_ms() / 10);
    }
    LOG(ERROR) << "Could not find " << title_substring << " in "
               << GetActiveTabTitle();
    return false;
  }
};

TEST_F(ErrorPageTest, DNSError_Basic) {
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);

  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
}

TEST_F(ErrorPageTest, DNSError_GoBack1) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));

  GetActiveTab()->GoBack();

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, DNSError_GoBack2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title3.html"));

  // The first navigation should fail, and the second one should be the error
  // page.
  GetActiveTab()->GoBackBlockUntilNavigationsComplete(2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  GetActiveTab()->GoBack();

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title3.html"));

  // The first navigation should fail, and the second one should be the error
  // page.
  GetActiveTab()->GoBackBlockUntilNavigationsComplete(2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  GetActiveTab()->GoBack();
  // The first navigation should fail, and the second one should be the error
  // page.
  GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2);

  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
}

TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title3.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));

  // The first navigation should fail, and the second one should be the error
  // page.
  GetActiveTab()->GoBackBlockUntilNavigationsComplete(2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  GetActiveTab()->GoBack();
  // The first navigation should fail, and the second one should be the error
  // page.
  GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2);
  EXPECT_TRUE(WaitForTitleContaining(test_url.host()));
  GetActiveTab()->GoForward();

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"iframe_dns_error.html"));
  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBack) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"iframe_dns_error.html"));

  GetActiveTab()->GoBack();

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBackAndForward) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"iframe_dns_error.html"));

  GetActiveTab()->GoBack();
  GetActiveTab()->GoForward();

  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

TEST_F(ErrorPageTest, IFrame404) {
  // iframes that have 404 pages should not trigger an alternate error page.
  // In this test, the iframe sets the title of the parent page to "SUCCESS"
  // when the iframe loads.  If the iframe fails to load (because an alternate
  // error page loads instead), then the title will remain as "FAIL".
  scoped_refptr<HTTPTestServer> server =
      HTTPTestServer::CreateServer(L"chrome/test/data", NULL);
  ASSERT_TRUE(NULL != server.get());
  GURL test_url = server->TestServerPage("files/iframe404.html");
  NavigateToURL(test_url);

  EXPECT_TRUE(WaitForTitleMatching(L"SUCCESS"));
}

TEST_F(ErrorPageTest, Page404) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(
      URLRequestMockHTTPJob::GetMockUrl(L"page404.html"), 2);

  EXPECT_TRUE(WaitForTitleContaining("page404.html"));
}

TEST_F(ErrorPageTest, Page404_GoBack) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(L"title2.html"));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(
      URLRequestMockHTTPJob::GetMockUrl(L"page404.html"), 2);
  EXPECT_TRUE(WaitForTitleContaining("page404.html"));

  GetActiveTab()->GoBack();

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/time.h>
#include <cassert>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>

#include <FWContextBase.h>
#include <FWPlatformBase.h>
#include <EventLoop.h>
#include <CurlClient.h>

#include <ContextCairo.h>

#include <iostream>

using namespace std;

bool XNextEventTimed(Display * dsp, XEvent * event_return, struct timeval * tv) {
  // optimization

  if (tv == NULL) {
    XNextEvent(dsp, event_return);
    return True;
  }

  // the real deal

  if (XPending(dsp) == 0) {
    int fd = ConnectionNumber(dsp);
    cerr << "nothing pending, fd = " << fd << "\n";
    fd_set readset;
    FD_ZERO(&readset);
    FD_SET(fd, &readset);
    int r = select(fd+1, &readset, NULL, NULL, tv);
    if (r == -1) {
      cerr << "select failed\n";
      return false;
    } else if (r == 0) {
      cerr << "nothing to select\n";
      return false;
    } else {
      cerr << "getting event (r = " << r << ")\n";
      if (XPending(dsp)) {
	XNextEvent(dsp, event_return);
	return true;
      } else {
	return false;
      }
    }
  } else {
    cerr << "pending\n";

    XNextEvent(dsp, event_return);
    return true;
  }
}

class PlatformX11 : public FWPlatformBase {
public:
  PlatformX11() : FWPlatformBase(1.0f,
				 // "#version 300 es",
				 "#version 100",
				 true) { }

  double getTime() const override {
    struct timeval tv;
    struct timezone tz;
    int r = gettimeofday(&tv, &tz);
    double t = 0;
    if (r == 0) {
      t = (double)tv.tv_sec + tv.tv_usec / 1000000.0;
    }
    return t;
  }

  void showMessageBox(const string&, const string&) {

  }
  void postNotification(const string&, const string&) {

  }
  string getLocalFilename(const char * fn, FileType type) {
    string s = "android_projects/assets/";
    return s + fn;
  }

  std::shared_ptr<HTTPClientFactory> createHTTPClientFactory() const {
    return std::make_shared<CurlClientFactory>();
  }

  int showActionSheet(const FWRect&, const FWActionSheet&) {
    return 0;
  }

  bool createWindow(FWContextBase * context, const char* title) override {
    Window root;
    XSetWindowAttributes swa;
    XSetWindowAttributes  xattr;
    Atom wm_state;
    XWMHints hints;
    XEvent xev;
    EGLConfig ecfg;
    EGLint num_config;
    Window win;

    /*
     * X11 native display initialization
     */

    x_display = XOpenDisplay(NULL);
    if (x_display == NULL) {
      return false;
    }

    root = DefaultRootWindow(x_display);

    // esContext->getActualWidth(), esContext->getActualHeight()
    int width = 800;
    int height = 600;

    swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask;
    win = XCreateWindow(
               x_display, root,
               0, 0, width, height, 0,
               CopyFromParent, InputOutput,
               CopyFromParent, CWEventMask,
               &swa );

    xattr.override_redirect = 0;
    XChangeWindowAttributes ( x_display, win, CWOverrideRedirect, &xattr );

    XSelectInput(x_display, win,
		 ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
		 ButtonPressMask | ButtonReleaseMask  | StructureNotifyMask
		 );

    hints.input = 1;
    hints.flags = InputHint;
    XSetWMHints(x_display, win, &hints);

    // make the window visible on the screen
    XMapWindow (x_display, win);
    XStoreName (x_display, win, title);

    // get identifiers for the provided atom name strings
    wm_state = XInternAtom (x_display, "_NET_WM_STATE", 0);

    memset ( &xev, 0, sizeof(xev) );
    xev.type                 = ClientMessage;
    xev.xclient.window       = win;
    xev.xclient.message_type = wm_state;
    xev.xclient.format       = 32;
    xev.xclient.data.l[0]    = 1;
    xev.xclient.data.l[1]    = 0;
    XSendEvent (
       x_display,
       DefaultRootWindow ( x_display ),
       0,
       SubstructureNotifyMask,
       &xev );

    eglNativeWindow = (EGLNativeWindowType) win;
    eglNativeDisplay = (EGLNativeDisplayType) x_display;

    cerr << "native display = " << x_display << endl;

    XFlush(x_display);

    return true;
  }

  std::shared_ptr<canvas::ContextFactory> createContextFactory() const {
    return std::shared_ptr<canvas::ContextFactory>(new canvas::CairoContextFactory);
  }

  std::shared_ptr<EventLoop> createEventLoop() override;

  void showMessageBox(const std::string & message) {

  }

  std::string showTextEntryDialog(const std::string & message) {
    return "";
  }

  void postNotification(const std::string & message) {

  }

  void launchBrowser(const std::string & input_url) {

  }

  std::string getBundleFilename(const char * filename) {
    string s = "android_project/assets/";
    return s + filename;
  }

  void storeValue(const std::string & key, const std::string & value) {

  }

  std::string loadValue(const std::string & key) {
    return "";
  }

  void swapBuffers() {
    eglSwapBuffers(eglDisplay, eglSurface);
  }

private:
  // X11 related local variables
  Display * x_display = NULL;
};

class PlatformX11;

class EventLoopX11 : public EventLoop {
public:
  EventLoopX11( Display * _x_display,
		PlatformX11 * _platform,
		FWContextBase * _application
		)
    : EventLoop(_application), x_display(_x_display), platform(_platform) { }

  void readEvents() {
    XEvent xev;

    cerr << "read pending\n";

    while ( XPending(x_display) ) {
      XNextEvent(x_display, &xev);
      handleEvent(xev);
    }
    if (doKeepRunning()) {
      sendEvents();
    }

    if (doKeepRunning()) {
      cerr << "read all\n";

      timeval tv = { 1, 0 }; // 1000000 / 50 };
      if (XNextEventTimed(x_display, &xev, &tv)) {
	handleEvent(xev);
	sendEvents();
      }
    }
  }

  void run() override {
    struct timeval t1, t2;
    struct timezone tz;
    float deltatime;

    gettimeofday ( &t1 , &tz );

    while (doKeepRunning()) {
      readEvents();
      getApplication()->loadEvents();

      gettimeofday(&t2, &tz);
      deltatime = (float)(t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6);
      t1 = t2;

      if (getApplication()->onUpdate(deltatime)) {
	getApplication()->onDraw();
	platform->swapBuffers();
      }
    }
  }

protected:
  void sendEvents() {
    if (display_width && display_height &&
	(display_width != getApplication()->getActualWidth() ||
	 display_height != getApplication()->getActualHeight())) {
      getApplication()->onResize(display_width, display_height, display_width, display_height);
    }
  }

  void handleEvent(XEvent & xev) {
    KeySym key;
    char text;

    switch (xev.type) {
    case KeyPress:
      if (XLookupString(&xev.xkey, &text, 1, &key, 0) == 1) {
	getApplication()->onKeyPress(text, getPlatform()->getTime(), 0, 0);
      }
      break;
    case DestroyNotify:
      stop();
      break;
    case MotionNotify:
      // getApplication().onMouseMove(xev.xmotion.x, xev.xmotion.y);
      if (button_pressed) {
	getApplication()->touchesMoved(xev.xmotion.x, xev.xmotion.y, getPlatform()->getTime(), 0);
      }
      mouse_x = xev.xmotion.x;
      mouse_y = xev.xmotion.y;
      break;
    case ButtonPress:
      // getApplication().onMouseDown(xev.xbutton.button, 0, 0);
      getApplication()->touchesBegin(mouse_x, mouse_y, getPlatform()->getTime(), 0);
      button_pressed = true;
      break;
    case ButtonRelease:
      // getApplication().onMouseUp(xev.xbutton.button, 0, 0);
      getApplication()->touchesEnded(mouse_x, mouse_y, getPlatform()->getTime(), 0);
      button_pressed = false;
      break;
    case ConfigureNotify:
      {
	XConfigureEvent xce = xev.xconfigure;
	display_width = xce.width;
	display_height = xce.height;
      }
      break;
    }
  }

  PlatformX11 * getPlatform() { return platform; }

private:
  Display * x_display;
  PlatformX11 * platform;
  int display_width = 0, display_height = 0;
  bool button_pressed = false;
  int mouse_x = 0, mouse_y = 0;
};

std::shared_ptr<EventLoop>
PlatformX11::createEventLoop() {
  return std::make_shared<EventLoopX11>(x_display, this, &(getApplication()));
}

///
//  Global extern.  The application must declare this function
//  that runs the application.
//
extern void applicationMain(FWPlatformBase * platform);

///
//  main()
//
//      Main entrypoint for application
//
int main(int argc, char *argv[]) {
  PlatformX11 platform;
  cerr << "starting\n";
  applicationMain(&platform);
  // platform.createWindow(&(platform.getApplication()), "App");
  platform.createContext(&(platform.getApplication()), "App", 800, 600);
  platform.getApplication().onCmdLine(argc, argv);
  platform.getApplication().Init();

  auto eventloop = platform.createEventLoop();
  eventloop->run();

  platform.getApplication().onShutdown();
  return 0;
}
<commit_msg>remove debugs, fix asset directory, temporarily multiply time by 1000<commit_after>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/time.h>
#include <cassert>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>

#include <FWContextBase.h>
#include <FWPlatformBase.h>
#include <EventLoop.h>
#include <CurlClient.h>

#include <ContextCairo.h>

#include <iostream>

using namespace std;

bool XNextEventTimed(Display * dsp, XEvent * event_return, struct timeval * tv) {
  // optimization

  if (tv == NULL) {
    XNextEvent(dsp, event_return);
    return True;
  }

  // the real deal

  if (XPending(dsp) == 0) {
    int fd = ConnectionNumber(dsp);
    // cerr << "nothing pending, fd = " << fd << "\n";
    fd_set readset;
    FD_ZERO(&readset);
    FD_SET(fd, &readset);
    int r = select(fd+1, &readset, NULL, NULL, tv);
    if (r == -1) {
      cerr << "select failed\n";
      return false;
    } else if (r == 0) {
      cerr << "nothing to select\n";
      return false;
    } else {
      // cerr << "getting event (r = " << r << ")\n";
      if (XPending(dsp)) {
	XNextEvent(dsp, event_return);
	return true;
      } else {
	return false;
      }
    }
  } else {
    // cerr << "pending\n";

    XNextEvent(dsp, event_return);
    return true;
  }
}

class PlatformX11 : public FWPlatformBase {
public:
  PlatformX11() : FWPlatformBase(1.0f,
				 // "#version 300 es",
				 "#version 100",
				 true) { }

  double getTime() const override {
    struct timeval tv;
    struct timezone tz;
    int r = gettimeofday(&tv, &tz);
    double t = 0;
    if (r == 0) {
      t = (double)tv.tv_sec + tv.tv_usec / 1000000.0;
    }
    return t;
  }

  void showMessageBox(const string&, const string&) {

  }
  void postNotification(const string&, const string&) {

  }
  string getLocalFilename(const char * fn, FileType type) {
    string s = "android_projects/assets/";
    return s + fn;
  }

  std::shared_ptr<HTTPClientFactory> createHTTPClientFactory() const {
    return std::make_shared<CurlClientFactory>();
  }

  int showActionSheet(const FWRect&, const FWActionSheet&) {
    return 0;
  }

  bool createWindow(FWContextBase * context, const char* title) override {
    Window root;
    XSetWindowAttributes swa;
    XSetWindowAttributes  xattr;
    Atom wm_state;
    XWMHints hints;
    XEvent xev;
    EGLConfig ecfg;
    EGLint num_config;
    Window win;

    /*
     * X11 native display initialization
     */

    x_display = XOpenDisplay(NULL);
    if (x_display == NULL) {
      return false;
    }

    root = DefaultRootWindow(x_display);

    // esContext->getActualWidth(), esContext->getActualHeight()
    int width = 800;
    int height = 600;

    swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask;
    win = XCreateWindow(
               x_display, root,
               0, 0, width, height, 0,
               CopyFromParent, InputOutput,
               CopyFromParent, CWEventMask,
               &swa );

    xattr.override_redirect = 0;
    XChangeWindowAttributes ( x_display, win, CWOverrideRedirect, &xattr );

    XSelectInput(x_display, win,
		 ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
		 ButtonPressMask | ButtonReleaseMask  | StructureNotifyMask
		 );

    hints.input = 1;
    hints.flags = InputHint;
    XSetWMHints(x_display, win, &hints);

    // make the window visible on the screen
    XMapWindow (x_display, win);
    XStoreName (x_display, win, title);

    // get identifiers for the provided atom name strings
    wm_state = XInternAtom (x_display, "_NET_WM_STATE", 0);

    memset ( &xev, 0, sizeof(xev) );
    xev.type                 = ClientMessage;
    xev.xclient.window       = win;
    xev.xclient.message_type = wm_state;
    xev.xclient.format       = 32;
    xev.xclient.data.l[0]    = 1;
    xev.xclient.data.l[1]    = 0;
    XSendEvent (
       x_display,
       DefaultRootWindow ( x_display ),
       0,
       SubstructureNotifyMask,
       &xev );

    eglNativeWindow = (EGLNativeWindowType) win;
    eglNativeDisplay = (EGLNativeDisplayType) x_display;

    cerr << "native display = " << x_display << endl;

    XFlush(x_display);

    return true;
  }

  std::shared_ptr<canvas::ContextFactory> createContextFactory() const {
    return std::shared_ptr<canvas::ContextFactory>(new canvas::CairoContextFactory);
  }

  std::shared_ptr<EventLoop> createEventLoop() override;

  void showMessageBox(const std::string & message) {

  }

  std::string showTextEntryDialog(const std::string & message) {
    return "";
  }

  void postNotification(const std::string & message) {

  }

  void launchBrowser(const std::string & input_url) {

  }

  std::string getBundleFilename(const char * filename) {
    string s = "assets/";
    return s + filename;
  }

  void storeValue(const std::string & key, const std::string & value) {

  }

  std::string loadValue(const std::string & key) {
    return "";
  }

  void swapBuffers() {
    eglSwapBuffers(eglDisplay, eglSurface);
  }

private:
  // X11 related local variables
  Display * x_display = NULL;
};

class PlatformX11;

class EventLoopX11 : public EventLoop {
public:
  EventLoopX11( Display * _x_display,
		PlatformX11 * _platform,
		FWContextBase * _application
		)
    : EventLoop(_application), x_display(_x_display), platform(_platform) { }

  void readEvents() {
    XEvent xev;

    // cerr << "read pending\n";

    while ( XPending(x_display) ) {
      XNextEvent(x_display, &xev);
      handleEvent(xev);
    }
    if (doKeepRunning()) {
      sendEvents();
    }

    if (doKeepRunning()) {
      // cerr << "read all\n";

      timeval tv = { 1, 0 }; // 1000000 / 50 };
      if (XNextEventTimed(x_display, &xev, &tv)) {
	handleEvent(xev);
	sendEvents();
      }
    }
  }

  void run() override {
    struct timeval t1, t2;
    struct timezone tz;
    float deltatime;

    gettimeofday ( &t1 , &tz );

    while (doKeepRunning()) {
      readEvents();
      getApplication()->loadEvents();

#if 0
      gettimeofday(&t2, &tz);
      deltatime = (float)(t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6);
      t1 = t2;
#endif

      if (getApplication()->onUpdate(getPlatform()->getTime() * 1000)) {
	getApplication()->onDraw();
	platform->swapBuffers();
      }
    }
  }

protected:
  void sendEvents() {
    if (display_width && display_height &&
	(display_width != getApplication()->getActualWidth() ||
	 display_height != getApplication()->getActualHeight())) {
      getApplication()->onResize(display_width, display_height, display_width, display_height);
    }
  }

  void handleEvent(XEvent & xev) {
    KeySym key;
    char text;

    switch (xev.type) {
    case KeyPress:
      if (XLookupString(&xev.xkey, &text, 1, &key, 0) == 1) {
	getApplication()->onKeyPress(text, getPlatform()->getTime(), 0, 0);
      }
      break;
    case DestroyNotify:
      stop();
      break;
    case MotionNotify:
      // getApplication().onMouseMove(xev.xmotion.x, xev.xmotion.y);
      if (button_pressed) {
	getApplication()->touchesMoved(xev.xmotion.x, xev.xmotion.y, getPlatform()->getTime(), 0);
      }
      mouse_x = xev.xmotion.x;
      mouse_y = xev.xmotion.y;
      break;
    case ButtonPress:
      // getApplication().onMouseDown(xev.xbutton.button, 0, 0);
      getApplication()->touchesBegin(mouse_x, mouse_y, getPlatform()->getTime(), 0);
      button_pressed = true;
      break;
    case ButtonRelease:
      // getApplication().onMouseUp(xev.xbutton.button, 0, 0);
      getApplication()->touchesEnded(mouse_x, mouse_y, getPlatform()->getTime(), 0);
      button_pressed = false;
      break;
    case ConfigureNotify:
      {
	XConfigureEvent xce = xev.xconfigure;
	display_width = xce.width;
	display_height = xce.height;
      }
      break;
    }
  }

  PlatformX11 * getPlatform() { return platform; }

private:
  Display * x_display;
  PlatformX11 * platform;
  int display_width = 0, display_height = 0;
  bool button_pressed = false;
  int mouse_x = 0, mouse_y = 0;
};

std::shared_ptr<EventLoop>
PlatformX11::createEventLoop() {
  return std::make_shared<EventLoopX11>(x_display, this, &(getApplication()));
}

///
//  Global extern.  The application must declare this function
//  that runs the application.
//
extern void applicationMain(FWPlatformBase * platform);

///
//  main()
//
//      Main entrypoint for application
//
int main(int argc, char *argv[]) {
  PlatformX11 platform;
  cerr << "starting\n";
  applicationMain(&platform);
  // platform.createWindow(&(platform.getApplication()), "App");
  platform.createContext(&(platform.getApplication()), "App", 800, 600);
  platform.getApplication().onCmdLine(argc, argv);
  platform.getApplication().Init();

  auto eventloop = platform.createEventLoop();
  eventloop->run();

  platform.getApplication().onShutdown();
  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Tests for the top plugins to catch regressions in our plugin host code, as
// well as in the out of process code.  Currently this tests:
//  Flash
//  Real
//  QuickTime
//  Windows Media Player
//    -this includes both WMP plugins.  npdsplay.dll is the older one that
//     comes with XP.  np-mswmp.dll can be downloaded from Microsoft and
//     needs SP2 or Vista.

#include "build/build_config.h"

#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include <comutil.h>
#endif

#include <stdlib.h>
#include <string.h>
#include <memory.h>

#include <string>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "third_party/npapi/bindings/npapi.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_list.h"

#if defined(OS_WIN)
#include "base/registry.h"
#endif

class PluginTest : public UITest {
 protected:
#if defined(OS_WIN)
  virtual void SetUp() {
    const testing::TestInfo* const test_info =
        testing::UnitTest::GetInstance()->current_test_info();
    if (strcmp(test_info->name(), "MediaPlayerNew") == 0) {
      // The installer adds our process names to the registry key below.  Since
      // the installer might not have run on this machine, add it manually.
      RegKey regkey;
      if (regkey.Open(HKEY_LOCAL_MACHINE,
                      L"Software\\Microsoft\\MediaPlayer\\ShimInclusionList",
                      KEY_WRITE)) {
        regkey.CreateKey(L"CHROME.EXE", KEY_READ);
      }
    } else if (strcmp(test_info->name(), "MediaPlayerOld") == 0) {
      // When testing the old WMP plugin, we need to force Chrome to not load
      // the new plugin.
      launch_arguments_.AppendSwitch(kUseOldWMPPluginSwitch);
    } else if (strcmp(test_info->name(), "FlashSecurity") == 0) {
      launch_arguments_.AppendSwitchASCII(switches::kTestSandbox,
                                          "security_tests.dll");
    }

    UITest::SetUp();
  }
#endif  // defined(OS_WIN)

  void TestPlugin(const std::string& test_case,
                  int timeout,
                  bool mock_http) {
    GURL url = GetTestUrl(test_case, mock_http);
    NavigateToURL(url);
    WaitForFinish(timeout, mock_http);
  }

  // Generate the URL for testing a particular test.
  // HTML for the tests is all located in test_directory\plugin\<testcase>
  // Set |mock_http| to true to use mock HTTP server.
  GURL GetTestUrl(const std::string &test_case, bool mock_http) {
    static const FilePath::CharType kPluginPath[] = FILE_PATH_LITERAL("plugin");
    if (mock_http) {
      FilePath plugin_path = FilePath(kPluginPath).AppendASCII(test_case);
      return URLRequestMockHTTPJob::GetMockUrl(plugin_path);
    }

    FilePath path;
    PathService::Get(chrome::DIR_TEST_DATA, &path);
    path = path.Append(kPluginPath).AppendASCII(test_case);
    return net::FilePathToFileURL(path);
  }

  // Waits for the test case to finish.
  void WaitForFinish(const int wait_time, bool mock_http) {
    static const char kTestCompleteCookie[] = "status";
    static const char kTestCompleteSuccess[] = "OK";

    GURL url = GetTestUrl("done", mock_http);
    scoped_refptr<TabProxy> tab(GetActiveTab());

    const std::string result =
        WaitUntilCookieNonEmpty(tab, url, kTestCompleteCookie, wait_time);
    ASSERT_EQ(kTestCompleteSuccess, result);
  }
};

TEST_F(PluginTest, Flash) {
  // Note: This does not work with the npwrapper on 64-bit Linux. Install the
  // native 64-bit Flash to run the test.
  // TODO(thestig) Update this list if we decide to only test against internal
  // Flash plugin in the future?
  std::string kFlashQuery =
#if defined(OS_WIN)
      "npswf32.dll"
#elif defined(OS_MACOSX)
      "Flash Player.plugin"
#elif defined(OS_POSIX)
      "libflashplayer.so"
#endif
      ;
  TestPlugin("flash.html?" + kFlashQuery, action_max_timeout_ms(), false);
}

#if defined(OS_WIN)
// Windows only test
TEST_F(PluginTest, FlashSecurity) {
  TestPlugin("flash.html", action_max_timeout_ms(), false);
}
#endif  // defined(OS_WIN)

#if defined(OS_WIN)
// TODO(port) Port the following tests to platforms that have the required
// plugins.
TEST_F(PluginTest, Quicktime) {
  TestPlugin("quicktime.html", action_max_timeout_ms(), false);
}

// Disabled on Release bots - http://crbug.com/44662
#if defined(NDEBUG)
#define MediaPlayerNew DISABLED_MediaPlayerNew
#endif
TEST_F(PluginTest, MediaPlayerNew) {
  TestPlugin("wmp_new.html", action_max_timeout_ms(), false);
}

// http://crbug.com/4809
TEST_F(PluginTest, DISABLED_MediaPlayerOld) {
  TestPlugin("wmp_old.html", action_max_timeout_ms(), false);
}

#if defined(NDEBUG)
#define Real DISABLED_Real
#endif
// Disabled on Release bots - http://crbug.com/44673
TEST_F(PluginTest, Real) {
  TestPlugin("real.html", action_max_timeout_ms(), false);
}

TEST_F(PluginTest, FlashOctetStream) {
  TestPlugin("flash-octet-stream.html", action_max_timeout_ms(), false);
}

// http://crbug.com/16114
TEST_F(PluginTest, FlashLayoutWhilePainting) {
  TestPlugin("flash-layout-while-painting.html", action_max_timeout_ms(), true);
}

// http://crbug.com/8690
TEST_F(PluginTest, DISABLED_Java) {
  TestPlugin("Java.html", action_max_timeout_ms(), false);
}

TEST_F(PluginTest, Silverlight) {
  TestPlugin("silverlight.html", action_max_timeout_ms(), false);
}
#endif  // defined(OS_WIN)
<commit_msg>Mark PluginTest.FlashLayoutWhilePainting as flaky on Windows.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Tests for the top plugins to catch regressions in our plugin host code, as
// well as in the out of process code.  Currently this tests:
//  Flash
//  Real
//  QuickTime
//  Windows Media Player
//    -this includes both WMP plugins.  npdsplay.dll is the older one that
//     comes with XP.  np-mswmp.dll can be downloaded from Microsoft and
//     needs SP2 or Vista.

#include "build/build_config.h"

#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include <comutil.h>
#endif

#include <stdlib.h>
#include <string.h>
#include <memory.h>

#include <string>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "third_party/npapi/bindings/npapi.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_list.h"

#if defined(OS_WIN)
#include "base/registry.h"
#endif

class PluginTest : public UITest {
 protected:
#if defined(OS_WIN)
  virtual void SetUp() {
    const testing::TestInfo* const test_info =
        testing::UnitTest::GetInstance()->current_test_info();
    if (strcmp(test_info->name(), "MediaPlayerNew") == 0) {
      // The installer adds our process names to the registry key below.  Since
      // the installer might not have run on this machine, add it manually.
      RegKey regkey;
      if (regkey.Open(HKEY_LOCAL_MACHINE,
                      L"Software\\Microsoft\\MediaPlayer\\ShimInclusionList",
                      KEY_WRITE)) {
        regkey.CreateKey(L"CHROME.EXE", KEY_READ);
      }
    } else if (strcmp(test_info->name(), "MediaPlayerOld") == 0) {
      // When testing the old WMP plugin, we need to force Chrome to not load
      // the new plugin.
      launch_arguments_.AppendSwitch(kUseOldWMPPluginSwitch);
    } else if (strcmp(test_info->name(), "FlashSecurity") == 0) {
      launch_arguments_.AppendSwitchASCII(switches::kTestSandbox,
                                          "security_tests.dll");
    }

    UITest::SetUp();
  }
#endif  // defined(OS_WIN)

  void TestPlugin(const std::string& test_case,
                  int timeout,
                  bool mock_http) {
    GURL url = GetTestUrl(test_case, mock_http);
    NavigateToURL(url);
    WaitForFinish(timeout, mock_http);
  }

  // Generate the URL for testing a particular test.
  // HTML for the tests is all located in test_directory\plugin\<testcase>
  // Set |mock_http| to true to use mock HTTP server.
  GURL GetTestUrl(const std::string &test_case, bool mock_http) {
    static const FilePath::CharType kPluginPath[] = FILE_PATH_LITERAL("plugin");
    if (mock_http) {
      FilePath plugin_path = FilePath(kPluginPath).AppendASCII(test_case);
      return URLRequestMockHTTPJob::GetMockUrl(plugin_path);
    }

    FilePath path;
    PathService::Get(chrome::DIR_TEST_DATA, &path);
    path = path.Append(kPluginPath).AppendASCII(test_case);
    return net::FilePathToFileURL(path);
  }

  // Waits for the test case to finish.
  void WaitForFinish(const int wait_time, bool mock_http) {
    static const char kTestCompleteCookie[] = "status";
    static const char kTestCompleteSuccess[] = "OK";

    GURL url = GetTestUrl("done", mock_http);
    scoped_refptr<TabProxy> tab(GetActiveTab());

    const std::string result =
        WaitUntilCookieNonEmpty(tab, url, kTestCompleteCookie, wait_time);
    ASSERT_EQ(kTestCompleteSuccess, result);
  }
};

TEST_F(PluginTest, Flash) {
  // Note: This does not work with the npwrapper on 64-bit Linux. Install the
  // native 64-bit Flash to run the test.
  // TODO(thestig) Update this list if we decide to only test against internal
  // Flash plugin in the future?
  std::string kFlashQuery =
#if defined(OS_WIN)
      "npswf32.dll"
#elif defined(OS_MACOSX)
      "Flash Player.plugin"
#elif defined(OS_POSIX)
      "libflashplayer.so"
#endif
      ;
  TestPlugin("flash.html?" + kFlashQuery, action_max_timeout_ms(), false);
}

#if defined(OS_WIN)
// Windows only test
TEST_F(PluginTest, FlashSecurity) {
  TestPlugin("flash.html", action_max_timeout_ms(), false);
}
#endif  // defined(OS_WIN)

#if defined(OS_WIN)
// TODO(port) Port the following tests to platforms that have the required
// plugins.
TEST_F(PluginTest, Quicktime) {
  TestPlugin("quicktime.html", action_max_timeout_ms(), false);
}

// Disabled on Release bots - http://crbug.com/44662
#if defined(NDEBUG)
#define MediaPlayerNew DISABLED_MediaPlayerNew
#endif
TEST_F(PluginTest, MediaPlayerNew) {
  TestPlugin("wmp_new.html", action_max_timeout_ms(), false);
}

// http://crbug.com/4809
TEST_F(PluginTest, DISABLED_MediaPlayerOld) {
  TestPlugin("wmp_old.html", action_max_timeout_ms(), false);
}

#if defined(NDEBUG)
#define Real DISABLED_Real
#endif
// Disabled on Release bots - http://crbug.com/44673
TEST_F(PluginTest, Real) {
  TestPlugin("real.html", action_max_timeout_ms(), false);
}

TEST_F(PluginTest, FlashOctetStream) {
  TestPlugin("flash-octet-stream.html", action_max_timeout_ms(), false);
}

#if defined(OS_WIN)
// http://crbug.com/53926
TEST_F(PluginTest, FLAKY_FlashLayoutWhilePainting) {
#else
TEST_F(PluginTest, FlashLayoutWhilePainting) {
#endif
  TestPlugin("flash-layout-while-painting.html", action_max_timeout_ms(), true);
}

// http://crbug.com/8690
TEST_F(PluginTest, DISABLED_Java) {
  TestPlugin("Java.html", action_max_timeout_ms(), false);
}

TEST_F(PluginTest, Silverlight) {
  TestPlugin("silverlight.html", action_max_timeout_ms(), false);
}
#endif  // defined(OS_WIN)
<|endoftext|>


<commit_before>// Local
#include "MainWindow.h"
#include "ui_MainWindow.h"

#include "ShadowSettings.h"

#include "GraphicsRoundedRectItem.h"

// Qt
#include <QGraphicsRectItem>
#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
#include <QMenu>
#include <QInputDialog>
#include <QDebug>

MainWindow::MainWindow(QWidget* parent)
  : QMainWindow(parent)
  , ui(new Ui::MainWindow)
  , m_settings(new QSettings)
  , m_width(40)
  , m_height(40)
  , m_radius(0)
  , m_scale(1)
{
  ui->setupUi(this);

  m_scene = new QGraphicsScene(this);

  m_baseItem = new GraphicsRoundedRectItem();
  m_baseItem->setBrush(QBrush(Qt::white));
  m_baseItem->setPen(QPen(Qt::NoBrush, 0, Qt::NoPen));
  m_baseItem->setZValue(1000);

  m_scene->addItem(m_baseItem);
  ui->graphicsView->setScene(m_scene);
  addShadow();

  connect(ui->scaleSlider, SIGNAL(valueChanged(int)), SLOT(userScaleChanged(int)));

  connect(ui->widthBox, SIGNAL(valueChanged(int)), SLOT(userSourceChanged()));
  connect(ui->heightBox, SIGNAL(valueChanged(int)), SLOT(userSourceChanged()));
  connect(ui->radiusBox, SIGNAL(valueChanged(int)), SLOT(userSourceChanged()));

  connect(ui->addShadowButton, SIGNAL(clicked()), SLOT(addShadow()));

  connect(this, SIGNAL(sourceOptionsChanged(int,int,int)), SLOT(updateSource()));
  connect(this, SIGNAL(scaleChanged(qreal)), SLOT(updateSource()));

  // Hack: position view to the center of layout
  //
  // This is the only way I've found to ensure the item will be placed in the center of view: we simply make the view
  // rectangle definitely larger than the view itself, turn off the scroll bars display (in the UI file) and forcing
  // positioning on the center of the base item. If the scene rect is smaller than the view itself, QGraphicsView
  // control simply ignores QGraphicsView::centerOn calls
  ui->graphicsView->setSceneRect(-1000, -1000, 2000, 2000);

  updateSource();
  updatePresets();
}

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

void MainWindow::on_saveButton_clicked()
{
  // File name
  QString fileName = QFileDialog::getSaveFileName(this, tr("Save rendered image as..."), QString(),
                                                  "PNG image (*.png)");
  if (fileName.isEmpty())
    return;
  if (!fileName.endsWith(".png", Qt::CaseInsensitive))
    fileName.append(".png");

  // Source scene rect to render
  // We must use the aligned rectangle to not mess with the non-integer items coordinates
  QRectF sourceRect = QRectF(m_scene->itemsBoundingRect().toAlignedRect());

  QImage target(sourceRect.width(), sourceRect.height(), QImage::Format_ARGB32_Premultiplied);
  target.fill(Qt::transparent);

  QPainter p(&target);
  p.setRenderHint(QPainter::Antialiasing);
  p.setRenderHint(QPainter::SmoothPixmapTransform);

  if (!ui->renderSourceCheckBox->isChecked())
    m_baseItem->setVisible(false);

  m_scene->render(&p, target.rect(), sourceRect);

  m_baseItem->setVisible(true);
  p.end();

  // Determine the image rectangle filled by shadow and crop borders
  QRect filled = filledRect(target);
  target = target.copy(filled);

  // Save file
  bool saveResult = target.save(fileName);
  if (!saveResult)
  {
    QMessageBox::critical(this, tr("Error saving file"), tr("Could not save file %1").arg(fileName));
    return;
  }

  // Generate QML
  if (ui->generateQmlCheckBox->isChecked())
  {
    QRectF baseItemRect = m_baseItem->boundingRect().translated(-sourceRect.topLeft()).translated(-filled.topLeft());

    QFileInfo fileInfo(fileName);
    QFile qmlFile(fileInfo.absolutePath() + "/" + fileInfo.completeBaseName() + ".qml");
    if (!qmlFile.open(QIODevice::WriteOnly | QIODevice::Text))
    {
      QMessageBox::critical(this, tr("Error saving file"), tr("Could not save file %1").arg(qmlFile.fileName()));
      return;
    }

    QTextStream stream(&qmlFile);

    stream << "import QtQuick 2.0" << endl;
    stream << endl;
    stream << "Item {" << endl;

    stream << "  BorderImage {" << endl;
    stream << "    source: \"" << fileInfo.fileName() << "\"" << endl;
    stream << endl;
    stream << "    anchors {" << endl;
    stream << "      fill: parent" << endl;
    stream << "      leftMargin: -border.left; topMargin: -border.top" << endl;
    stream << "      rightMargin: -border.right; bottomMargin: -border.bottom" << endl;
    stream << "    }" << endl;
    stream << endl;
    stream << "    border.left: " << baseItemRect.left() << "; border.top: " << baseItemRect.top() << endl;
    stream << "    border.right: " << target.width() - baseItemRect.right()
           <<   "; border.bottom: " << target.height() - baseItemRect.bottom() << endl;
    stream << "  }" << endl;

    stream << "}" << endl;

    qmlFile.close();
  }
}

void MainWindow::updateSource()
{
  m_baseItem->setRect(0, 0, m_width * m_scale, m_height * m_scale);
  m_baseItem->setRadiusX(m_radius * m_scale);
  m_baseItem->setRadiusY(m_radius * m_scale);

  ui->graphicsView->centerOn(m_baseItem);
}

void MainWindow::addShadow(int xOffset, int yOffset, int opacity, double blur)
{
  QBoxLayout* shadowLayout = static_cast<QBoxLayout*>(ui->shadowsBox->layout());

  ShadowSettings* settings = new ShadowSettings(m_scene);
  settings->setSourceOptions(m_width, m_height, m_radius);
  settings->setScale(m_scale);

  connect(this, SIGNAL(sourceOptionsChanged(int,int,int)), settings, SLOT(setSourceOptions(int,int,int)));
  connect(this, SIGNAL(scaleChanged(qreal)), settings, SLOT(setScale(qreal)));
  connect(settings, &QObject::destroyed, [this](QObject* obj) { m_shadows.removeOne(qobject_cast<ShadowSettings*>(obj)); });

  settings->setXOffset(xOffset);
  settings->setYOffset(yOffset);
  settings->setOpacity(opacity);
  settings->setBlur(blur);

  shadowLayout->insertWidget(shadowLayout->count() - 1, settings);

  m_shadows.append(settings);
  ui->graphicsView->centerOn(m_baseItem);
}

void MainWindow::userSourceChanged()
{
  m_width = ui->widthBox->value();
  m_height = ui->heightBox->value();
  m_radius = ui->radiusBox->value();

  ui->radiusBox->setMaximum(qMin(m_width, m_height) / 2);

  emit sourceOptionsChanged(m_width, m_height, m_radius);
}

void MainWindow::userScaleChanged(int value)
{
  // Calculate and display scale value
  m_scale = qreal(value) * 0.25;
  ui->scaleValueLabel->setText(tr("%1%").arg(m_scale * 100));

  emit scaleChanged(m_scale);
}

void MainWindow::loadShadowPreset()
{
  QAction* a = qobject_cast<QAction*>(sender());
  if (!a)
  {
    qWarning("Unknown action source");
    return;
  }

  QVariantList o = a->data().toList();
  if (o.size() % 4)
  {
    qWarning() << "Incorrect preset data for preset" << a->text();
    return;
  }

  qDeleteAll(m_shadows);
  m_shadows.clear();

  for (int i = 0; i < o.size() / 4; ++i)
    addShadow(o.at(i * 4).toInt(), o.at(i * 4 + 1).toInt(), o.at(i * 4 + 2).toInt(), o.at(i * 4 + 3).toDouble());
}

QRect MainWindow::filledRect(const QImage& image)
{
  QRect result = image.rect();

  // Left border
  while (result.left() < result.right())
  {
    bool hasFilledPixel = false;
    for (int y = result.top(); y <= result.bottom(); y++)
    {
      if (qAlpha(image.pixel(result.left(), y)) > 0)
      {
        hasFilledPixel = true;
        break;
      }
    }

    if (hasFilledPixel)
      break;

    result.adjust(1, 0, 0, 0);
  }

  // Right border
  while (result.right() > result.left())
  {
    bool hasFilledPixel = false;
    for (int y = result.top(); y <= result.bottom(); y++)
    {
      if (qAlpha(image.pixel(result.right(), y)) > 0)
      {
        hasFilledPixel = true;
        break;
      }
    }

    if (hasFilledPixel)
      break;

    result.adjust(0, 0, -1, 0);
  }

  // Top border
  while (result.top() < result.bottom())
  {
    bool hasFilledPixel = false;
    for (int x = result.left(); x <= result.right(); x++)
    {
      if (qAlpha(image.pixel(x, result.top())) > 0)
      {
        hasFilledPixel = true;
        break;
      }
    }

    if (hasFilledPixel)
      break;

    result.adjust(0, 1, 0, 0);
  }

  // Top border
  while (result.bottom() > result.top())
  {
    bool hasFilledPixel = false;
    for (int x = result.left(); x <= result.right(); x++)
    {
      if (qAlpha(image.pixel(x, result.bottom())) > 0)
      {
        hasFilledPixel = true;
        break;
      }
    }

    if (hasFilledPixel)
      break;

    result.adjust(0, 0, 0, -1);
  }

  return result;
}

void MainWindow::updatePresets()
{
  if (!ui->loadPresetButton->menu())
    ui->loadPresetButton->setMenu(new QMenu);

  QMenu* menu = ui->loadPresetButton->menu();
  menu->clear();

  // Default presets
  QVariantList presets;
  if (!m_settings->contains("ShadowPresets"))
  {
    QVariantMap d1;
    d1[QStringLiteral("name")] = tr("Material design Z=1");
    d1[QStringLiteral("options")] = QVariantList() << 0 << 1 << 12 << 1.5
                                                   << 0 << 1 << 24 << 1.;

    QVariantMap d2;
    d2[QStringLiteral("name")] = tr("Material design Z=2");
    d2[QStringLiteral("options")] = QVariantList() << 0 << 3 << 16 << 3.
                                                   << 0 << 3 << 23 << 3.;

    QVariantMap d3;
    d3[QStringLiteral("name")] = tr("Material design Z=3");
    d3[QStringLiteral("options")] = QVariantList() << 0 << 10 << 19 << 10.
                                                   << 0 << 6  << 23 << 3.;

    QVariantMap d4;
    d4[QStringLiteral("name")] = tr("Material design Z=4");
    d4[QStringLiteral("options")] = QVariantList() << 0 << 14 << 25 << 14.
                                                   << 0 << 10 << 22 << 5.;

    QVariantMap d5;
    d5[QStringLiteral("name")] = tr("Material design Z=5");
    d5[QStringLiteral("options")] = QVariantList() << 0 << 19 << 30 << 19.
                                                   << 0 << 15 << 22 << 6.;

    presets << d1 << d2 << d3 << d4 << d5;
    m_settings->setValue(QStringLiteral("ShadowPresets"), presets);
  }
  else
  {
    presets = m_settings->value(QStringLiteral("ShadowPresets")).toList();
  }

  // Fill in the menu
  for (auto p : presets)
  {
    if (!p.isValid())
    {
      qWarning() << "Failed to load preset";
      continue;
    }

    QVariantMap preset = p.toMap();
    auto action = menu->addAction(preset[QStringLiteral("name")].toString(), this, SLOT(loadShadowPreset()));
    action->setData(preset[QStringLiteral("options")]);
  }
}

void MainWindow::on_addPresetButton_clicked()
{
  QString name = QInputDialog::getText(this, tr("Choose preset name"), tr("Preset name:"));
  if (!name.isEmpty())
  {
    QVariantMap preset;
    preset[QStringLiteral("name")] = name;
    QVariantList options;
    for (auto s : m_shadows)
      options << s->xOffset() << s->yOffset() << s->opacity() << s->blur();

    preset[QStringLiteral("options")] = options;

    auto presets = m_settings->value(QStringLiteral("ShadowPresets")).toList();
    presets.append(preset);
    m_settings->setValue(QStringLiteral("ShadowPresets"), presets);
    updatePresets();
  }
}
<commit_msg>Fixed crash<commit_after>// Local
#include "MainWindow.h"
#include "ui_MainWindow.h"

#include "ShadowSettings.h"

#include "GraphicsRoundedRectItem.h"

// Qt
#include <QGraphicsRectItem>
#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
#include <QMenu>
#include <QInputDialog>
#include <QDebug>

MainWindow::MainWindow(QWidget* parent)
  : QMainWindow(parent)
  , ui(new Ui::MainWindow)
  , m_settings(new QSettings)
  , m_width(40)
  , m_height(40)
  , m_radius(0)
  , m_scale(1)
{
  ui->setupUi(this);

  m_scene = new QGraphicsScene(this);

  m_baseItem = new GraphicsRoundedRectItem();
  m_baseItem->setBrush(QBrush(Qt::white));
  m_baseItem->setPen(QPen(Qt::NoBrush, 0, Qt::NoPen));
  m_baseItem->setZValue(1000);

  m_scene->addItem(m_baseItem);
  ui->graphicsView->setScene(m_scene);
  addShadow();

  connect(ui->scaleSlider, SIGNAL(valueChanged(int)), SLOT(userScaleChanged(int)));

  connect(ui->widthBox, SIGNAL(valueChanged(int)), SLOT(userSourceChanged()));
  connect(ui->heightBox, SIGNAL(valueChanged(int)), SLOT(userSourceChanged()));
  connect(ui->radiusBox, SIGNAL(valueChanged(int)), SLOT(userSourceChanged()));

  connect(ui->addShadowButton, SIGNAL(clicked()), SLOT(addShadow()));

  connect(this, SIGNAL(sourceOptionsChanged(int,int,int)), SLOT(updateSource()));
  connect(this, SIGNAL(scaleChanged(qreal)), SLOT(updateSource()));

  // Hack: position view to the center of layout
  //
  // This is the only way I've found to ensure the item will be placed in the center of view: we simply make the view
  // rectangle definitely larger than the view itself, turn off the scroll bars display (in the UI file) and forcing
  // positioning on the center of the base item. If the scene rect is smaller than the view itself, QGraphicsView
  // control simply ignores QGraphicsView::centerOn calls
  ui->graphicsView->setSceneRect(-1000, -1000, 2000, 2000);

  updateSource();
  updatePresets();
}

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

void MainWindow::on_saveButton_clicked()
{
  // File name
  QString fileName = QFileDialog::getSaveFileName(this, tr("Save rendered image as..."), QString(),
                                                  "PNG image (*.png)");
  if (fileName.isEmpty())
    return;
  if (!fileName.endsWith(".png", Qt::CaseInsensitive))
    fileName.append(".png");

  // Source scene rect to render
  // We must use the aligned rectangle to not mess with the non-integer items coordinates
  QRectF sourceRect = QRectF(m_scene->itemsBoundingRect().toAlignedRect());

  QImage target(sourceRect.width(), sourceRect.height(), QImage::Format_ARGB32_Premultiplied);
  target.fill(Qt::transparent);

  QPainter p(&target);
  p.setRenderHint(QPainter::Antialiasing);
  p.setRenderHint(QPainter::SmoothPixmapTransform);

  if (!ui->renderSourceCheckBox->isChecked())
    m_baseItem->setVisible(false);

  m_scene->render(&p, target.rect(), sourceRect);

  m_baseItem->setVisible(true);
  p.end();

  // Determine the image rectangle filled by shadow and crop borders
  QRect filled = filledRect(target);
  target = target.copy(filled);

  // Save file
  bool saveResult = target.save(fileName);
  if (!saveResult)
  {
    QMessageBox::critical(this, tr("Error saving file"), tr("Could not save file %1").arg(fileName));
    return;
  }

  // Generate QML
  if (ui->generateQmlCheckBox->isChecked())
  {
    QRectF baseItemRect = m_baseItem->boundingRect().translated(-sourceRect.topLeft()).translated(-filled.topLeft());

    QFileInfo fileInfo(fileName);
    QFile qmlFile(fileInfo.absolutePath() + "/" + fileInfo.completeBaseName() + ".qml");
    if (!qmlFile.open(QIODevice::WriteOnly | QIODevice::Text))
    {
      QMessageBox::critical(this, tr("Error saving file"), tr("Could not save file %1").arg(qmlFile.fileName()));
      return;
    }

    QTextStream stream(&qmlFile);

    stream << "import QtQuick 2.0" << endl;
    stream << endl;
    stream << "Item {" << endl;

    stream << "  BorderImage {" << endl;
    stream << "    source: \"" << fileInfo.fileName() << "\"" << endl;
    stream << endl;
    stream << "    anchors {" << endl;
    stream << "      fill: parent" << endl;
    stream << "      leftMargin: -border.left; topMargin: -border.top" << endl;
    stream << "      rightMargin: -border.right; bottomMargin: -border.bottom" << endl;
    stream << "    }" << endl;
    stream << endl;
    stream << "    border.left: " << baseItemRect.left() << "; border.top: " << baseItemRect.top() << endl;
    stream << "    border.right: " << target.width() - baseItemRect.right()
           <<   "; border.bottom: " << target.height() - baseItemRect.bottom() << endl;
    stream << "  }" << endl;

    stream << "}" << endl;

    qmlFile.close();
  }
}

void MainWindow::updateSource()
{
  m_baseItem->setRect(0, 0, m_width * m_scale, m_height * m_scale);
  m_baseItem->setRadiusX(m_radius * m_scale);
  m_baseItem->setRadiusY(m_radius * m_scale);

  ui->graphicsView->centerOn(m_baseItem);
}

void MainWindow::addShadow(int xOffset, int yOffset, int opacity, double blur)
{
  QBoxLayout* shadowLayout = static_cast<QBoxLayout*>(ui->shadowsBox->layout());

  ShadowSettings* settings = new ShadowSettings(m_scene);
  settings->setSourceOptions(m_width, m_height, m_radius);
  settings->setScale(m_scale);

  connect(this, SIGNAL(sourceOptionsChanged(int,int,int)), settings, SLOT(setSourceOptions(int,int,int)));
  connect(this, SIGNAL(scaleChanged(qreal)), settings, SLOT(setScale(qreal)));
  connect(settings, &QObject::destroyed,
          [this](QObject* obj)
          {
            qDebug() << obj;
            this->m_shadows.removeOne(static_cast<ShadowSettings*>(obj));
            qDebug("remove");
          });

  settings->setXOffset(xOffset);
  settings->setYOffset(yOffset);
  settings->setOpacity(opacity);
  settings->setBlur(blur);

  shadowLayout->insertWidget(shadowLayout->count() - 1, settings);

  m_shadows.append(settings);
  ui->graphicsView->centerOn(m_baseItem);
}

void MainWindow::userSourceChanged()
{
  m_width = ui->widthBox->value();
  m_height = ui->heightBox->value();
  m_radius = ui->radiusBox->value();

  ui->radiusBox->setMaximum(qMin(m_width, m_height) / 2);

  emit sourceOptionsChanged(m_width, m_height, m_radius);
}

void MainWindow::userScaleChanged(int value)
{
  // Calculate and display scale value
  m_scale = qreal(value) * 0.25;
  ui->scaleValueLabel->setText(tr("%1%").arg(m_scale * 100));

  emit scaleChanged(m_scale);
}

void MainWindow::loadShadowPreset()
{
  QAction* a = qobject_cast<QAction*>(sender());
  if (!a)
  {
    qWarning("Unknown action source");
    return;
  }

  QVariantList o = a->data().toList();
  if (o.size() % 4)
  {
    qWarning() << "Incorrect preset data for preset" << a->text();
    return;
  }

  qDeleteAll(m_shadows);
  m_shadows.clear();

  for (int i = 0; i < o.size() / 4; ++i)
    addShadow(o.at(i * 4).toInt(), o.at(i * 4 + 1).toInt(), o.at(i * 4 + 2).toInt(), o.at(i * 4 + 3).toDouble());
}

QRect MainWindow::filledRect(const QImage& image)
{
  QRect result = image.rect();

  // Left border
  while (result.left() < result.right())
  {
    bool hasFilledPixel = false;
    for (int y = result.top(); y <= result.bottom(); y++)
    {
      if (qAlpha(image.pixel(result.left(), y)) > 0)
      {
        hasFilledPixel = true;
        break;
      }
    }

    if (hasFilledPixel)
      break;

    result.adjust(1, 0, 0, 0);
  }

  // Right border
  while (result.right() > result.left())
  {
    bool hasFilledPixel = false;
    for (int y = result.top(); y <= result.bottom(); y++)
    {
      if (qAlpha(image.pixel(result.right(), y)) > 0)
      {
        hasFilledPixel = true;
        break;
      }
    }

    if (hasFilledPixel)
      break;

    result.adjust(0, 0, -1, 0);
  }

  // Top border
  while (result.top() < result.bottom())
  {
    bool hasFilledPixel = false;
    for (int x = result.left(); x <= result.right(); x++)
    {
      if (qAlpha(image.pixel(x, result.top())) > 0)
      {
        hasFilledPixel = true;
        break;
      }
    }

    if (hasFilledPixel)
      break;

    result.adjust(0, 1, 0, 0);
  }

  // Top border
  while (result.bottom() > result.top())
  {
    bool hasFilledPixel = false;
    for (int x = result.left(); x <= result.right(); x++)
    {
      if (qAlpha(image.pixel(x, result.bottom())) > 0)
      {
        hasFilledPixel = true;
        break;
      }
    }

    if (hasFilledPixel)
      break;

    result.adjust(0, 0, 0, -1);
  }

  return result;
}

void MainWindow::updatePresets()
{
  if (!ui->loadPresetButton->menu())
    ui->loadPresetButton->setMenu(new QMenu);

  QMenu* menu = ui->loadPresetButton->menu();
  menu->clear();

  // Default presets
  QVariantList presets;
  if (!m_settings->contains("ShadowPresets"))
  {
    QVariantMap d1;
    d1[QStringLiteral("name")] = tr("Material design Z=1");
    d1[QStringLiteral("options")] = QVariantList() << 0 << 1 << 12 << 1.5
                                                   << 0 << 1 << 24 << 1.;

    QVariantMap d2;
    d2[QStringLiteral("name")] = tr("Material design Z=2");
    d2[QStringLiteral("options")] = QVariantList() << 0 << 3 << 16 << 3.
                                                   << 0 << 3 << 23 << 3.;

    QVariantMap d3;
    d3[QStringLiteral("name")] = tr("Material design Z=3");
    d3[QStringLiteral("options")] = QVariantList() << 0 << 10 << 19 << 10.
                                                   << 0 << 6  << 23 << 3.;

    QVariantMap d4;
    d4[QStringLiteral("name")] = tr("Material design Z=4");
    d4[QStringLiteral("options")] = QVariantList() << 0 << 14 << 25 << 14.
                                                   << 0 << 10 << 22 << 5.;

    QVariantMap d5;
    d5[QStringLiteral("name")] = tr("Material design Z=5");
    d5[QStringLiteral("options")] = QVariantList() << 0 << 19 << 30 << 19.
                                                   << 0 << 15 << 22 << 6.;

    presets << d1 << d2 << d3 << d4 << d5;
    m_settings->setValue(QStringLiteral("ShadowPresets"), presets);
  }
  else
  {
    presets = m_settings->value(QStringLiteral("ShadowPresets")).toList();
  }

  // Fill in the menu
  for (auto p : presets)
  {
    if (!p.isValid())
    {
      qWarning() << "Failed to load preset";
      continue;
    }

    QVariantMap preset = p.toMap();
    auto action = menu->addAction(preset[QStringLiteral("name")].toString(), this, SLOT(loadShadowPreset()));
    action->setData(preset[QStringLiteral("options")]);
  }
}

void MainWindow::on_addPresetButton_clicked()
{
  QString name = QInputDialog::getText(this, tr("Choose preset name"), tr("Preset name:"));
  if (!name.isEmpty())
  {
    QVariantMap preset;
    preset[QStringLiteral("name")] = name;
    QVariantList options;
    for (auto s : m_shadows)
      options << s->xOffset() << s->yOffset() << s->opacity() << s->blur();

    preset[QStringLiteral("options")] = options;

    auto presets = m_settings->value(QStringLiteral("ShadowPresets")).toList();
    presets.append(preset);
    m_settings->setValue(QStringLiteral("ShadowPresets"), presets);
    updatePresets();
  }
}
<|endoftext|>