summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/beingmanager.cpp61
-rw-r--r--src/beingmanager.h12
-rw-r--r--src/gui/chat.cpp178
-rw-r--r--src/gui/chat.h25
-rw-r--r--src/gui/textdialog.cpp4
-rw-r--r--src/gui/widgets/chattab.cpp6
-rw-r--r--src/gui/widgets/chattab.h7
-rw-r--r--src/gui/widgets/textfield.cpp137
-rw-r--r--src/gui/widgets/textfield.h68
-rw-r--r--src/utils/stringutils.cpp37
-rw-r--r--src/utils/stringutils.h4
11 files changed, 318 insertions, 221 deletions
diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp
index 931e4579..d7045684 100644
--- a/src/beingmanager.cpp
+++ b/src/beingmanager.cpp
@@ -53,8 +53,48 @@ class FindBeingFunctor
Being::Type type;
} beingFinder;
+class PlayerNamesLister : public AutoCompleteLister
+{
+ void getAutoCompleteList(std::vector<std::string>& names) const
+ {
+ Beings::iterator i = beingManager->mBeings.begin();
+ names.clear();
+
+ while (i != beingManager->mBeings.end())
+ {
+ Being *being = (*i);
+ if (being->getType() == Being::PLAYER && being->getName() != "")
+ names.push_back(being->getName());
+
+ ++i;
+ }
+ }
+};
+
+class PlayerNPCNamesLister : public AutoCompleteLister
+{
+ void getAutoCompleteList(std::vector<std::string>& names) const
+ {
+ Beings::iterator i = beingManager->mBeings.begin();
+ names.clear();
+
+ while (i != beingManager->mBeings.end())
+ {
+ Being *being = (*i);
+ if ((being->getType() == Being::PLAYER
+ || being->getType() == Being::NPC)
+ && being->getName() != "")
+ names.push_back(being->getName());
+
+ ++i;
+ }
+ }
+};
+
BeingManager::BeingManager()
{
+ mPlayerNames = new PlayerNamesLister;
+ mPlayerNPCNames = new PlayerNPCNamesLister;
}
BeingManager::~BeingManager()
@@ -263,23 +303,14 @@ bool BeingManager::hasBeing(Being *being) const
return false;
}
-void BeingManager::getPlayerNames(std::vector<std::string> &names,
- bool npcNames)
+AutoCompleteLister *BeingManager::getPlayerNameLister()
{
- Beings::iterator i = mBeings.begin();
- names.clear();
+ return mPlayerNames;
+}
- while (i != mBeings.end())
- {
- Being *being = (*i);
- if ((being->getType() == Being::PLAYER
- || (being->getType() == Being::NPC && npcNames))
- && being->getName() != "")
- {
- names.push_back(being->getName());
- }
- ++i;
- }
+AutoCompleteLister *BeingManager::getPlayerNPCNameLister()
+{
+ return mPlayerNPCNames;
}
void BeingManager::updatePlayerNames()
diff --git a/src/beingmanager.h b/src/beingmanager.h
index 7fd63afe..f2f8eb6d 100644
--- a/src/beingmanager.h
+++ b/src/beingmanager.h
@@ -24,6 +24,8 @@
#include "being.h"
+#include "gui/widgets/textfield.h"
+
class LocalPlayer;
class Map;
@@ -122,12 +124,18 @@ class BeingManager
*/
void clear();
- void getPlayerNames(std::vector<std::string> &names,
- bool npcNames);
+ AutoCompleteLister *getPlayerNameLister();
+
+ AutoCompleteLister *getPlayerNPCNameLister();
void updatePlayerNames();
protected:
+ friend class PlayerNamesLister;
+ friend class PlayerNPCNamesLister;
+
+ AutoCompleteLister *mPlayerNames;
+ AutoCompleteLister *mPlayerNPCNames;
Beings mBeings;
Map *mMap;
};
diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp
index f87a8a3d..6d900e98 100644
--- a/src/gui/chat.cpp
+++ b/src/gui/chat.cpp
@@ -72,9 +72,21 @@ class ChatInput : public TextField, public gcn::FocusListener
}
};
+class ChatAutoComplete : public AutoCompleteLister
+{
+ void getAutoCompleteList(std::vector<std::string> &list) const
+ {
+ ChatTab *tab = static_cast<ChatTab*>(chatWindow->mChatTabs
+ ->getSelectedTab());
+
+ return tab->getAutoCompleteList(list);
+ }
+};
ChatWindow::ChatWindow():
Window(_("Chat")),
+ mHistory(new TextHistory()),
+ mAutoComplete(new ChatAutoComplete),
mTmpVisible(false)
{
setWindowName("Chat");
@@ -104,9 +116,8 @@ ChatWindow::ChatWindow():
loadWindowState();
- // Add key listener to chat input to be able to respond to up/down
- mChatInput->addKeyListener(this);
- mCurHist = mHistory.end();
+ mChatInput->setHistory(mHistory);
+ mChatInput->setAutoComplete(mAutoComplete);
mReturnToggles = config.getValue("ReturnToggles", "0") == "1";
@@ -119,6 +130,8 @@ ChatWindow::~ChatWindow()
delete mRecorder;
removeAllWhispers();
delete mItemLinkHandler;
+ delete mHistory;
+ delete mAutoComplete;
}
void ChatWindow::resetToDefaultSize()
@@ -173,14 +186,6 @@ void ChatWindow::action(const gcn::ActionEvent &event)
if (!message.empty())
{
- // If message different from previous, put it in the history
- if (mHistory.empty() || message != mHistory.back())
- {
- mHistory.push_back(message);
- }
- // Reset history iterator
- mCurHist = mHistory.end();
-
// Send the message to the server
chatInput(message);
@@ -366,48 +371,6 @@ void ChatWindow::mouseDragged(gcn::MouseEvent &event)
}
}
-
-void ChatWindow::keyPressed(gcn::KeyEvent &event)
-{
- if (event.getKey().getValue() == Key::DOWN)
- {
- if (mCurHist != mHistory.end())
- {
- // Move forward through the history
- HistoryIterator prevHist = mCurHist++;
-
- if (mCurHist != mHistory.end())
- {
- mChatInput->setText(*mCurHist);
- mChatInput->setCaretPosition(mChatInput->getText().length());
- }
- else
- {
- mChatInput->setText("");
- mCurHist = prevHist;
- }
- }
- else if (mChatInput->getText() != "")
- {
- mChatInput->setText("");
- }
- }
- else if (event.getKey().getValue() == Key::UP &&
- mCurHist != mHistory.begin() && mHistory.size() > 0)
- {
- // Move backward through the history
- mCurHist--;
- 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)
{
const int caretPos = mChatInput->getCaretPosition();
@@ -516,112 +479,3 @@ 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());
- std::vector<std::string> nameList;
- cTab->getAutoCompleteList(nameList);
- newName = autoComplete(nameList, name);
-
- if (newName == "")
- {
- beingManager->getPlayerNames(nameList, true);
- newName = autoComplete(nameList, name);
- }
- if (newName == "")
- {
- newName = autoCompleteHistory(name);
- }
-
- if (newName != "")
- {
- if(inputText[0] == '@' || inputText[0] == '/')
- newName = "\"" + 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::autoComplete(std::vector<std::string> &names,
- std::string partName) const
-{
- std::vector<std::string>::iterator i = names.begin();
- toLower(partName);
- std::string newName("");
-
- while (i != names.end())
- {
- if (!i->empty())
- {
- std::string name = *i;
- toLower(name);
-
- std::string::size_type pos = name.find(partName, 0);
- if (pos == 0)
- {
- if (newName != "")
- {
- toLower(newName);
- newName = findSameSubstring(name, newName);
- }
- else
- {
- newName = *i;
- }
- }
- }
- ++i;
- }
-
- return newName;
-}
-
-std::string ChatWindow::autoCompleteHistory(std::string partName)
-{
- History::iterator i = mHistory.begin();
- std::vector<std::string> nameList;
-
- while (i != mHistory.end())
- {
- std::string line = *i;
- unsigned int f = 0;
- while (f < line.length() && !isWordSeparator(line.at(f)))
- {
- f++;
- }
- line = line.substr(0, f);
- if (line != "")
- {
- nameList.push_back(line);
- }
- ++i;
- }
- return autoComplete(nameList, partName);
-}
diff --git a/src/gui/chat.h b/src/gui/chat.h
index b0d91556..1c673556 100644
--- a/src/gui/chat.h
+++ b/src/gui/chat.h
@@ -23,6 +23,7 @@
#define CHAT_H
#include "gui/widgets/window.h"
+#include "gui/widgets/textfield.h"
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
@@ -61,8 +62,7 @@ struct CHATLOG
* \ingroup Interface
*/
class ChatWindow : public Window,
- public gcn::ActionListener,
- public gcn::KeyListener
+ public gcn::ActionListener
{
public:
/**
@@ -131,9 +131,6 @@ class ChatWindow : public Window,
*/
void chatInput(const std::string &msg);
- /** Called when key is pressed */
- void keyPressed(gcn::KeyEvent &event);
-
/** Add the given text to the chat input. */
void addInputText(const std::string &text);
@@ -143,11 +140,9 @@ class ChatWindow : public Window,
/** Override to reset mTmpVisible */
void setVisible(bool visible);
-
void mousePressed(gcn::MouseEvent &event);
void mouseDragged(gcn::MouseEvent &event);
-
/**
* Scrolls the chat window
*
@@ -177,7 +172,7 @@ class ChatWindow : public Window,
protected:
friend class ChatTab;
friend class WhisperTab;
- friend class TextField;
+ friend class ChatAutoComplete;
/** Remove the given tab from the window */
void removeTab(ChatTab *tab);
@@ -189,13 +184,6 @@ class ChatWindow : public Window,
void removeAllWhispers();
- void autoComplete();
-
- std::string autoCompleteHistory(std::string partName);
-
- std::string autoComplete(std::vector<std::string> &names,
- std::string partName) const;
-
/** Used for showing item popup on clicking links **/
ItemLinkHandler *mItemLinkHandler;
Recorder *mRecorder;
@@ -203,6 +191,9 @@ class ChatWindow : public Window,
/** Input box for typing chat messages. */
ChatInput *mChatInput;
+ TextHistory *mHistory;
+ AutoCompleteLister *mAutoComplete;
+
private:
bool mTmpVisible;
@@ -213,10 +204,6 @@ class ChatWindow : public Window,
/** Manage whisper tabs */
TabMap mWhispers;
- typedef std::list<std::string> History;
- typedef History::iterator HistoryIterator;
- History mHistory; /**< Command history. */
- HistoryIterator mCurHist; /**< History iterator. */
bool mReturnToggles; /**< Marks whether <Return> toggles the chat log
or not */
};
diff --git a/src/gui/textdialog.cpp b/src/gui/textdialog.cpp
index 28792a0b..d9728357 100644
--- a/src/gui/textdialog.cpp
+++ b/src/gui/textdialog.cpp
@@ -21,6 +21,8 @@
#include "gui/textdialog.h"
+#include "beingmanager.h"
+
#include "gui/widgets/button.h"
#include "gui/widgets/label.h"
#include "gui/widgets/textfield.h"
@@ -40,7 +42,7 @@ TextDialog::TextDialog(const std::string &title, const std::string &msg,
// In TextField the escape key will either cause autoComplete or lose focus
mTextField = new TextField("", ! autoCompleteEnabled);
if (autoCompleteEnabled)
- mTextField->setAutoComplete(true);
+ mTextField->setAutoComplete(beingManager->getPlayerNameLister());
mTextField->addActionListener(this);
diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp
index 39ea6887..8bf57508 100644
--- a/src/gui/widgets/chattab.cpp
+++ b/src/gui/widgets/chattab.cpp
@@ -21,6 +21,7 @@
#include "gui/widgets/chattab.h"
+#include "beingmanager.h"
#include "commandhandler.h"
#include "configuration.h"
#include "localplayer.h"
@@ -275,6 +276,11 @@ void ChatTab::handleCommand(const std::string &msg)
commandHandler->handleCommand(msg, this);
}
+void ChatTab::getAutoCompleteList(std::vector<std::string> &names) const
+{
+ beingManager->getPlayerNPCNameLister()->getAutoCompleteList(names);
+}
+
void ChatTab::addRow(std::string &line)
{
std::string::size_type idx = 0;
diff --git a/src/gui/widgets/chattab.h b/src/gui/widgets/chattab.h
index 7fd3931e..c2dfa1c1 100644
--- a/src/gui/widgets/chattab.h
+++ b/src/gui/widgets/chattab.h
@@ -25,6 +25,7 @@
#include "gui/chat.h"
#include "gui/widgets/tab.h"
+#include "gui/widgets/textfield.h"
class BrowserBox;
class Recorder;
@@ -45,7 +46,7 @@ enum
/**
* A tab for the chat window. This is special to ease chat handling.
*/
-class ChatTab : public Tab
+class ChatTab : public Tab, public AutoCompleteLister
{
public:
/**
@@ -111,6 +112,8 @@ class ChatTab : public Tab
const std::string &args)
{ return false; }
+ void getAutoCompleteList(std::vector<std::string> &names) const;
+
protected:
friend class ChatWindow;
friend class WhisperWindow;
@@ -121,8 +124,6 @@ class ChatTab : public Tab
virtual void handleCommand(const std::string &msg);
- virtual void getAutoCompleteList(std::vector<std::string>&) const {}
-
void addRow(std::string &line);
ScrollArea *mScrollArea;
diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp
index 60a1f57f..3e02be98 100644
--- a/src/gui/widgets/textfield.cpp
+++ b/src/gui/widgets/textfield.cpp
@@ -25,7 +25,6 @@
#include "configuration.h"
#include "graphics.h"
-#include "gui/chat.h"
#include "gui/palette.h"
#include "gui/sdlinput.h"
#include "gui/theme.h"
@@ -34,6 +33,7 @@
#include "utils/copynpaste.h"
#include "utils/dtor.h"
+#include "utils/stringutils.h"
#include <guichan/font.hpp>
@@ -46,7 +46,8 @@ ImageRect TextField::skin;
TextField::TextField(const std::string &text, bool loseFocusOnTab):
gcn::TextField(text),
mNumeric(false),
- mAutoComplete(false)
+ mAutoComplete(NULL),
+ mHistory(NULL)
{
setFrameSize(2);
@@ -212,6 +213,42 @@ void TextField::keyPressed(gcn::KeyEvent &keyEvent)
}
} break;
+ case Key::UP:
+ {
+ if (mHistory && !mHistory->atBegining() && !mHistory->empty())
+ {
+ // Move backward through the history
+ mHistory->current--;
+ setText(*mHistory->current);
+ setCaretPosition(getText().length());
+ }
+ } break;
+
+ case Key::DOWN:
+ {
+ if (mHistory && !mHistory->atEnd())
+ {
+ // Move forward through the history
+ TextHistoryIterator prevHist = mHistory->current++;
+
+ if (!mHistory->atEnd())
+ {
+ setText(*mHistory->current);
+ setCaretPosition(getText().length());
+ }
+ else
+ {
+ setText("");
+ mHistory->current = prevHist;
+ }
+ }
+ else if (getText() != "")
+ {
+ // Always clear (easy access to useful function)
+ setText("");
+ }
+ } break;
+
case Key::DELETE:
{
unsigned sz = mText.size();
@@ -237,6 +274,19 @@ void TextField::keyPressed(gcn::KeyEvent &keyEvent)
} break;
case Key::ENTER:
+ if (mHistory)
+ {
+ mHistory->toEnd();
+
+ // If the input is different from previous, put it in the history
+ if (mHistory->empty() || !mHistory->matchesEntry(getText()))
+ {
+ mHistory->addEntry(getText());
+ }
+
+ mHistory->toEnd();
+ }
+
distributeActionEvent();
break;
@@ -249,17 +299,7 @@ void TextField::keyPressed(gcn::KeyEvent &keyEvent)
break;
case Key::TAB:
- if (mAutoComplete && mText.size() > 0)
- {
- std::vector<std::string> names;
- beingManager->getPlayerNames(names, false);
- std::string newName = chatWindow->autoComplete(names, mText);
- if (newName != "")
- {
- setText(newName);
- setCaretPosition(mText.size());
- }
- }
+ autoComplete();
if (mLoseFocusOnTab)
return;
break;
@@ -273,6 +313,77 @@ void TextField::keyPressed(gcn::KeyEvent &keyEvent)
fixScroll();
}
+void TextField::autoComplete()
+{
+ if (mAutoComplete && mText.size() > 0)
+ {
+ int caretPos = getCaretPosition();
+ int startName = 0;
+ const std::string inputText = 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;
+
+
+ std::vector<std::string> nameList;
+ mAutoComplete->getAutoCompleteList(nameList);
+ newName = autocomplete(nameList, name);
+
+ if (newName == "" && mHistory)
+ {
+
+ TextHistoryIterator i = mHistory->history.begin();
+ std::vector<std::string> nameList;
+
+ while (i != mHistory->history.end())
+ {
+ std::string line = *i;
+ unsigned int f = 0;
+ while (f < line.length() && !isWordSeparator(line.at(f)))
+ {
+ f++;
+ }
+ line = line.substr(0, f);
+ if (line != "")
+ {
+ nameList.push_back(line);
+ }
+ ++i;
+ }
+
+ newName = autocomplete(nameList, name);
+ }
+
+ if (newName != "")
+ {
+ if(inputText[0] == '@' || inputText[0] == '/')
+ newName = "\"" + newName + "\"";
+
+ setText(inputText.substr(0, startName) + newName
+ + inputText.substr(caretPos, inputText.length()
+ - caretPos));
+
+ if (startName > 0)
+ setCaretPosition(caretPos - name.length() + newName.length()
+ + 1);
+ else
+ setCaretPosition(caretPos - name.length() + newName.length());
+ }
+ }
+}
+
void TextField::handlePaste()
{
std::string text = getText();
diff --git a/src/gui/widgets/textfield.h b/src/gui/widgets/textfield.h
index 1e6df9d6..6e50f1e9 100644
--- a/src/gui/widgets/textfield.h
+++ b/src/gui/widgets/textfield.h
@@ -24,9 +24,48 @@
#include <guichan/widgets/textfield.hpp>
+#include <vector>
+
class ImageRect;
class TextField;
+typedef std::list<std::string> TextHistoryList;
+typedef TextHistoryList::iterator TextHistoryIterator;
+
+struct TextHistory {
+ TextHistoryList history; /**< Command history. */
+ TextHistoryIterator current; /**< History iterator. */
+
+ TextHistory()
+ { current = history.end(); }
+
+ bool empty() const
+ { return history.empty(); }
+
+ bool atBegining() const
+ { return current == history.begin(); }
+
+ bool atEnd() const
+ { return current == history.end(); }
+
+ void toBegining()
+ { current = history.begin(); }
+
+ void toEnd()
+ { current = history.end(); }
+
+ void addEntry(const std::string &text)
+ { history.push_back(text); }
+
+ bool matchesEntry(const std::string &text)
+ { return (*current) == text; }
+};
+
+class AutoCompleteLister {
+public:
+ virtual void getAutoCompleteList(std::vector<std::string>&) const {}
+};
+
/**
* A text field.
*
@@ -91,16 +130,32 @@ class TextField : public gcn::TextField
int getValue() const;
/**
- * Set if the tabulator key causes auto complete
+ * Sets the TextField's source of autocomplete. Passing null will
+ * disable autocomplete.
+ */
+ void setAutoComplete(AutoCompleteLister *lister)
+ { mAutoComplete = lister; }
+
+ /**
+ * Returns the TextField's source of autocomplete.
*/
- void setAutoComplete(bool b ) {mAutoComplete = b;}
+ AutoCompleteLister *getAutoComplete() const
+ { return mAutoComplete; }
/**
- * Returns if the tabulator key causes auto complete
+ * Sets the TextField's source of input history.
*/
- bool getAutoComplete() {return mAutoComplete;}
+ void setHistory(TextHistory *history)
+ { mHistory = history; }
+
+ /**
+ * Returns the TextField's source of input history.
+ */
+ TextHistory *getHistory() const
+ { return mHistory; }
private:
+ void autoComplete();
void handlePaste();
static int instances;
@@ -110,7 +165,10 @@ class TextField : public gcn::TextField
int mMinimum;
int mMaximum;
bool mLoseFocusOnTab;
- bool mAutoComplete;
+
+ AutoCompleteLister *mAutoComplete;
+
+ TextHistory *mHistory; /**< Text history. */
};
#endif
diff --git a/src/utils/stringutils.cpp b/src/utils/stringutils.cpp
index 9fe3de14..445427fe 100644
--- a/src/utils/stringutils.cpp
+++ b/src/utils/stringutils.cpp
@@ -174,4 +174,39 @@ const char* getSafeUtf8String(std::string text)
memcpy(buf, text.c_str(), text.size());
memset(buf + text.size(), 0, UTF8_MAX_SIZE);
return buf;
-} \ No newline at end of file
+}
+
+std::string autocomplete(std::vector<std::string> &candidates,
+ std::string base)
+{
+ std::vector<std::string>::iterator i = candidates.begin();
+ toLower(base);
+ std::string newName("");
+
+ while (i != candidates.end())
+ {
+ if (!i->empty())
+ {
+ std::string name = *i;
+ toLower(name);
+
+ std::string::size_type pos = name.find(base, 0);
+ if (pos == 0)
+ {
+ if (newName != "")
+ {
+ toLower(newName);
+ newName = findSameSubstring(name, newName);
+ }
+ else
+ {
+ newName = *i;
+ }
+ }
+ }
+
+ ++i;
+ }
+
+ return newName;
+}
diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h
index ec82e240..5f1f05f0 100644
--- a/src/utils/stringutils.h
+++ b/src/utils/stringutils.h
@@ -24,6 +24,7 @@
#include <string>
#include <sstream>
+#include <vector>
/**
* Trims spaces off the end and the beginning of the given string.
@@ -125,4 +126,7 @@ const std::string findSameSubstring(const std::string &str1, const std::string &
const char* getSafeUtf8String(std::string text);
+std::string autocomplete(std::vector<std::string> &candidates,
+ std::string base);
+
#endif // UTILS_STRINGUTILS_H