summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrei Karas <akaras@inbox.ru>2009-10-31 15:42:28 +0200
committerBlue <bluesansdouze@gmail.com>2010-01-07 23:12:10 +0100
commitbe5460f2a294bb8e50b40f498f29a556b31bedd7 (patch)
tree5256167e0b8487fdb2c49090986cc883614fb9b1 /src
parent84da747711ed1713984ca514a8bb786219a85d9b (diff)
downloadmana-client-be5460f2a294bb8e50b40f498f29a556b31bedd7.tar.gz
mana-client-be5460f2a294bb8e50b40f498f29a556b31bedd7.tar.bz2
mana-client-be5460f2a294bb8e50b40f498f29a556b31bedd7.tar.xz
mana-client-be5460f2a294bb8e50b40f498f29a556b31bedd7.zip
Chat auto completing
Diffstat (limited to 'src')
-rw-r--r--src/beingmanager.cpp35
-rw-r--r--src/beingmanager.h2
-rw-r--r--src/gui/chat.cpp92
-rw-r--r--src/gui/chat.h4
-rw-r--r--src/gui/partywindow.cpp34
-rw-r--r--src/gui/partywindow.h2
-rw-r--r--src/gui/widgets/chattab.cpp5
-rw-r--r--src/gui/widgets/chattab.h13
-rw-r--r--src/gui/widgets/textfield.cpp8
-rw-r--r--src/gui/widgets/textfield.h4
-rw-r--r--src/gui/widgets/whispertab.cpp5
-rw-r--r--src/gui/widgets/whispertab.h2
-rw-r--r--src/net/ea/gui/partytab.cpp5
-rw-r--r--src/net/ea/gui/partytab.h2
-rw-r--r--src/utils/stringutils.cpp18
-rw-r--r--src/utils/stringutils.h4
16 files changed, 230 insertions, 5 deletions
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 <cassert>
@@ -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<ChatTab*>(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