Patch from AC to enable completion over chat lobby participants

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@6193 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2013-03-06 19:41:08 +00:00
parent 7f06b1e9b8
commit 17f2d2e8a5
2 changed files with 147 additions and 14 deletions

View File

@ -233,7 +233,17 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event)
updateStatusTyping(); updateStatusTyping();
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent && (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)) { if (keyEvent) {
if (isChatLobby) {
if (keyEvent->key() == Qt::Key_Tab) {
completeNickname((bool)(keyEvent->modifiers() & Qt::ShiftModifier));
return true; // eat event
}
else {
completionWord.clear();
}
}
if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) {
// Enter pressed // Enter pressed
if (Settings->getChatSendMessageWithCtrlReturn()) { if (Settings->getChatSendMessageWithCtrlReturn()) {
if (keyEvent->modifiers() & Qt::ControlModifier) { if (keyEvent->modifiers() & Qt::ControlModifier) {
@ -253,6 +263,7 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event)
} }
} }
} }
}
} else { } else {
if (event->type() == QEvent::WindowActivate) { if (event->type() == QEvent::WindowActivate) {
if (isVisible() && (window() == NULL || window()->isActiveWindow())) { if (isVisible() && (window() == NULL || window()->isActiveWindow())) {
@ -266,6 +277,124 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event)
return QWidget::eventFilter(obj, event); return QWidget::eventFilter(obj, event);
} }
/**
* @brief Utility function for completeNickname.
*/
static bool caseInsensitiveCompare(QString a, QString b)
{
return a.toLower() < b.toLower();
}
/**
* @brief Completes nickname based on previous characters.
* @param reverse true to list nicknames in reverse alphabetical order.
*/
void ChatWidget::completeNickname(bool reverse)
{
// Find lobby we belong to
const ChatLobbyInfo *lobby = NULL;
std::list<ChatLobbyInfo> lobbies;
rsMsgs->getChatLobbyList(lobbies);
std::list<ChatLobbyInfo>::const_iterator lobbyIt;
for (lobbyIt = lobbies.begin(); lobbyIt != lobbies.end(); ++lobbyIt) {
std::string vpid;
if (rsMsgs->getVirtualPeerId(lobbyIt->lobby_id, vpid)) {
if (vpid == peerId) {
lobby = &*lobbyIt;
break;
}
}
}
if (!lobby)
return;
QTextCursor cursor = ui->chatTextEdit->textCursor();
// Do nothing if there is a selection
if (cursor.anchor() != cursor.position())
return;
// We want to complete the word typed by the user. This is easy.
// But also, if there are two participants whose name start with the word
// the user typed, the first press on <tab> should show the first
// participants name, and the second press on <tab> should show the
// second participants name.
cursor.beginEditBlock();
if (!completionWord.isEmpty()) {
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, cursor.position() - completionPosition);
}
else {
cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
completionPosition = cursor.position();
}
if (cursor.selectedText() == ": ") {
cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
}
bool firstWord = (cursor.position() == 0);
QString word = cursor.selectedText();
if (word.endsWith(": ")) {
word.chop(2);
}
if (word.length() > 0) {
// Sort participants list
std::list<QString> participants;
for ( std::map<std::string,time_t>::const_iterator it = lobby->nick_names.begin();
it != lobby->nick_names.end();
it++) {
participants.push_front(QString::fromUtf8(it->first.c_str()));
}
participants.sort(caseInsensitiveCompare);
// Search for a participant nickname that starts with the previous word
std::list<QString>::const_iterator it, start, end;
int delta;
bool skippedParticipant = false;
if (reverse) {
// Note: at the moment reverse completion doesnt work because
// shift-tab selects the previous widget
start = participants.end();
--start;
end = participants.begin();
--end;
delta = -1;
}
else {
start = participants.begin();
end = participants.end();
delta = 1;
}
do {
for (it = start; it != end; (delta == 1) ? ++it : --it) {
QString participant = *it;
if (participant.startsWith(word, Qt::CaseInsensitive)) {
if (!completionWord.isEmpty() && !skippedParticipant) {
// This participant nicknaem was completed with <tab>;
// skip it and find the next one that starts with
// completionWord
word = completionWord;
skippedParticipant = true;
continue;
}
skippedParticipant = false;
cursor.insertText(participant);
if (firstWord) {
cursor.insertText(QString(": "));
}
break;
}
}
} while (skippedParticipant);
if (completionWord.isEmpty()) {
completionWord = word;
}
}
cursor.endEditBlock();
}
void ChatWidget::addToolsAction(QAction *action) void ChatWidget::addToolsAction(QAction *action)
{ {
ui->pushtoolsButton->menu()->addAction(action); ui->pushtoolsButton->menu()->addAction(action);

View File

@ -135,9 +135,13 @@ private:
void setColorAndFont(); void setColorAndFont();
void processSettings(bool load); void processSettings(bool load);
void completeNickname(bool reverse);
std::string peerId; std::string peerId;
QString title; QString title;
QString name; QString name;
QString completionWord;
int completionPosition;
QColor currentColor; QColor currentColor;
QFont currentFont; QFont currentFont;