--- a/QTfrontend/ui/widget/SmartLineEdit.cpp Tue Oct 18 15:34:40 2011 +0200
+++ b/QTfrontend/ui/widget/SmartLineEdit.cpp Wed Oct 19 02:10:27 2011 +0200
@@ -21,14 +21,19 @@
#include "SmartLineEdit.h"
-SmartLineEdit::SmartLineEdit(QWidget * parent)
+SmartLineEdit::SmartLineEdit(QWidget * parent, int maxHistorySize)
: QLineEdit(parent)
{
+ m_curHistEntryIdx = 0;
+ m_maxHistorySize = maxHistorySize;
+
m_whitespace = QRegExp("\\s");
m_cmds = new QStringList();
m_nicks = new QStringList();
+ m_history = new QStringList();
+
resetAutoCompletionStatus();
// reset autocompletion status when cursor is moved or content is changed
@@ -41,58 +46,140 @@
void SmartLineEdit::addCommands(const QStringList & commands)
{
- m_mutex.lock();
+ m_keywordMutex.lock();
m_cmds->append(commands);
- m_mutex.unlock();
+ m_keywordMutex.unlock();
}
void SmartLineEdit::removeCommands(const QStringList & commands)
{
- m_mutex.lock();
+ m_keywordMutex.lock();
foreach (const QString & cmd, commands)
{
m_cmds->removeAll(cmd);
}
- m_mutex.unlock();
+ m_keywordMutex.unlock();
}
void SmartLineEdit::addNickname(const QString & name)
{
- m_mutex.lock();
+ m_keywordMutex.lock();
m_nicks->append(name);
- m_mutex.unlock();
+ m_keywordMutex.unlock();
}
void SmartLineEdit::removeNickname(const QString & name)
{
- m_mutex.lock();
+ m_keywordMutex.lock();
m_nicks->removeAll(name);
- m_mutex.unlock();
+ m_keywordMutex.unlock();
+}
+
+void SmartLineEdit::rememberCurrentText()
+{
+ m_historyMutex.lock();
+
+ rememberCurrentTextUnsynced();
+
+ m_historyMutex.unlock();
+}
+
+void SmartLineEdit::rememberCurrentTextUnsynced()
+{
+ QString newEntry = text();
+
+ // don't store whitespace-only/empty text
+ if (newEntry.trimmed().isEmpty())
+ return;
+
+ m_history->removeOne(newEntry); // no duplicates please
+ m_history->append(newEntry);
+
+ // do not keep more entries than allowed
+ if (m_history->size() > m_maxHistorySize)
+ m_history->removeFirst();
+
+ // we're looking at the latest entry
+ m_curHistEntryIdx = m_history->size() - 1;
+}
+
+void SmartLineEdit::clear()
+{
+ m_historyMutex.lock();
+
+ QLineEdit::clear();
+ m_curHistEntryIdx = m_history->size();
+
+ m_historyMutex.unlock();
}
void SmartLineEdit::forgetEverything()
{
- m_mutex.lock();
+ // forget keywords
+ m_keywordMutex.lock();
m_cmds->clear();
m_nicks->clear();
- m_mutex.unlock();
+ m_keywordMutex.unlock();
+
+ // forget history
+ m_historyMutex.lock();
+
+ m_history->clear();
+ m_curHistEntryIdx = 0;
+
+ m_historyMutex.unlock();
resetAutoCompletionStatus();
}
+void SmartLineEdit::navigateHistory(bool isGoingUp)
+{
+ m_historyMutex.lock();
+
+ // save possible changes to new entry
+ if ((m_curHistEntryIdx >= m_history->size() ||
+ (text() != m_history->at(m_curHistEntryIdx))))
+ {
+ rememberCurrentTextUnsynced();
+ }
+
+ if (isGoingUp)
+ m_curHistEntryIdx--;
+ else
+ m_curHistEntryIdx++;
+
+ // if Idx higher than valid range
+ if (m_curHistEntryIdx >= m_history->size())
+ {
+ QLineEdit::clear();
+ m_curHistEntryIdx = m_history->size();
+ }
+ // if Idx in valid range
+ else if (m_curHistEntryIdx >= 0)
+ {
+ setText(m_history->at(m_curHistEntryIdx));
+ }
+ // if Idx below 0
+ else
+ m_curHistEntryIdx = 0;
+
+
+ m_historyMutex.unlock();
+}
+
bool SmartLineEdit::event(QEvent * event)
{
// we only want special treatment for key press events
@@ -121,11 +208,29 @@
autoComplete();
event->accept();
}
- // clear contents on pressed ESC
- else if ((event->key() == Qt::Key_Escape) &&
- (event->modifiers() == Qt::NoModifier)
- )
- clear();
+ // clear contents on pressed ESC, navigate history with arrow keys
+ else if (event->modifiers() == Qt::NoModifier)
+ switch (key)
+ {
+ case Qt::Key_Escape:
+ clear();
+ event->accept();
+ break;
+
+ case Qt::Key_Up:
+ navigateHistory(true);
+ event->accept();
+ break;
+
+ case Qt::Key_Down:
+ navigateHistory(false);
+ event->accept();
+ break;
+
+ default:
+ QLineEdit::keyPressEvent(event);
+ break;
+ }
// otherwise forward keys to parent
else
QLineEdit::keyPressEvent(event);
@@ -152,10 +257,10 @@
}
else
{
- m_mutex.lock();
+ m_keywordMutex.lock();
m_cmds->sort();
m_nicks->sort();
- m_mutex.unlock();
+ m_keywordMutex.unlock();
int cp = cursorPosition();
@@ -190,7 +295,7 @@
}
- m_mutex.lock();
+ m_keywordMutex.lock();
if (isFirstWord)
{
@@ -229,7 +334,7 @@
}
}
- m_mutex.unlock();
+ m_keywordMutex.unlock();
// we found a single match?
if (!match.isEmpty())
--- a/QTfrontend/ui/widget/SmartLineEdit.h Tue Oct 18 15:34:40 2011 +0200
+++ b/QTfrontend/ui/widget/SmartLineEdit.h Wed Oct 19 02:10:27 2011 +0200
@@ -33,11 +33,15 @@
class QLineEdit;
/**
- * A modification of QLineEdit that will attempt to auto-complete the current
- * word with cursor when the TAB key is pressed.
- * Additionally it will delete its contents when ESC is pressed.
- * A Keyword can either be a command (if first word) or
- * a nickname (completed if any word)
+ * A modification of QLineEdit that features:
+ * + Auto-completion for word under cursor when the TAB key is pressed.
+ * + ESC key clears text.
+ * + History of previous contents, re-selectable using the arrow keys.
+ *
+ * Note:
+ * * A Keyword can either be a command (if first word) or
+ * a nickname (completed regardless of position in text).
+ * * Public methods for accessing keywords and history are thread-safe.
* @author sheepluva
* @since 0.9.17
*/
@@ -48,8 +52,10 @@
public:
/**
* Class constructor.
+ * @param parent parent QWidget.
+ * @param maxHistorySize maximum amount of history entries kept.
*/
- SmartLineEdit(QWidget * parent = 0);
+ SmartLineEdit(QWidget * parent = 0, int maxHistorySize = 64);
/**
* Adds commands to the auto-completion feature.
@@ -64,6 +70,11 @@
void addNickname(const QString & nickname);
/**
+ * Appends current text to history.
+ */
+ void rememberCurrentText();
+
+ /**
* Removes commands from the auto-completion feature.
* @param commands list of commands to be removed.
*/
@@ -81,6 +92,13 @@
void forgetEverything();
+public slots:
+ /**
+ * Clears the contents.
+ */
+ void clear();
+
+
protected:
/**
* Overrides method of parent class.
@@ -94,9 +112,10 @@
/**
* Overrides method of parent class.
* Autocompletes if TAB is reported as pressed key in the key event,
- * otherwise keys except for ESC (with no modifiers)
+ * otherwise keys except for ESC and Up/Down (with no modifiers)
* are forwarded to parent method.
* ESC leads to the contents being cleared.
+ * Arrow keys are used for navigating the history.
* @param event the key event.
*/
virtual void keyPressEvent(QKeyEvent * event);
@@ -105,9 +124,14 @@
private:
QRegExp m_whitespace; // regexp that matches a whitespace
+ int m_maxHistorySize; // the maximum allowed size for the history
+ int m_curHistEntryIdx; // the index of the currently used entry or -1
+
QStringList * m_cmds; // list of recognized commands
QStringList * m_nicks; // list of recognized nicknames
+ QStringList * m_history; // history of previous inputs
+
// these variables contain information about the last replacement
// they get reset whenever cursor is moved or text is changed
@@ -116,13 +140,27 @@
QString m_prefix; // prefix of the text replacement this widget just did
QString m_postfix; // postfix of the text replacement this widget just did
- QMutex m_mutex; // make all the QStringList action thread-safe
+ QMutex m_keywordMutex; // make keyword QStringList action thread-safe
+ QMutex m_historyMutex; // make history QStringList action thread-safe
/**
* Autocompletes the contents based on the known commands and/or names.
*/
void autoComplete();
+ /**
+ * Navigates content history in the desired direction.
+ * Note: no wrap-around on purpose (so that holding down/up will get the
+ * the user to the respective end rather than into an endless cycle :P)
+ * @param isGoingUp true: next older entry, false: next more recent entry.
+ */
+ void navigateHistory(bool isGoingUp);
+
+ /**
+ * Appends current text to history, without Mutex.
+ */
+ void rememberCurrentTextUnsynced();
+
private slots:
/**
--- a/QTfrontend/ui/widget/chatwidget.cpp Tue Oct 18 15:34:40 2011 +0200
+++ b/QTfrontend/ui/widget/chatwidget.cpp Wed Oct 19 02:10:27 2011 +0200
@@ -334,6 +334,7 @@
void HWChatWidget::returnPressed()
{
QStringList lines = chatEditLine->text().split('\n');
+ chatEditLine->rememberCurrentText();
chatEditLine->clear();
foreach (const QString &line, lines)
emit chatLine(line);