diff options
Diffstat (limited to 'Swift/QtUI/QtChatWindow.cpp')
| -rw-r--r-- | Swift/QtUI/QtChatWindow.cpp | 165 | 
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) {  | 
 Swift