From be5460f2a294bb8e50b40f498f29a556b31bedd7 Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Sat, 31 Oct 2009 15:42:28 +0200 Subject: Chat auto completing --- src/beingmanager.cpp | 35 ++++++++++++++++ src/beingmanager.h | 2 + src/gui/chat.cpp | 92 +++++++++++++++++++++++++++++++++++++++++- src/gui/chat.h | 4 ++ src/gui/partywindow.cpp | 34 ++++++++++++++++ src/gui/partywindow.h | 2 + src/gui/widgets/chattab.cpp | 5 +++ src/gui/widgets/chattab.h | 13 ++++++ src/gui/widgets/textfield.cpp | 8 +++- src/gui/widgets/textfield.h | 4 +- src/gui/widgets/whispertab.cpp | 5 +++ src/gui/widgets/whispertab.h | 2 + src/net/ea/gui/partytab.cpp | 5 +++ src/net/ea/gui/partytab.h | 2 + src/utils/stringutils.cpp | 18 +++++++++ src/utils/stringutils.h | 4 ++ 16 files changed, 230 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp index 724ac899..74461d44 100644 --- a/src/beingmanager.cpp +++ b/src/beingmanager.cpp @@ -26,6 +26,7 @@ #include "npc.h" #include "player.h" +#include "utils/stringutils.h" #include "utils/dtor.h" #include @@ -298,3 +299,37 @@ bool BeingManager::hasBeing(Being *being) const return false; } + +std::string BeingManager::getAutoCompletePlayerName(std::string partName) +{ + Beings::iterator i = mBeings.begin(); + std::transform(partName.begin(), partName.end(), partName.begin(), tolower); + std::string newName(""); + + while (i != mBeings.end()) + { + Being *being = (*i); + if (being->getType() != Being::MONSTER && being->getName() != "") + { + std::string name = being->getName(); + std::transform(name.begin(), name.end(), name.begin(), tolower); + + std::string::size_type pos = name.find(partName, 0); + if (pos == 0) + { + if (newName != "") + { + std::transform(newName.begin(), newName.end(), newName.begin(), tolower); + newName = findSameSubstring(name, newName); + } + else + { + newName = being->getName(); + } + } + } + ++i; + } + + return newName; +} diff --git a/src/beingmanager.h b/src/beingmanager.h index 0150f373..4490738e 100644 --- a/src/beingmanager.h +++ b/src/beingmanager.h @@ -118,6 +118,8 @@ class BeingManager */ void clear(); + std::string getAutoCompletePlayerName(std::string partName); + protected: Beings mBeings; Map *mMap; diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp index c0597a64..3c4961cf 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -25,6 +25,7 @@ #include "gui/recorder.h" #include "gui/setup.h" #include "gui/sdlinput.h" +#include "gui/partywindow.h" #include "gui/widgets/chattab.h" #include "gui/widgets/scrollarea.h" @@ -54,7 +55,8 @@ class ChatInput : public TextField, public gcn::FocusListener { public: - ChatInput() + ChatInput(): + TextField("", false) { setVisible(false); addFocusListener(this); @@ -394,6 +396,12 @@ void ChatWindow::keyPressed(gcn::KeyEvent &event) mChatInput->setText(*mCurHist); mChatInput->setCaretPosition(mChatInput->getText().length()); } + else if (event.getKey().getValue() == Key::TAB && + mChatInput->getText() != "") + { + autoComplete(); + return; + } } void ChatWindow::addInputText(const std::string &text) @@ -499,3 +507,85 @@ ChatTab *ChatWindow::addWhisperTab(const std::string &nick, bool switchTo) return ret; } + +void ChatWindow::autoComplete() +{ + int caretPos = mChatInput->getCaretPosition(); + int startName = 0; + const std::string inputText = mChatInput->getText(); + std::string name = inputText.substr(0, caretPos); + std::string newName(""); + + for (int f = caretPos - 1; f > -1; f --) + { + if (isWordSeparator(inputText[f])) + { + startName = f + 1; + name = inputText.substr(f + 1, caretPos - f); + break; + } + } + + if (caretPos - 1 + 1 == startName) + return; + + + ChatTab *cTab = static_cast(mChatTabs->getSelectedTab()); + if (cTab && cTab->getType() == ChatTab::PARTY) + { + newName = partyWindow->getAutoCompleteName(name); + } + if (newName == "") + { + newName = beingManager->getAutoCompletePlayerName(name); + } + if (newName == "") + { + newName = autoCompleteHistory(name); + } + + if (newName != "") + { + mChatInput->setText(inputText.substr(0, startName) + newName + + inputText.substr(caretPos, inputText.length() - caretPos)); + + if (startName > 0) + mChatInput->setCaretPosition(caretPos - name.length() + newName.length() + 1); + else + mChatInput->setCaretPosition(caretPos - name.length() + newName.length()); + } +} + +std::string ChatWindow::autoCompleteHistory(std::string partName) +{ + History::iterator i = mHistory.begin(); + std::string newName = ""; + + while (i != mHistory.end()) + { + std::string line = *i; + int f = 0; + while (f < line.length() && !isWordSeparator(line.at(f))) + { + f++; + } + line = line.substr(0, f); + if (line != "") + { + std::string::size_type pos = line.find(partName, 0); + if (pos == 0) + { + if (newName != "") + { + newName = findSameSubstring(line, newName); + } + else + { + newName = line; + } + } + } + ++i; + } + return newName; +} diff --git a/src/gui/chat.h b/src/gui/chat.h index af5f760b..b64ea5e8 100644 --- a/src/gui/chat.h +++ b/src/gui/chat.h @@ -187,6 +187,10 @@ class ChatWindow : public Window, void removeWhisper(const std::string &nick); + void autoComplete(); + + std::string autoCompleteHistory(std::string partName); + /** Used for showing item popup on clicking links **/ ItemLinkHandler *mItemLinkHandler; Recorder *mRecorder; diff --git a/src/gui/partywindow.cpp b/src/gui/partywindow.cpp index 72e983d5..ae8112c8 100644 --- a/src/gui/partywindow.cpp +++ b/src/gui/partywindow.cpp @@ -253,3 +253,37 @@ void PartyWindow::buildLayout() lastPos += member->mAvatar->getHeight() + 2; } } + +std::string PartyWindow::getAutoCompleteName(std::string partName) +{ + PartyList::iterator i = mMembers.begin(); + std::transform(partName.begin(), partName.end(), partName.begin(), tolower); + std::string newName(""); + + while (i != mMembers.end()) + { + PartyMember *member = (*i).second; + if (member->getAvatar() && member->getAvatar()->getName() != "") + { + std::string name = member->getAvatar()->getName(); + std::transform(name.begin(), name.end(), name.begin(), tolower); + + std::string::size_type pos = name.find(partName, 0); + if (pos == 0) + { + if (newName != "") + { + std::transform(newName.begin(), newName.end(), newName.begin(), tolower); + newName = findSameSubstring(name, newName); + } + else + { + newName = member->getAvatar()->getName(); + } + } + } + ++i; + } + + return newName; +} diff --git a/src/gui/partywindow.h b/src/gui/partywindow.h index 7f366fd1..ed217910 100644 --- a/src/gui/partywindow.h +++ b/src/gui/partywindow.h @@ -127,6 +127,8 @@ class PartyWindow : public Window, gcn::ActionListener void clearMembers(); + std::string getAutoCompleteName(std::string partName); + private: /** * Find a party member based on ID. Creates if not found. diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp index e3ba4874..443fab3d 100644 --- a/src/gui/widgets/chattab.cpp +++ b/src/gui/widgets/chattab.cpp @@ -270,3 +270,8 @@ void ChatTab::handleCommand(const std::string &msg) { commandHandler->handleCommand(msg, this); } + +int ChatTab::getType() const +{ + return INPUT; +} diff --git a/src/gui/widgets/chattab.h b/src/gui/widgets/chattab.h index 4cb6a58f..40a1c1f5 100644 --- a/src/gui/widgets/chattab.h +++ b/src/gui/widgets/chattab.h @@ -47,6 +47,14 @@ enum class ChatTab : public Tab { public: + enum Type + { + UNKNOWN, + INPUT, + WHISPER, + PARTY + }; + /** * Constructor. */ @@ -110,6 +118,11 @@ class ChatTab : public Tab const std::string &args) { return false; } + /** + * Returns type of the being. + */ + virtual int getType() const; + protected: friend class ChatWindow; friend class WhisperWindow; diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp index f19b4d82..0f0caa00 100644 --- a/src/gui/widgets/textfield.cpp +++ b/src/gui/widgets/textfield.cpp @@ -41,12 +41,14 @@ int TextField::instances = 0; float TextField::mAlpha = 1.0; ImageRect TextField::skin; -TextField::TextField(const std::string &text): +TextField::TextField(const std::string &text, bool loseFocusOnTab): gcn::TextField(text), mNumeric(false) { setFrameSize(2); + mLoseFocusOnTab = loseFocusOnTab; + if (instances == 0) { // Load the skin @@ -245,7 +247,9 @@ void TextField::keyPressed(gcn::KeyEvent &keyEvent) break; case Key::TAB: - return; + if (mLoseFocusOnTab) + return; + break; } keyEvent.consume(); diff --git a/src/gui/widgets/textfield.h b/src/gui/widgets/textfield.h index 9130e441..e101e112 100644 --- a/src/gui/widgets/textfield.h +++ b/src/gui/widgets/textfield.h @@ -38,8 +38,7 @@ class TextField : public gcn::TextField /** * Constructor, initializes the text field with the given string. */ - TextField(const std::string &text = ""); - + TextField(const std::string &text = "", bool loseFocusOnTab = true); ~TextField(); /** @@ -98,6 +97,7 @@ class TextField : public gcn::TextField bool mNumeric; int mMinimum; int mMaximum; + bool mLoseFocusOnTab; }; #endif diff --git a/src/gui/widgets/whispertab.cpp b/src/gui/widgets/whispertab.cpp index 5509a589..537aa2cc 100644 --- a/src/gui/widgets/whispertab.cpp +++ b/src/gui/widgets/whispertab.cpp @@ -113,3 +113,8 @@ bool WhisperTab::handleCommand(const std::string &type, return true; } + +int WhisperTab::getType() const +{ + return ChatTab::WHISPER; +} diff --git a/src/gui/widgets/whispertab.h b/src/gui/widgets/whispertab.h index af71025b..750e7f09 100644 --- a/src/gui/widgets/whispertab.h +++ b/src/gui/widgets/whispertab.h @@ -39,6 +39,8 @@ class WhisperTab : public ChatTab bool handleCommand(const std::string &type, const std::string &args); + int getType() const; + protected: friend class ChatWindow; diff --git a/src/net/ea/gui/partytab.cpp b/src/net/ea/gui/partytab.cpp index dab233e1..24bd739b 100644 --- a/src/net/ea/gui/partytab.cpp +++ b/src/net/ea/gui/partytab.cpp @@ -201,3 +201,8 @@ bool PartyTab::handleCommand(const std::string &type, const std::string &args) return true; } + +int PartyTab::getType() const +{ + return ChatTab::PARTY; +} diff --git a/src/net/ea/gui/partytab.h b/src/net/ea/gui/partytab.h index 1e4b6e0c..9ef481e2 100644 --- a/src/net/ea/gui/partytab.h +++ b/src/net/ea/gui/partytab.h @@ -37,6 +37,8 @@ class PartyTab : public ChatTab bool handleCommand(const std::string &type, const std::string &args); + int getType() const; + protected: void handleInput(const std::string &msg); }; diff --git a/src/utils/stringutils.cpp b/src/utils/stringutils.cpp index 67a0d831..6727dcdf 100644 --- a/src/utils/stringutils.cpp +++ b/src/utils/stringutils.cpp @@ -140,3 +140,21 @@ int compareStrI(const std::string &a, const std::string &b) return 0; } + +bool isWordSeparator(char chr) +{ + return (chr == ' ' || chr == ',' || chr == '.'); +} + +const std::string findSameSubstring(std::string &str1, std::string &str2) +{ + int minLength = str1.length() > str2.length() ? str2.length() : str1.length(); + for (int f = 0; f < minLength; f ++) + { + if (str1.at(f) != str2.at(f)) + { + return str1.substr(0, f); + } + } + return str1.substr(0, minLength); +} diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h index 3624268f..4f0138de 100644 --- a/src/utils/stringutils.h +++ b/src/utils/stringutils.h @@ -119,4 +119,8 @@ std::string removeColors(std::string msg); */ int compareStrI(const std::string &a, const std::string &b); +bool isWordSeparator(char chr); + +const std::string findSameSubstring(std::string &str1, std::string &str2); + #endif // UTILS_STRINGUTILS_H -- cgit v1.2.3-70-g09d2