summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/QtUI/QtChatWindow.cpp')
-rw-r--r--Swift/QtUI/QtChatWindow.cpp165
1 files changed, 145 insertions, 20 deletions
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 1a909fd..d7ffc65 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -13,10 +13,12 @@
#include "MessageSnippet.h"
#include "SystemMessageSnippet.h"
#include "QtTextEdit.h"
+#include "QtSettingsProvider.h"
#include "QtScaledAvatarCache.h"
#include "SwifTools/TabComplete.h"
+#include <QLabel>
#include <QApplication>
#include <QBoxLayout>
#include <QCloseEvent>
@@ -28,6 +30,7 @@
#include <QTextEdit>
#include <QTime>
#include <QUrl>
+#include <QPushButton>
namespace Swift {
QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream) : QtTabbable(), contact_(contact), previousMessageWasSelf_(false), previousMessageWasSystem_(false), previousMessageWasPresence_(false), eventStream_(eventStream) {
@@ -35,25 +38,44 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
inputEnabled_ = true;
completer_ = NULL;
theme_ = theme;
+ isCorrection_ = false;
+ correctionEnabled_ = Maybe;
updateTitleWithUnreadCount();
+ QtSettingsProvider settings;
+
+ alertStyleSheet_ = "background: rgb(255, 255, 153); color: black";
QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
layout->setContentsMargins(0,0,0,0);
layout->setSpacing(2);
-
-
- QSplitter *logRosterSplitter = new QSplitter(this);
- logRosterSplitter->setAutoFillBackground(true);
- layout->addWidget(logRosterSplitter);
+ alertWidget_ = new QWidget(this);
+ QHBoxLayout* alertLayout = new QHBoxLayout(alertWidget_);
+ layout->addWidget(alertWidget_);
+ alertLabel_ = new QLabel(this);
+ alertLayout->addWidget(alertLabel_);
+ alertButton_ = new QPushButton(this);
+ connect (alertButton_, SIGNAL(clicked()), this, SLOT(handleAlertButtonClicked()));
+ alertLayout->addWidget(alertButton_);
+ QPalette palette = alertWidget_->palette();
+ palette.setColor(QPalette::Window, QColor(Qt::yellow));
+ palette.setColor(QPalette::WindowText, QColor(Qt::black));
+ alertWidget_->setStyleSheet(alertStyleSheet_);
+ alertLabel_->setStyleSheet(alertStyleSheet_);
+ alertWidget_->hide();
+
+ logRosterSplitter_ = new QSplitter(this);
+ logRosterSplitter_->setAutoFillBackground(true);
+ layout->addWidget(logRosterSplitter_);
messageLog_ = new QtChatView(theme, this);
- logRosterSplitter->addWidget(messageLog_);
+ logRosterSplitter_->addWidget(messageLog_);
treeWidget_ = new QtTreeWidget(eventStream_);
treeWidget_->setEditable(false);
treeWidget_->hide();
- logRosterSplitter->addWidget(treeWidget_);
- logRosterSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ logRosterSplitter_->addWidget(treeWidget_);
+ logRosterSplitter_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ connect(logRosterSplitter_, SIGNAL(splitterMoved(int, int)), this, SLOT(handleSplitterMoved(int, int)));
QWidget* midBar = new QWidget(this);
layout->addWidget(midBar);
@@ -69,10 +91,17 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
labelsWidget_->setSizeAdjustPolicy(QComboBox::AdjustToContents);
midBarLayout->addWidget(labelsWidget_,0);
+ QHBoxLayout* inputBarLayout = new QHBoxLayout();
+ inputBarLayout->setContentsMargins(0,0,0,0);
+ inputBarLayout->setSpacing(2);
input_ = new QtTextEdit(this);
input_->setAcceptRichText(false);
- layout->addWidget(input_);
-
+ inputBarLayout->addWidget(input_);
+ correctingLabel_ = new QLabel(tr("Correcting"), this);
+ inputBarLayout->addWidget(correctingLabel_);
+ correctingLabel_->hide();
+ layout->addLayout(inputBarLayout);
+
inputClearing_ = false;
contactIsTyping_ = false;
@@ -80,18 +109,45 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
connect(input_, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
connect(input_, SIGNAL(textChanged()), this, SLOT(handleInputChanged()));
setFocusProxy(input_);
- logRosterSplitter->setFocusProxy(input_);
+ logRosterSplitter_->setFocusProxy(input_);
midBar->setFocusProxy(input_);
messageLog_->setFocusProxy(input_);
connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(qAppFocusChanged(QWidget*, QWidget*)));
connect(messageLog_, SIGNAL(gotFocus()), input_, SLOT(setFocus()));
resize(400,300);
+ connect(messageLog_, SIGNAL(fontResized(int)), this, SIGNAL(fontResized(int)));
+
+
}
QtChatWindow::~QtChatWindow() {
}
+
+void QtChatWindow::handleFontResized(int fontSizeSteps) {
+ messageLog_->resizeFont(fontSizeSteps);
+}
+
+void QtChatWindow::handleAlertButtonClicked() {
+ onAlertButtonClicked();
+}
+
+void QtChatWindow::setAlert(const std::string& alertText, const std::string& buttonText) {
+ alertLabel_->setText(alertText.c_str());
+ if (buttonText.empty()) {
+ alertButton_->hide();
+ } else {
+ alertButton_->setText(buttonText.c_str());
+ alertButton_->show();
+ }
+ alertWidget_->show();
+}
+
+void QtChatWindow::cancelAlert() {
+ alertWidget_->hide();
+}
+
void QtChatWindow::setTabComplete(TabComplete* completer) {
completer_ = completer;
}
@@ -118,11 +174,55 @@ void QtChatWindow::handleKeyPressEvent(QKeyEvent* event) {
emit requestActiveTab();
} else if (key == Qt::Key_Tab) {
tabComplete();
+ } else if ((key == Qt::Key_Up) && input_->toPlainText().isEmpty() && !(lastSentMessage_.isEmpty())) {
+ beginCorrection();
+ } else if (key == Qt::Key_Down && isCorrection_ && input_->textCursor().atBlockEnd()) {
+ cancelCorrection();
+ } else if (key == Qt::Key_Down || key == Qt::Key_Up) {
+ /* Drop */
} else {
messageLog_->handleKeyPressEvent(event);
}
}
+void QtChatWindow::beginCorrection() {
+ if (correctionEnabled_ == ChatWindow::Maybe) {
+ setAlert(Q2PSTRING(tr("This chat may not support message correction. If you send a correction anyway, it may appear as a duplicate message")));
+ } else if (correctionEnabled_ == ChatWindow::No) {
+ setAlert(Q2PSTRING(tr("This chat does not support message correction. If you send a correction anyway, it will appear as a duplicate message")));
+ }
+ QTextCursor cursor = input_->textCursor();
+ cursor.select(QTextCursor::Document);
+ cursor.beginEditBlock();
+ cursor.insertText(QString(lastSentMessage_));
+ cursor.endEditBlock();
+ isCorrection_ = true;
+ correctingLabel_->show();
+ input_->setStyleSheet(alertStyleSheet_);
+}
+
+void QtChatWindow::cancelCorrection() {
+ cancelAlert();
+ QTextCursor cursor = input_->textCursor();
+ cursor.select(QTextCursor::Document);
+ cursor.removeSelectedText();
+ isCorrection_ = false;
+ correctingLabel_->hide();
+ input_->setStyleSheet(qApp->styleSheet());
+}
+
+QByteArray QtChatWindow::getSplitterState() {
+ return logRosterSplitter_->saveState();
+}
+
+void QtChatWindow::handleChangeSplitterState(QByteArray state) {
+ logRosterSplitter_->restoreState(state);
+}
+
+void QtChatWindow::handleSplitterMoved(int, int) {
+ emit splitterMoved();
+}
+
void QtChatWindow::tabComplete() {
if (!completer_) {
return;
@@ -150,7 +250,7 @@ void QtChatWindow::tabComplete() {
}
void QtChatWindow::setRosterModel(Roster* roster) {
- treeWidget_->setRosterModel(roster);
+ treeWidget_->setRosterModel(roster);
}
void QtChatWindow::setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) {
@@ -185,6 +285,10 @@ void QtChatWindow::setSecurityLabelsEnabled(bool enabled) {
}
}
+void QtChatWindow::setCorrectionEnabled(Tristate enabled) {
+ correctionEnabled_ = enabled;
+}
+
SecurityLabelsCatalog::Item QtChatWindow::getSelectedSecurityLabel() {
assert(labelsWidget_->isEnabled());
return availableLabels_[labelsWidget_->currentIndex()];
@@ -204,10 +308,13 @@ void QtChatWindow::qAppFocusChanged(QWidget *old, QWidget *now) {
Q_UNUSED(old);
Q_UNUSED(now);
if (isWidgetSelected()) {
+ lastLineTracker_.setHasFocus(true);
input_->setFocus();
onAllMessagesRead();
}
-
+ else {
+ lastLineTracker_.setHasFocus(false);
+ }
}
void QtChatWindow::setInputEnabled(bool enabled) {
@@ -236,7 +343,7 @@ void QtChatWindow::setContactChatState(ChatState::ChatStateType state) {
QtTabbable::AlertType QtChatWindow::getWidgetAlertState() {
if (contactIsTyping_) {
return ImpendingActivity;
- }
+ }
if (unreadCount_ > 0) {
return WaitingActivity;
}
@@ -265,7 +372,6 @@ std::string QtChatWindow::addMessage(const std::string &message, const std::stri
if (isWidgetSelected()) {
onAllMessagesRead();
}
-
QString scaledAvatarPath = QtScaledAvatarCache(32).getScaledAvatarPath(avatarPath.c_str());
QString htmlString;
@@ -281,6 +387,12 @@ std::string QtChatWindow::addMessage(const std::string &message, const std::stri
htmlString += styleSpanStart + messageHTML + styleSpanEnd;
bool appendToPrevious = !previousMessageWasSystem_ && !previousMessageWasPresence_ && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_ && previousSenderName_ == P2QSTRING(senderName)));
+ if (lastLineTracker_.getShouldMoveLastLine()) {
+ /* should this be queued? */
+ messageLog_->addLastSeenLine();
+ /* if the line is added we should break the snippet */
+ appendToPrevious = false;
+ }
QString qAvatarPath = scaledAvatarPath.isEmpty() ? "qrc:/icons/avatar.png" : QUrl::fromLocalFile(scaledAvatarPath).toEncoded();
std::string id = id_.generateID();
messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(time), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id))));
@@ -321,7 +433,7 @@ void QtChatWindow::addErrorMessage(const std::string& errorMessage) {
QString errorMessageHTML(Qt::escape(P2QSTRING(errorMessage)));
errorMessageHTML.replace("\n","<br/>");
- messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet(QString("<span class=\"error\">" + tr("Couldn't send message: %1") + "</span>").arg(errorMessageHTML), QDateTime::currentDateTime(), false, theme_)));
+ messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet("<span class=\"error\">" + errorMessageHTML + "</span>", QDateTime::currentDateTime(), false, theme_)));
previousMessageWasSelf_ = false;
previousMessageWasSystem_ = true;
@@ -343,6 +455,15 @@ void QtChatWindow::addSystemMessage(const std::string& message) {
previousMessageWasPresence_ = false;
}
+void QtChatWindow::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) {
+ if (!id.empty()) {
+ QString messageHTML(Qt::escape(P2QSTRING(message)));
+ messageHTML = P2QSTRING(Linkify::linkify(Q2PSTRING(messageHTML)));
+ messageHTML.replace("\n","<br/>");
+ messageLog_->replaceMessage(messageHTML, P2QSTRING(id), B2QDATE(time));
+ }
+}
+
void QtChatWindow::addPresenceMessage(const std::string& message) {
if (isWidgetSelected()) {
onAllMessagesRead();
@@ -364,9 +485,11 @@ void QtChatWindow::returnPressed() {
return;
}
messageLog_->scrollToBottom();
- onSendMessageRequest(Q2PSTRING(input_->toPlainText()));
+ lastSentMessage_ = QString(input_->toPlainText());
+ onSendMessageRequest(Q2PSTRING(input_->toPlainText()), isCorrection_);
inputClearing_ = true;
input_->clear();
+ cancelCorrection();
inputClearing_ = false;
}
@@ -382,7 +505,9 @@ void QtChatWindow::handleInputChanged() {
}
void QtChatWindow::show() {
- QWidget::show();
+ if (parentWidget() == NULL) {
+ QWidget::show();
+ }
emit windowOpening();
}
@@ -399,7 +524,7 @@ void QtChatWindow::resizeEvent(QResizeEvent*) {
}
void QtChatWindow::moveEvent(QMoveEvent*) {
- emit geometryChanged();
+ emit geometryChanged();
}
void QtChatWindow::replaceLastMessage(const std::string& message) {