diff options
Diffstat (limited to 'SwifTools')
30 files changed, 620 insertions, 60 deletions
diff --git a/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp b/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp index 5eb0e16..e7a47a7 100644 --- a/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp +++ b/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -9,6 +9,7 @@ #include <string> #include <boost/algorithm/string.hpp> +#include <Swiften/Base/Path.h> #include <SwifTools/Application/PlatformApplicationPathProvider.h> using namespace Swift; @@ -40,7 +41,7 @@ class ApplicationPathProviderTest : public CppUnit::TestFixture { void testGetExecutableDir() { boost::filesystem::path dir = testling_->getExecutableDir(); CPPUNIT_ASSERT(boost::filesystem::is_directory(dir)); - CPPUNIT_ASSERT(boost::ends_with(dir.string(), "UnitTest")); + CPPUNIT_ASSERT(boost::ends_with(pathToString(dir), "UnitTest")); } private: diff --git a/SwifTools/Application/WindowsApplicationPathProvider.cpp b/SwifTools/Application/WindowsApplicationPathProvider.cpp index 8514fa7..2c61208 100644 --- a/SwifTools/Application/WindowsApplicationPathProvider.cpp +++ b/SwifTools/Application/WindowsApplicationPathProvider.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,6 +7,8 @@ #include <SwifTools/Application/WindowsApplicationPathProvider.h> #include <windows.h> +#include <cassert> +#include <Swiften/Base/String.h> namespace Swift { @@ -15,4 +17,21 @@ WindowsApplicationPathProvider::WindowsApplicationPathProvider(const std::string resourceDirs.push_back(getExecutableDir() / "../resources"); // Development } +boost::filesystem::path WindowsApplicationPathProvider::getDataDir() const { + wchar_t* appDirRaw = _wgetenv(L"APPDATA"); + assert(appDirRaw); + boost::filesystem::path result( + boost::filesystem::path(appDirRaw) / getApplicationName()); + boost::filesystem::create_directory(result); + return result; +} + +boost::filesystem::path WindowsApplicationPathProvider::getHomeDir() const { + //FIXME: This should be My Documents + wchar_t* homeDirRaw = _wgetenv(L"USERPROFILE"); + assert(homeDirRaw); + return boost::filesystem::path(homeDirRaw); +} + + } diff --git a/SwifTools/Application/WindowsApplicationPathProvider.h b/SwifTools/Application/WindowsApplicationPathProvider.h index f288326..a4e8668 100644 --- a/SwifTools/Application/WindowsApplicationPathProvider.h +++ b/SwifTools/Application/WindowsApplicationPathProvider.h @@ -13,19 +13,8 @@ namespace Swift { public: WindowsApplicationPathProvider(const std::string& name); - boost::filesystem::path getDataDir() const { - char* appDirRaw = getenv("APPDATA"); - boost::filesystem::path result(boost::filesystem::path(appDirRaw) / getApplicationName()); - boost::filesystem::create_directory(result); - return result; - } - - boost::filesystem::path getHomeDir() const { - //FIXME: This should be My Documents - - char* homeDirRaw = getenv("USERPROFILE"); - return boost::filesystem::path(homeDirRaw); - } + boost::filesystem::path getDataDir() const; + boost::filesystem::path getHomeDir() const; virtual std::vector<boost::filesystem::path> getResourceDirs() const { return resourceDirs; diff --git a/SwifTools/Cocoa/CocoaAction.h b/SwifTools/Cocoa/CocoaAction.h index a46ef7c..0ef993e 100644 --- a/SwifTools/Cocoa/CocoaAction.h +++ b/SwifTools/Cocoa/CocoaAction.h @@ -9,9 +9,7 @@ #include <Cocoa/Cocoa.h> #include <boost/function.hpp> -@interface CocoaAction : NSObject { - boost::function<void ()>* function; -} +@interface CocoaAction : NSObject /** * Acquires ownership of 'f'. diff --git a/SwifTools/Cocoa/CocoaAction.mm b/SwifTools/Cocoa/CocoaAction.mm index d560787..7162cd2 100644 --- a/SwifTools/Cocoa/CocoaAction.mm +++ b/SwifTools/Cocoa/CocoaAction.mm @@ -1,18 +1,20 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <SwifTools/Cocoa/CocoaAction.h> -@implementation CocoaAction +@implementation CocoaAction { + boost::function<void ()>* function; +} - (id) initWithFunction: (boost::function<void()>*) f { - if ([super init]) { - function = f; - } - return self; + if ((self = [super init])) { + function = f; + } + return self; } - (void) dealloc { diff --git a/SwifTools/CrashReporter.cpp b/SwifTools/CrashReporter.cpp index 4a07e40..f47ab33 100644 --- a/SwifTools/CrashReporter.cpp +++ b/SwifTools/CrashReporter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Remko Tronçon + * Copyright (c) 2012-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,6 +7,7 @@ #include <SwifTools/CrashReporter.h> #include <Swiften/Base/Platform.h> +#include <Swiften/Base/Path.h> #if defined(HAVE_BREAKPAD) @@ -51,16 +52,18 @@ CrashReporter::CrashReporter(const boost::filesystem::path& path) { p = boost::make_shared<Private>(); #if defined(SWIFTEN_PLATFORM_WINDOWS) // FIXME: Need UTF8 conversion from string to wstring - std::string pathString = path.string(); - p->handler = boost::make_shared<google_breakpad::ExceptionHandler>( - std::wstring(pathString.begin(), pathString.end()), - (google_breakpad::ExceptionHandler::FilterCallback) 0, - handleDump, - (void*) 0, - google_breakpad::ExceptionHandler::HANDLER_ALL); + std::string pathString = pathToString(path); + p->handler = boost::shared_ptr<google_breakpad::ExceptionHandler>( + // Not using make_shared, because 'handleDump' seems to have problems with VC2010 + new google_breakpad::ExceptionHandler( + std::wstring(pathString.begin(), pathString.end()), + (google_breakpad::ExceptionHandler::FilterCallback) 0, + handleDump, + (void*) 0, + google_breakpad::ExceptionHandler::HANDLER_ALL)); // Turning it off for Mac, because it doesn't really help us //#elif defined(SWIFTEN_PLATFORM_MACOSX) -// p->handler = boost::make_shared<google_breakpad::ExceptionHandler>(path.string(), (google_breakpad::ExceptionHandler::FilterCallback) 0, handleDump, (void*) 0, true, (const char*) 0); +// p->handler = boost::make_shared<google_breakpad::ExceptionHandler>(pathToString(path), (google_breakpad::ExceptionHandler::FilterCallback) 0, handleDump, (void*) 0, true, (const char*) 0); #endif } @@ -71,6 +74,6 @@ CrashReporter::CrashReporter(const boost::filesystem::path& path) { // Dummy implementation namespace Swift { CrashReporter::CrashReporter(const boost::filesystem::path&) {} -}; +} #endif diff --git a/SwifTools/HunspellChecker.cpp b/SwifTools/HunspellChecker.cpp new file mode 100644 index 0000000..ecd352e --- /dev/null +++ b/SwifTools/HunspellChecker.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <SwifTools/HunspellChecker.h> + +#include <algorithm> +#include <hunspell/hunspell.hxx> +#include <boost/algorithm/string.hpp> + + +namespace Swift { + +HunspellChecker::HunspellChecker(const char* affix_path, const char* dictionary_path) { + speller_ = new Hunspell(affix_path, dictionary_path); +} + +HunspellChecker::~HunspellChecker() { + delete speller_; +} + +bool HunspellChecker::isCorrect(const std::string& word) { + return speller_->spell(word.c_str()); +} + +void HunspellChecker::getSuggestions(const std::string& word, std::vector<std::string>& list) { + char **suggestList; + int words_returned; + if (!word.empty()) { + words_returned = speller_->suggest(&suggestList, word.c_str()); + } + for (int i = 0; i < words_returned; ++i) { + list.push_back(suggestList[i]); + free(suggestList[i]); + } + free(suggestList); +} + +void HunspellChecker::checkFragment(const std::string& fragment, PositionPairList& misspelledPositions) { + if (!fragment.empty()) { + parser_->check(fragment, misspelledPositions); + for (PositionPairList::iterator it = misspelledPositions.begin(); it != misspelledPositions.end();) { + if (isCorrect(fragment.substr(boost::get<0>(*it), boost::get<1>(*it) - boost::get<0>(*it)))) { + it = misspelledPositions.erase(it); + } + else { + ++it; + } + } + } +} + +} diff --git a/SwifTools/HunspellChecker.h b/SwifTools/HunspellChecker.h new file mode 100644 index 0000000..12c0485 --- /dev/null +++ b/SwifTools/HunspellChecker.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <vector> +#include <boost/algorithm/string.hpp> +#include <boost/tuple/tuple.hpp> +#include <SwifTools/SpellChecker.h> + +#pragma once + +class Hunspell; + +namespace Swift { + class HunspellChecker : public SpellChecker { + public: + HunspellChecker(const char* affix_path, const char* dict_path); + virtual ~HunspellChecker(); + virtual bool isCorrect(const std::string& word); + virtual void getSuggestions(const std::string& word, std::vector<std::string>& list); + virtual void checkFragment(const std::string& fragment, PositionPairList& misspelledPositions); + private: + Hunspell* speller_; + }; +} diff --git a/SwifTools/Idle/IdleQuerierTest/IdleQuerierTest.cpp b/SwifTools/Idle/IdleQuerierTest/IdleQuerierTest.cpp index df233a2..41238a0 100644 --- a/SwifTools/Idle/IdleQuerierTest/IdleQuerierTest.cpp +++ b/SwifTools/Idle/IdleQuerierTest/IdleQuerierTest.cpp @@ -5,6 +5,7 @@ */ #include <iostream> +#include <cassert> #include <SwifTools/Idle/PlatformIdleQuerier.h> #include <Swiften/Base/sleep.h> @@ -17,6 +18,6 @@ int main() { std::cout << "Idle time: " << querier.getIdleTimeSeconds() << std::endl; Swift::sleep(1000); } - + assert(false); return 0; } diff --git a/SwifTools/Idle/MacOSXIdleQuerier.cpp b/SwifTools/Idle/MacOSXIdleQuerier.cpp index 233d7c6..8eaece6 100644 --- a/SwifTools/Idle/MacOSXIdleQuerier.cpp +++ b/SwifTools/Idle/MacOSXIdleQuerier.cpp @@ -10,6 +10,7 @@ #include <cassert> #include <iostream> +#include <boost/numeric/conversion/cast.hpp> #include <CoreFoundation/CoreFoundation.h> namespace Swift { @@ -28,7 +29,7 @@ int MacOSXIdleQuerier::getIdleTimeSeconds() { assert(result); (void) result; CFRelease(property); - return idle / 1000000000; + return boost::numeric_cast<int>(idle / 1000000000); } } diff --git a/SwifTools/Linkify.cpp b/SwifTools/Linkify.cpp index 906026d..8ecbb09 100644 --- a/SwifTools/Linkify.cpp +++ b/SwifTools/Linkify.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -49,4 +49,55 @@ std::string Linkify::linkify(const std::string& input) { return std::string(result.str()); } +std::pair<std::vector<std::string>, size_t> Linkify::splitLink(const std::string& input) { + std::vector<std::string> result; + std::pair<std::vector<std::string>, size_t> pair; + std::vector<char> currentURL; + bool inURL = false; + size_t urlStartsAt = 0; + for (size_t i = 0; i < input.size(); ++i) { + char c = input[i]; + if (inURL) { + if (c != ' ' && c != '\t' && c != '\n' && !(c == '*' && i == input.size() - 1 && input[0] == '*')) { + // Keep parsing + } + else { + std::string url(input.substr(urlStartsAt, i - urlStartsAt)); + result.push_back(url); + inURL = false; + size_t remaining = input.size() - i; + if (remaining > 0) { + result.push_back(input.substr(i, remaining)); + } + pair.first = result; + pair.second = urlStartsAt == 0 ? 0 : 1; + return pair; + } + } + else { + if (boost::regex_match(input.substr(i, 8), linkifyRegexp)) { + urlStartsAt = i; + inURL = true; + if (i > 0) { + result.push_back(input.substr(0, i)); + } + } + else { + // Just keep swimming + } + } + } + if (urlStartsAt > 0 || inURL) { + std::string url(input.substr(urlStartsAt, input.size() - urlStartsAt)); + result.push_back(url); + pair.first = result; + pair.second = urlStartsAt == 0 ? 0 : 1; + } + else { + pair.first.push_back(input); + pair.second = 1; + } + return pair; +} + } diff --git a/SwifTools/Linkify.h b/SwifTools/Linkify.h index ebe232f..0a9c132 100644 --- a/SwifTools/Linkify.h +++ b/SwifTools/Linkify.h @@ -1,15 +1,27 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once +#include <vector> #include <string> namespace Swift { namespace Linkify { std::string linkify(const std::string&); + /** + * Parse the string for a URI. The string will be split by the URI, and the segments plus index of the URI returned. + * If no URI is found the index will be result.size() (i.e. an invalid index) + * + * Examples: + * "not a URI" -> <<"not a URI">, -1> + * "http://swift.im" -> <<"http://swift.im">, 0 + * " See http://swift.im" -> <<" See ", "http://swift.im">, 1> + * "Right, http://swift.im it is" -> <<"Right, ", "http://swift.im", " it is">, 1> + */ + std::pair<std::vector<std::string>, size_t> splitLink(const std::string& text); } } diff --git a/SwifTools/MacOSXChecker.h b/SwifTools/MacOSXChecker.h new file mode 100644 index 0000000..f2f8ebc --- /dev/null +++ b/SwifTools/MacOSXChecker.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <vector> +#include <boost/tuple/tuple.hpp> +#include <SwifTools/SpellChecker.h> + +namespace Swift { + class MacOSXChecker : public SpellChecker { + public: + MacOSXChecker(); + virtual ~MacOSXChecker(); + virtual bool isCorrect(const std::string& word); + virtual void getSuggestions(const std::string& word, std::vector<std::string>& list); + virtual void checkFragment(const std::string& fragment, PositionPairList& misspelledPositions); + }; +} diff --git a/SwifTools/MacOSXChecker.mm b/SwifTools/MacOSXChecker.mm new file mode 100644 index 0000000..3e687d1 --- /dev/null +++ b/SwifTools/MacOSXChecker.mm @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <SwifTools/MacOSXChecker.h> + +#include <algorithm> +#include <boost/algorithm/string.hpp> + +#include <AppKit/AppKit.h> + +namespace Swift { + +MacOSXChecker::MacOSXChecker() { +} + +MacOSXChecker::~MacOSXChecker() { +} + +bool MacOSXChecker::isCorrect(const std::string& /*word*/) { + // No content since it doesn't seem to be used anywhere. + return false; +} + +void MacOSXChecker::getSuggestions(const std::string& word, std::vector<std::string>& list) { + NSSpellChecker* spellChecker = [NSSpellChecker sharedSpellChecker]; + NSString* wordString = [[NSString alloc] initWithUTF8String: word.c_str()]; + NSArray* suggestions = [spellChecker guessesForWord: wordString]; + for(unsigned int i = 0; i < [suggestions count]; ++i) { + list.push_back(std::string([[suggestions objectAtIndex:i] UTF8String])); + } + [wordString release]; +} + +void MacOSXChecker::checkFragment(const std::string& fragment, PositionPairList& misspelledPositions) { + NSSpellChecker* spellChecker = [NSSpellChecker sharedSpellChecker]; + size_t nextLocation = 0; + NSRange range; + NSString *fragmentString = [[NSString alloc] initWithUTF8String: fragment.c_str()]; + do { + range = [spellChecker checkSpellingOfString:fragmentString startingAt:static_cast<long>(nextLocation)]; + if (range.location != NSNotFound) { + if (range.location < nextLocation) + break; + misspelledPositions.push_back(PositionPair(static_cast<int>(range.location), static_cast<int>(range.location + range.length))); + nextLocation = range.location + range.length + 1; + } + } while (range.location != NSNotFound); + [fragmentString release]; +} + +} diff --git a/SwifTools/Notifier/GNTPNotifier.cpp b/SwifTools/Notifier/GNTPNotifier.cpp index 9bc05bd..757594f 100644 --- a/SwifTools/Notifier/GNTPNotifier.cpp +++ b/SwifTools/Notifier/GNTPNotifier.cpp @@ -14,6 +14,7 @@ #include <sstream> #include <Swiften/Base/foreach.h> +#include <Swiften/Base/Path.h> #include <Swiften/Network/ConnectionFactory.h> namespace Swift { @@ -23,7 +24,7 @@ GNTPNotifier::GNTPNotifier(const std::string& name, const boost::filesystem::pat std::ostringstream message; message << "GNTP/1.0 REGISTER NONE\r\n"; message << "Application-Name: " << name << "\r\n"; - message << "Application-Icon: file://" << icon.string() << "\r\n"; + message << "Application-Icon: file://" << pathToString(icon) << "\r\n"; message << "Notifications-Count: " << getAllTypes().size() << "\r\n"; std::vector<Notifier::Type> defaultTypes = getDefaultTypes(); std::vector<Notifier::Type> allTypes = getAllTypes(); @@ -59,7 +60,7 @@ void GNTPNotifier::showMessage(Type type, const std::string& subject, const std: message << "Notification-Name: " << typeToString(type) << "\r\n"; message << "Notification-Title: " << subject << "\r\n"; message << "Notification-Text: " << description << "\r\n"; - message << "Notification-Icon: " << picture.string() << "\r\n"; + message << "Notification-Icon: " << pathToString(picture) << "\r\n"; message << "\r\n"; send(message.str()); } diff --git a/SwifTools/Notifier/GrowlNotifier.mm b/SwifTools/Notifier/GrowlNotifier.mm index c1996d9..2ababf4 100644 --- a/SwifTools/Notifier/GrowlNotifier.mm +++ b/SwifTools/Notifier/GrowlNotifier.mm @@ -65,7 +65,7 @@ GrowlNotifier::~GrowlNotifier() { void GrowlNotifier::showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picturePath, boost::function<void()> callback) { ByteArray picture; - readByteArrayFromFile(picture, picturePath.string()); + readByteArrayFromFile(picture, picturePath); Context* context = new Context(callback); // Growl sometimes sends timeout notifications twice for the same message. We therefore need diff --git a/SwifTools/Notifier/GrowlNotifierDelegate.mm b/SwifTools/Notifier/GrowlNotifierDelegate.mm index 6952cab..e184da6 100644 --- a/SwifTools/Notifier/GrowlNotifierDelegate.mm +++ b/SwifTools/Notifier/GrowlNotifierDelegate.mm @@ -8,7 +8,7 @@ #include <SwifTools/Notifier/GrowlNotifier.h> -@implementation GrowlNotifierDelegate; +@implementation GrowlNotifierDelegate @synthesize registrationDictionary; @synthesize name; diff --git a/SwifTools/SConscript b/SwifTools/SConscript index fa2686a..b9822e0 100644 --- a/SwifTools/SConscript +++ b/SwifTools/SConscript @@ -30,9 +30,25 @@ if env["SCONS_STAGE"] == "build" : "TabComplete.cpp", "LastLineTracker.cpp", ] + + if swiftools_env["HAVE_HUNSPELL"] : + swiftools_env.UseFlags(swiftools_env["HUNSPELL_FLAGS"]) + swiftools_env.Append(CPPDEFINES = ["HAVE_HUNSPELL"]) + sources += [ + "SpellCheckerFactory.cpp", + "HunspellChecker.cpp", + "SpellParser.cpp", + ] + elif swiftools_env["PLATFORM"] == "darwin" and env["target"] == "native" : + sources += [ + "SpellCheckerFactory.cpp", + "MacOSXChecker.mm", + "SpellParser.cpp", + ] + if swiftools_env.get("HAVE_SPARKLE", 0) : - swiftools_env.MergeFlags(swiftools_env["SPARKLE_FLAGS"]) + swiftools_env.UseFlags(swiftools_env["SPARKLE_FLAGS"]) swiftools_env.Append(CPPDEFINES = ["HAVE_SPARKLE"]) sources += ["AutoUpdater/SparkleAutoUpdater.mm"] @@ -45,8 +61,8 @@ if env["SCONS_STAGE"] == "build" : swiftools_env.Append(CPPDEFINES = ["HAVE_XSS"]) sources += ["Idle/XSSIdleQuerier.cpp"] - swiftools_env.UseFlags(swiftools_env["BREAKPAD_FLAGS"]) - if env["HAVE_BREAKPAD"] : + if env.get("HAVE_BREAKPAD", False) : + swiftools_env.UseFlags(swiftools_env["BREAKPAD_FLAGS"]) swiftools_env.Append(CPPDEFINES = ["HAVE_BREAKPAD"]) sources += ["CrashReporter.cpp"] diff --git a/SwifTools/SpellChecker.h b/SwifTools/SpellChecker.h new file mode 100644 index 0000000..fd38418 --- /dev/null +++ b/SwifTools/SpellChecker.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <SwifTools/SpellParser.h> + +#include <boost/algorithm/string.hpp> +#include <boost/tuple/tuple.hpp> +#include <vector> + +#pragma once + +namespace Swift { + class SpellChecker { + public: + SpellChecker() { + parser_ = new SpellParser(); + } + virtual ~SpellChecker() { + delete parser_; + } + virtual bool isCorrect(const std::string& word) = 0; + virtual void getSuggestions(const std::string& word, std::vector<std::string>& list) = 0; + virtual void checkFragment(const std::string& fragment, PositionPairList& misspelledPositions) = 0; + protected: + SpellParser *parser_; + }; +} diff --git a/SwifTools/SpellCheckerFactory.cpp b/SwifTools/SpellCheckerFactory.cpp new file mode 100644 index 0000000..428e1a5 --- /dev/null +++ b/SwifTools/SpellCheckerFactory.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <boost/filesystem/operations.hpp> + +#include <SwifTools/SpellChecker.h> +#include <SwifTools/HunspellChecker.h> +#include <SwifTools/SpellCheckerFactory.h> +#include <Swiften/Base/Platform.h> + +#ifdef HAVE_HUNSPELL +#include <hunspell/hunspell.hxx> +#elif defined(SWIFTEN_PLATFORM_MACOSX) +#include <SwifTools/MacOSXChecker.h> +#endif + +namespace Swift { + +SpellCheckerFactory::SpellCheckerFactory() { +} + +#ifdef HAVE_HUNSPELL +SpellChecker* SpellCheckerFactory::createSpellChecker(const std::string& dictFile) { + std::string affixFile(dictFile); + boost::replace_all(affixFile, ".dic", ".aff"); + if ((boost::filesystem::exists(dictFile)) && (boost::filesystem::exists(affixFile))) { + return new HunspellChecker(affixFile.c_str(), dictFile.c_str()); + } + // If dictionaries don't exist disable the checker + return NULL; +} +#elif defined(SWIFTEN_PLATFORM_MACOSX) +SpellChecker* SpellCheckerFactory::createSpellChecker(const std::string& /*dictFile*/) { + return new MacOSXChecker(); +} +#endif + +} diff --git a/SwifTools/SpellCheckerFactory.h b/SwifTools/SpellCheckerFactory.h new file mode 100644 index 0000000..91118f9 --- /dev/null +++ b/SwifTools/SpellCheckerFactory.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Platform.h> + +#ifdef HAVE_HUNSPELL +#define HAVE_SPELLCHECKER +#elif defined(SWIFTEN_PLATFORM_MACOSX) +#define HAVE_SPELLCHECKER +#endif + +namespace Swift { + class SpellChecker; + class SpellCheckerFactory { + public: + SpellCheckerFactory(); + SpellChecker* createSpellChecker(const std::string& dictFile); + }; +} diff --git a/SwifTools/SpellParser.cpp b/SwifTools/SpellParser.cpp new file mode 100644 index 0000000..8cb42e4 --- /dev/null +++ b/SwifTools/SpellParser.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011-2013 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <SwifTools/SpellParser.h> + +#include <boost/spirit/include/lex_lexertl.hpp> +#include <boost/bind.hpp> +#include <boost/ref.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <string> + +namespace lex = boost::spirit::lex; + +namespace Swift { + +template <typename Lexer> +struct word_count_tokens : lex::lexer<Lexer> +{ + word_count_tokens() + { + // define tokens (regular expresions) to match strings + // order is important + this->self.add + ("w{3}.[^ ]+", ID_WWW) + ("http:\\/\\/[^ ]+", ID_HTTP) + ("\\w{1,}['?|\\-?]?\\w{1,}", ID_WORD) + (".", ID_CHAR); + } +}; + +struct counter +{ + typedef bool result_type; + // the function operator gets called for each of the matched tokens + template <typename Token> + bool operator()(Token const& t, PositionPairList& wordPositions, std::size_t& position) const + { + switch (t.id()) { + case ID_WWW: + position += boost::numeric_cast<size_t>(t.value().size()); + break; + case ID_HTTP: + position += boost::numeric_cast<size_t>(t.value().size()); + break; + case ID_WORD: // matched a word + wordPositions.push_back(boost::tuples::make_tuple(position, position + boost::numeric_cast<size_t>(t.value().size()))); + position += boost::numeric_cast<size_t>(t.value().size()); + break; + case ID_CHAR: // match a simple char + ++position; + break; + } + return true; // always continue to tokenize + } +}; + +void SpellParser::check(const std::string& fragment, PositionPairList& wordPositions) { + std::size_t position = 0; + // create the token definition instance needed to invoke the lexical analyzer + word_count_tokens<lex::lexertl::lexer<> > word_count_functor; + char const* first = fragment.c_str(); + char const* last = &first[fragment.size()]; + lex::tokenize(first, last, word_count_functor, boost::bind(counter(), _1, boost::ref(wordPositions), boost::ref(position))); +} + +} diff --git a/SwifTools/SpellParser.h b/SwifTools/SpellParser.h new file mode 100644 index 0000000..b64565c --- /dev/null +++ b/SwifTools/SpellParser.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/algorithm/string.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/algorithm/string.hpp> + +#include <vector> + +namespace Swift { + enum token_ids + { + ID_WWW = 1, + ID_HTTP = 2, + ID_WORD = 3, + ID_CHAR = 4 + }; + + typedef boost::tuple<int, int> PositionPair; + typedef std::vector<PositionPair > PositionPairList; + + class SpellParser{ + public: + void check(const std::string& fragment, PositionPairList& wordPositions); + }; +} diff --git a/SwifTools/URIHandler/MacOSXURIHandler.mm b/SwifTools/URIHandler/MacOSXURIHandler.mm index 0575d47..cdfba33 100644 --- a/SwifTools/URIHandler/MacOSXURIHandler.mm +++ b/SwifTools/URIHandler/MacOSXURIHandler.mm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -12,15 +12,20 @@ using namespace Swift; @interface MacOSXURIEventHandler : NSObject { - URIHandler* handler; } + - (id) initWithHandler: (URIHandler*) handler; - (void) getUrl: (NSAppleEventDescriptor*) event withReplyEvent: (NSAppleEventDescriptor*) replyEvent; @end + @implementation MacOSXURIEventHandler + { + URIHandler* handler; + } + - (id) initWithHandler: (URIHandler*) h { - if ([super init]) { + if ((self = [super init])) { handler = h; } return self; diff --git a/SwifTools/URIHandler/UnitTest/XMPPURITest.cpp b/SwifTools/URIHandler/UnitTest/XMPPURITest.cpp index 8d03b60..35020da 100644 --- a/SwifTools/URIHandler/UnitTest/XMPPURITest.cpp +++ b/SwifTools/URIHandler/UnitTest/XMPPURITest.cpp @@ -65,9 +65,9 @@ class XMPPURITest : public CppUnit::TestFixture { } void testFromString_AuthorityWithIntlChars() { - XMPPURI testling = XMPPURI::fromString("xmpp://nasty!%23$%25()*+,-.;=\%3F\%5B\%5C\%5D\%5E_\%60\%7B\%7C\%7D~node@example.com"); + XMPPURI testling = XMPPURI::fromString("xmpp://nasty!%23$%25()*+,-.;=%3F%5B%5C%5D%5E_%60%7B%7C%7D~node@example.com"); - CPPUNIT_ASSERT_EQUAL(JID("nasty!#$\%()*+,-.;=?[\\]^_`{|}~node@example.com"), testling.getAuthority()); + CPPUNIT_ASSERT_EQUAL(JID("nasty!#$%()*+,-.;=?[\\]^_`{|}~node@example.com"), testling.getAuthority()); } void testFromString_AuthorityWithQueryWithoutParameters() { @@ -118,9 +118,9 @@ class XMPPURITest : public CppUnit::TestFixture { } void testFromString_PathWithIntlChars() { - XMPPURI testling = XMPPURI::fromString("xmpp:nasty!%23$%25()*+,-.;=\%3F\%5B\%5C\%5D\%5E_\%60\%7B\%7C\%7D~node@example.com"); + XMPPURI testling = XMPPURI::fromString("xmpp:nasty!%23$%25()*+,-.;=%3F%5B%5C%5D%5E_%60%7B%7C%7D~node@example.com"); - CPPUNIT_ASSERT_EQUAL(JID("nasty!#$\%()*+,-.;=?[\\]^_`{|}~node@example.com"), testling.getPath()); + CPPUNIT_ASSERT_EQUAL(JID("nasty!#$%()*+,-.;=?[\\]^_`{|}~node@example.com"), testling.getPath()); } void testFromString_PathWithInvalidEscapedChar() { diff --git a/SwifTools/UnitTest/LastLineTrackerTest.cpp b/SwifTools/UnitTest/LastLineTrackerTest.cpp index a7046ed..97790e5 100644 --- a/SwifTools/UnitTest/LastLineTrackerTest.cpp +++ b/SwifTools/UnitTest/LastLineTrackerTest.cpp @@ -21,7 +21,7 @@ class LastLineTrackerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE_END(); public: LastLineTrackerTest () { - }; + } void testFocusNormal() { LastLineTracker testling; testling.setHasFocus(true); diff --git a/SwifTools/UnitTest/LinkifyTest.cpp b/SwifTools/UnitTest/LinkifyTest.cpp index 5df1a96..c464b50 100644 --- a/SwifTools/UnitTest/LinkifyTest.cpp +++ b/SwifTools/UnitTest/LinkifyTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -32,6 +32,12 @@ class LinkifyTest : public CppUnit::TestFixture { CPPUNIT_TEST(testLinkify_NewLine); CPPUNIT_TEST(testLinkify_Tab); CPPUNIT_TEST(testLinkify_Action); + + CPPUNIT_TEST(testLinkify_SplitNone); + CPPUNIT_TEST(testLinkify_SplitAll); + CPPUNIT_TEST(testLinkify_SplitFirst); + CPPUNIT_TEST(testLinkify_SplitSecond); + CPPUNIT_TEST(testLinkify_SplitMiddle); CPPUNIT_TEST_SUITE_END(); public: @@ -181,12 +187,57 @@ class LinkifyTest : public CppUnit::TestFixture { } void testLinkify_Action() { - std::string result = Linkify::linkify("*http://swift.im*"); + std::string result = Linkify::linkify("*http://swift.im*"); + + CPPUNIT_ASSERT_EQUAL( + std::string("*<a href=\"http://swift.im\">http://swift.im</a>*"), + result); + } - CPPUNIT_ASSERT_EQUAL( - std::string("*<a href=\"http://swift.im\">http://swift.im</a>*"), - result); + void checkResult(const std::string& testling, size_t expectedIndex, std::string expectedSplit[]) { + std::pair<std::vector<std::string>, size_t> result = Linkify::splitLink(testling); + CPPUNIT_ASSERT_EQUAL(expectedIndex, result.second); + for (size_t i = 0; i < result.first.size(); i++) { + CPPUNIT_ASSERT_EQUAL(expectedSplit[i], result.first[i]); } + } + + void testLinkify_SplitNone() { + std::string testling = "http this ain't"; + size_t expectedIndex = 1; + std::string expectedSplit[] = {"http this ain't"}; + checkResult(testling, expectedIndex, expectedSplit); + } + + void testLinkify_SplitAll() { + std::string testling = "http://swift.im"; + size_t expectedIndex = 0; + std::string expectedSplit[] = {"http://swift.im"}; + checkResult(testling, expectedIndex, expectedSplit); + } + + void testLinkify_SplitFirst() { + std::string testling = "http://swift.im is a link"; + size_t expectedIndex = 0; + std::string expectedSplit[] = {"http://swift.im", " is a link"}; + checkResult(testling, expectedIndex, expectedSplit); + } + + void testLinkify_SplitSecond() { + std::string testling = "this is a link: http://swift.im"; + size_t expectedIndex = 1; + std::string expectedSplit[] = {"this is a link: ", "http://swift.im"}; + checkResult(testling, expectedIndex, expectedSplit); + } + + void testLinkify_SplitMiddle() { + std::string testling = "Shove a link like http://swift.im in the middle"; + size_t expectedIndex = 1; + std::string expectedSplit[] = {"Shove a link like ","http://swift.im", " in the middle"}; + checkResult(testling, expectedIndex, expectedSplit); + } + + }; CPPUNIT_TEST_SUITE_REGISTRATION(LinkifyTest); diff --git a/SwifTools/UnitTest/SConscript b/SwifTools/UnitTest/SConscript index e469deb..dbd1ce5 100644 --- a/SwifTools/UnitTest/SConscript +++ b/SwifTools/UnitTest/SConscript @@ -5,3 +5,8 @@ env.Append(UNITTEST_SOURCES = [ File("TabCompleteTest.cpp"), File("LastLineTrackerTest.cpp"), ]) + +if env["HAVE_HUNSPELL"] : + env.Append(UNITTEST_SOURCES = [ + File("SpellParserTest.cpp"), + ]) diff --git a/SwifTools/UnitTest/SpellParserTest.cpp b/SwifTools/UnitTest/SpellParserTest.cpp new file mode 100644 index 0000000..09e686c --- /dev/null +++ b/SwifTools/UnitTest/SpellParserTest.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <boost/algorithm/string.hpp> + +#include <SwifTools/SpellParser.h> + +using namespace Swift; + +class SpellParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(SpellParserTest); + CPPUNIT_TEST(testSimpleCheckFragment); + CPPUNIT_TEST(testWWWCheckFragment); + CPPUNIT_TEST_SUITE_END(); + public: + SpellParserTest() { + parser_ = new SpellParser(); + }; + void tearDown() { + position_.clear(); + } + void testSimpleCheckFragment() { + parser_->check("fragment test", position_); + int size = position_.size(); + CPPUNIT_ASSERT_EQUAL(2, size); + CPPUNIT_ASSERT_EQUAL(0, boost::get<0>(position_.front())); + CPPUNIT_ASSERT_EQUAL(8, boost::get<1>(position_.front())); + CPPUNIT_ASSERT_EQUAL(9, boost::get<0>(position_.back())); + CPPUNIT_ASSERT_EQUAL(13, boost::get<1>(position_.back())); + } + void testWWWCheckFragment() { + parser_->check("www.link.com fragment test", position_); + int size = position_.size(); + CPPUNIT_ASSERT_EQUAL(2, size); + CPPUNIT_ASSERT_EQUAL(13, boost::get<0>(position_.front())); + CPPUNIT_ASSERT_EQUAL(21, boost::get<1>(position_.front())); + CPPUNIT_ASSERT_EQUAL(22, boost::get<0>(position_.back())); + CPPUNIT_ASSERT_EQUAL(26, boost::get<1>(position_.back())); + } + private: + SpellParser *parser_; + PositionPairList position_; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(SpellParserTest); diff --git a/SwifTools/UnitTest/TabCompleteTest.cpp b/SwifTools/UnitTest/TabCompleteTest.cpp index 0466484..cdb0296 100644 --- a/SwifTools/UnitTest/TabCompleteTest.cpp +++ b/SwifTools/UnitTest/TabCompleteTest.cpp @@ -24,7 +24,7 @@ class TabCompleteTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE_END(); public: - TabCompleteTest() {}; + TabCompleteTest() {} void setUp() { completer_ = TabComplete(); |