summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaciej Niedzielski <machekku@uaznia.net>2012-12-21 19:58:24 (GMT)
committerMaciej Niedzielski <machekku@uaznia.net>2013-01-09 12:34:06 (GMT)
commit4ed137080a3d80d20a2cead47f741e3dd2f2d42e (patch)
treef030f0d9b8e61733de4e2bec9cef7715d380af8f /Swift/QtUI
parenta8e2d82a1be5e94ac39523fc3e0606fcc261e913 (diff)
downloadswift-4ed137080a3d80d20a2cead47f741e3dd2f2d42e.zip
swift-4ed137080a3d80d20a2cead47f741e3dd2f2d42e.tar.bz2
Highlighting support
Change-Id: Ib6bd42cecff018998117bc1e7db279a62b3af434 License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.
Diffstat (limited to 'Swift/QtUI')
-rw-r--r--Swift/QtUI/QtChatWindow.cpp42
-rw-r--r--Swift/QtUI/QtChatWindow.h13
-rw-r--r--Swift/QtUI/QtColorToolButton.cpp45
-rw-r--r--Swift/QtUI/QtColorToolButton.h32
-rw-r--r--Swift/QtUI/QtHighlightEditorWidget.cpp149
-rw-r--r--Swift/QtUI/QtHighlightEditorWidget.h44
-rw-r--r--Swift/QtUI/QtHighlightEditorWidget.ui124
-rw-r--r--Swift/QtUI/QtHighlightRuleWidget.cpp134
-rw-r--r--Swift/QtUI/QtHighlightRuleWidget.h49
-rw-r--r--Swift/QtUI/QtHighlightRuleWidget.ui260
-rw-r--r--Swift/QtUI/QtHighlightRulesItemModel.cpp284
-rw-r--r--Swift/QtUI/QtHighlightRulesItemModel.h64
-rw-r--r--Swift/QtUI/QtLoginWindow.cpp9
-rw-r--r--Swift/QtUI/QtLoginWindow.h2
-rw-r--r--Swift/QtUI/QtSoundPlayer.cpp8
-rw-r--r--Swift/QtUI/QtSoundPlayer.h2
-rw-r--r--Swift/QtUI/QtUIFactory.cpp5
-rw-r--r--Swift/QtUI/QtUIFactory.h1
-rw-r--r--Swift/QtUI/SConscript6
19 files changed, 1252 insertions, 21 deletions
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 5d57184..a53ca5d 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -481,8 +481,8 @@ void QtChatWindow::updateTitleWithUnreadCount() {
emit titleUpdated();
}
-std::string QtChatWindow::addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) {
- return addMessage(linkimoticonify(P2QSTRING(message)), senderName, senderIsSelf, label, avatarPath, "", time);
+std::string QtChatWindow::addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) {
+ return addMessage(linkimoticonify(P2QSTRING(message)), senderName, senderIsSelf, label, avatarPath, "", time, highlight);
}
QString QtChatWindow::linkimoticonify(const QString& message) const {
@@ -502,7 +502,21 @@ QString QtChatWindow::linkimoticonify(const QString& message) const {
return messageHTML;
}
-std::string QtChatWindow::addMessage(const QString &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const QString& style, const boost::posix_time::ptime& time) {
+QString QtChatWindow::getHighlightSpanStart(const HighlightAction& highlight)
+{
+ QString color = Qt::escape(P2QSTRING(highlight.getTextColor()));
+ QString background = Qt::escape(P2QSTRING(highlight.getTextBackground()));
+ if (color.isEmpty()) {
+ color = "black";
+ }
+ if (background.isEmpty()) {
+ background = "yellow";
+ }
+
+ return QString("<span style=\"color: %1; background: %2\">").arg(color).arg(background);
+}
+
+std::string QtChatWindow::addMessage(const QString &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const QString& style, const boost::posix_time::ptime& time, const HighlightAction& highlight) {
if (isWidgetSelected()) {
onAllMessagesRead();
}
@@ -516,7 +530,9 @@ std::string QtChatWindow::addMessage(const QString &message, const std::string &
QString messageHTML(message);
QString styleSpanStart = style == "" ? "" : "<span style=\"" + style + "\">";
QString styleSpanEnd = style == "" ? "" : "</span>";
- htmlString += "<span class='swift_inner_message'>" + styleSpanStart + messageHTML + styleSpanEnd + "</span>" ;
+ QString highlightSpanStart = highlight.highlightText() ? getHighlightSpanStart(highlight) : "";
+ QString highlightSpanEnd = highlight.highlightText() ? "</span>" : "";
+ htmlString += "<span class='swift_inner_message'>" + styleSpanStart + highlightSpanStart + messageHTML + highlightSpanEnd + styleSpanEnd + "</span>" ;
bool appendToPrevious = appendToPreviousCheck(PreviousMessageWasMessage, senderName, senderIsSelf);
if (lastLineTracker_.getShouldMoveLastLine()) {
@@ -572,8 +588,8 @@ int QtChatWindow::getCount() {
return unreadCount_;
}
-std::string QtChatWindow::addAction(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) {
- return addMessage(" *" + linkimoticonify(P2QSTRING(message)) + "*", senderName, senderIsSelf, label, avatarPath, "font-style:italic ", time);
+std::string QtChatWindow::addAction(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) {
+ return addMessage(" *" + linkimoticonify(P2QSTRING(message)) + "*", senderName, senderIsSelf, label, avatarPath, "font-style:italic ", time, highlight);
}
// FIXME: Move this to a different file
@@ -770,15 +786,15 @@ void QtChatWindow::addSystemMessage(const std::string& message) {
previousMessageKind_ = PreviousMessageWasSystem;
}
-void QtChatWindow::replaceWithAction(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) {
- replaceMessage(" *" + linkimoticonify(P2QSTRING(message)) + "*", id, time, "font-style:italic ");
+void QtChatWindow::replaceWithAction(const std::string& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight) {
+ replaceMessage(" *" + linkimoticonify(P2QSTRING(message)) + "*", id, time, "font-style:italic ", highlight);
}
-void QtChatWindow::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) {
- replaceMessage(linkimoticonify(P2QSTRING(message)), id, time, "");
+void QtChatWindow::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight) {
+ replaceMessage(linkimoticonify(P2QSTRING(message)), id, time, "", highlight);
}
-void QtChatWindow::replaceMessage(const QString& message, const std::string& id, const boost::posix_time::ptime& time, const QString& style) {
+void QtChatWindow::replaceMessage(const QString& message, const std::string& id, const boost::posix_time::ptime& time, const QString& style, const HighlightAction& highlight) {
if (!id.empty()) {
if (isWidgetSelected()) {
onAllMessagesRead();
@@ -788,7 +804,9 @@ void QtChatWindow::replaceMessage(const QString& message, const std::string& id,
QString styleSpanStart = style == "" ? "" : "<span style=\"" + style + "\">";
QString styleSpanEnd = style == "" ? "" : "</span>";
- messageHTML = styleSpanStart + messageHTML + styleSpanEnd;
+ QString highlightSpanStart = highlight.highlightText() ? getHighlightSpanStart(highlight) : "";
+ QString highlightSpanEnd = highlight.highlightText() ? "</span>" : "";
+ messageHTML = styleSpanStart + highlightSpanStart + messageHTML + highlightSpanEnd + styleSpanEnd;
messageLog_->replaceMessage(messageHTML, P2QSTRING(id), B2QDATE(time));
}
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index c32ae83..4abd456 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -88,13 +88,13 @@ namespace Swift {
public:
QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings, QMap<QString, QString> emoticons);
~QtChatWindow();
- std::string addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
- std::string addAction(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
+ std::string addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight);
+ std::string addAction(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight);
void addSystemMessage(const std::string& message);
void addPresenceMessage(const std::string& message);
void addErrorMessage(const std::string& errorMessage);
- void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time);
- void replaceWithAction(const std::string& message, const std::string& id, const boost::posix_time::ptime& time);
+ void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight);
+ void replaceWithAction(const std::string& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight);
// File transfer related stuff
std::string addFileTransfer(const std::string& senderName, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes);
void setFileTransferProgress(std::string id, const int percentageDone);
@@ -192,11 +192,12 @@ namespace Swift {
void beginCorrection();
void cancelCorrection();
void handleSettingChanged(const std::string& setting);
- std::string addMessage(const QString& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const QString& style, const boost::posix_time::ptime& time);
- void replaceMessage(const QString& message, const std::string& id, const boost::posix_time::ptime& time, const QString& style);
+ std::string addMessage(const QString& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const QString& style, const boost::posix_time::ptime& time, const HighlightAction& highlight);
+ void replaceMessage(const QString& message, const std::string& id, const boost::posix_time::ptime& time, const QString& style, const HighlightAction& highlight);
void handleOccupantSelectionChanged(RosterItem* item);
bool appendToPreviousCheck(PreviousMessageKind messageKind, const std::string& senderName, bool senderIsSelf) const;
QString linkimoticonify(const QString& message) const;
+ QString getHighlightSpanStart(const HighlightAction& highlight);
int unreadCount_;
bool contactIsTyping_;
diff --git a/Swift/QtUI/QtColorToolButton.cpp b/Swift/QtUI/QtColorToolButton.cpp
new file mode 100644
index 0000000..1d379a3
--- /dev/null
+++ b/Swift/QtUI/QtColorToolButton.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <QColorDialog>
+#include <QPainter>
+
+#include <Swift/QtUI/QtColorToolButton.h>
+
+namespace Swift {
+
+QtColorToolButton::QtColorToolButton(QWidget* parent) :
+ QToolButton(parent)
+{
+ connect(this, SIGNAL(clicked()), SLOT(onClicked()));
+ setColorIcon(Qt::transparent);
+}
+
+void QtColorToolButton::setColor(const QColor& color)
+{
+ if (color.isValid() != color_.isValid() || (color.isValid() && color != color_)) {
+ color_ = color;
+ setColorIcon(color_);
+ emit colorChanged(color_);
+ }
+}
+
+void QtColorToolButton::onClicked()
+{
+ QColor c = QColorDialog::getColor(color_, this);
+ if (c.isValid()) {
+ setColor(c);
+ }
+}
+
+void QtColorToolButton::setColorIcon(const QColor& color)
+{
+ QPixmap pix(iconSize());
+ pix.fill(color.isValid() ? color : Qt::transparent);
+ setIcon(pix);
+}
+
+}
diff --git a/Swift/QtUI/QtColorToolButton.h b/Swift/QtUI/QtColorToolButton.h
new file mode 100644
index 0000000..33d195d
--- /dev/null
+++ b/Swift/QtUI/QtColorToolButton.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QToolButton>
+
+namespace Swift {
+
+ class QtColorToolButton : public QToolButton {
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ getColor WRITE setColor NOTIFY colorChanged)
+ public:
+ explicit QtColorToolButton(QWidget* parent = NULL);
+ void setColor(const QColor& color);
+ const QColor& getColor() const { return color_; }
+
+ signals:
+ void colorChanged(const QColor&);
+
+ private slots:
+ void onClicked();
+
+ private:
+ void setColorIcon(const QColor& color);
+ QColor color_;
+ };
+
+}
diff --git a/Swift/QtUI/QtHighlightEditorWidget.cpp b/Swift/QtUI/QtHighlightEditorWidget.cpp
new file mode 100644
index 0000000..7ff094e
--- /dev/null
+++ b/Swift/QtUI/QtHighlightEditorWidget.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <cassert>
+
+#include <Swift/QtUI/QtHighlightEditorWidget.h>
+#include <Swift/QtUI/QtHighlightRulesItemModel.h>
+
+namespace Swift {
+
+QtHighlightEditorWidget::QtHighlightEditorWidget(QWidget* parent)
+ : QWidget(parent)
+{
+ ui_.setupUi(this);
+
+ itemModel_ = new QtHighlightRulesItemModel(this);
+ ui_.treeView->setModel(itemModel_);
+ ui_.ruleWidget->setModel(itemModel_);
+
+ for (int i = 0; i < QtHighlightRulesItemModel::NumberOfColumns; ++i) {
+ switch (i) {
+ case QtHighlightRulesItemModel::ApplyTo:
+ case QtHighlightRulesItemModel::Sender:
+ case QtHighlightRulesItemModel::Keyword:
+ case QtHighlightRulesItemModel::Action:
+ ui_.treeView->showColumn(i);
+ break;
+ default:
+ ui_.treeView->hideColumn(i);
+ break;
+ }
+ }
+
+ setHighlightManager(NULL); // setup buttons for empty rules list
+
+ connect(ui_.treeView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), SLOT(onCurrentRowChanged(QModelIndex)));
+
+ connect(ui_.newButton, SIGNAL(clicked()), SLOT(onNewButtonClicked()));
+ connect(ui_.deleteButton, SIGNAL(clicked()), SLOT(onDeleteButtonClicked()));
+
+ connect(ui_.moveUpButton, SIGNAL(clicked()), SLOT(onMoveUpButtonClicked()));
+ connect(ui_.moveDownButton, SIGNAL(clicked()), SLOT(onMoveDownButtonClicked()));
+
+ connect(ui_.closeButton, SIGNAL(clicked()), SLOT(close()));
+
+ setWindowTitle(tr("Highlight Rules"));
+}
+
+QtHighlightEditorWidget::~QtHighlightEditorWidget()
+{
+}
+
+void QtHighlightEditorWidget::show()
+{
+ if (itemModel_->rowCount(QModelIndex())) {
+ selectRow(0);
+ }
+ QWidget::show();
+ QWidget::activateWindow();
+}
+
+void QtHighlightEditorWidget::setHighlightManager(HighlightManager* highlightManager)
+{
+ itemModel_->setHighlightManager(highlightManager);
+ ui_.newButton->setEnabled(highlightManager != NULL);
+
+ ui_.ruleWidget->setEnabled(false);
+ ui_.deleteButton->setEnabled(false);
+ ui_.moveUpButton->setEnabled(false);
+ ui_.moveDownButton->setEnabled(false);
+}
+
+void QtHighlightEditorWidget::closeEvent(QCloseEvent* event) {
+ ui_.ruleWidget->save();
+ event->accept();
+}
+
+void QtHighlightEditorWidget::onNewButtonClicked()
+{
+ int row = getSelectedRow() + 1;
+ itemModel_->insertRow(row, QModelIndex());
+ selectRow(row);
+}
+
+void QtHighlightEditorWidget::onDeleteButtonClicked()
+{
+ int row = getSelectedRow();
+ assert(row >= 0);
+
+ itemModel_->removeRow(row, QModelIndex());
+ if (row == itemModel_->rowCount(QModelIndex())) {
+ --row;
+ }
+ selectRow(row);
+}
+
+void QtHighlightEditorWidget::onMoveUpButtonClicked()
+{
+ int row = getSelectedRow();
+ assert(row > 0);
+
+ ui_.ruleWidget->save();
+ ui_.ruleWidget->setActiveIndex(QModelIndex());
+ itemModel_->swapRows(row, row - 1);
+ selectRow(row - 1);
+}
+
+void QtHighlightEditorWidget::onMoveDownButtonClicked()
+{
+ int row = getSelectedRow();
+ assert(row < itemModel_->rowCount(QModelIndex()) - 1);
+
+ ui_.ruleWidget->save();
+ ui_.ruleWidget->setActiveIndex(QModelIndex());
+ if (itemModel_->swapRows(row, row + 1)) {
+ selectRow(row + 1);
+ }
+}
+
+void QtHighlightEditorWidget::onCurrentRowChanged(const QModelIndex& index)
+{
+ ui_.ruleWidget->save();
+ ui_.ruleWidget->setActiveIndex(index);
+
+ ui_.ruleWidget->setEnabled(index.isValid());
+
+ ui_.deleteButton->setEnabled(index.isValid());
+
+ ui_.moveUpButton->setEnabled(index.isValid() && index.row() != 0);
+ ui_.moveDownButton->setEnabled(index.isValid() && index.row() != itemModel_->rowCount(QModelIndex()) - 1);
+}
+
+void QtHighlightEditorWidget::selectRow(int row)
+{
+ QModelIndex index = itemModel_->index(row, 0, QModelIndex());
+ ui_.treeView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
+}
+
+/** Return index of selected row or -1 if none is selected */
+int QtHighlightEditorWidget::getSelectedRow() const
+{
+ QModelIndexList rows = ui_.treeView->selectionModel()->selectedRows();
+ return rows.isEmpty() ? -1 : rows[0].row();
+}
+
+}
diff --git a/Swift/QtUI/QtHighlightEditorWidget.h b/Swift/QtUI/QtHighlightEditorWidget.h
new file mode 100644
index 0000000..1293c87
--- /dev/null
+++ b/Swift/QtUI/QtHighlightEditorWidget.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIInterfaces/HighlightEditorWidget.h>
+#include <Swift/QtUI/ui_QtHighlightEditorWidget.h>
+
+namespace Swift {
+
+ class QtHighlightRulesItemModel;
+
+ class QtHighlightEditorWidget : public QWidget, public HighlightEditorWidget {
+ Q_OBJECT
+
+ public:
+ QtHighlightEditorWidget(QWidget* parent = NULL);
+ virtual ~QtHighlightEditorWidget();
+
+ void show();
+
+ void setHighlightManager(HighlightManager* highlightManager);
+
+ private slots:
+ void onNewButtonClicked();
+ void onDeleteButtonClicked();
+ void onMoveUpButtonClicked();
+ void onMoveDownButtonClicked();
+ void onCurrentRowChanged(const QModelIndex&);
+
+ private:
+ virtual void closeEvent(QCloseEvent* event);
+
+ void selectRow(int row);
+ int getSelectedRow() const;
+
+ Ui::QtHighlightEditorWidget ui_;
+ QtHighlightRulesItemModel* itemModel_;
+ };
+
+}
diff --git a/Swift/QtUI/QtHighlightEditorWidget.ui b/Swift/QtUI/QtHighlightEditorWidget.ui
new file mode 100644
index 0000000..0f39168
--- /dev/null
+++ b/Swift/QtUI/QtHighlightEditorWidget.ui
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtHighlightEditorWidget</class>
+ <widget class="QWidget" name="QtHighlightEditorWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>419</width>
+ <height>373</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Incoming messages are checked against the following rules. First rule that matches will be executed.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="treeView">
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="Swift::QtHighlightRuleWidget" name="ruleWidget" native="true"/>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="newButton">
+ <property name="text">
+ <string>New</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="deleteButton">
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="moveUpButton">
+ <property name="text">
+ <string>Move up</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="moveDownButton">
+ <property name="text">
+ <string>Move down</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Swift::QtHighlightRuleWidget</class>
+ <extends>QWidget</extends>
+ <header>QtHighlightRuleWidget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Swift/QtUI/QtHighlightRuleWidget.cpp b/Swift/QtUI/QtHighlightRuleWidget.cpp
new file mode 100644
index 0000000..9c0df5e
--- /dev/null
+++ b/Swift/QtUI/QtHighlightRuleWidget.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <QDataWidgetMapper>
+#include <QStringListModel>
+#include <QFileDialog>
+
+#include <Swift/QtUI/QtHighlightRuleWidget.h>
+#include <Swift/QtUI/QtHighlightRulesItemModel.h>
+
+namespace Swift {
+
+QtHighlightRuleWidget::QtHighlightRuleWidget(QWidget* parent)
+ : QWidget(parent)
+{
+ ui_.setupUi(this);
+
+ QStringList applyToItems;
+ for (int i = 0; i < QtHighlightRulesItemModel::ApplyToEOL; ++i) {
+ applyToItems << QtHighlightRulesItemModel::getApplyToString(i);
+ }
+ QStringListModel * applyToModel = new QStringListModel(applyToItems, this);
+ ui_.applyTo->setModel(applyToModel);
+
+ connect(ui_.highlightText, SIGNAL(toggled(bool)), SLOT(onHighlightTextToggled(bool)));
+ connect(ui_.customColors, SIGNAL(toggled(bool)), SLOT(onCustomColorsToggled(bool)));
+ connect(ui_.playSound, SIGNAL(toggled(bool)), SLOT(onPlaySoundToggled(bool)));
+ connect(ui_.customSound, SIGNAL(toggled(bool)), SLOT(onCustomSoundToggled(bool)));
+ connect(ui_.soundFileButton, SIGNAL(clicked()), SLOT(onSoundFileButtonClicked()));
+
+ mapper_ = new QDataWidgetMapper(this);
+ hasValidIndex_ = false;
+ model_ = NULL;
+}
+
+QtHighlightRuleWidget::~QtHighlightRuleWidget()
+{
+}
+
+/** Widget does not gain ownership over the model */
+void QtHighlightRuleWidget::setModel(QtHighlightRulesItemModel* model)
+{
+ model_ = model;
+ mapper_->setModel(model_);
+}
+
+void QtHighlightRuleWidget::setActiveIndex(const QModelIndex& index)
+{
+ if (index.isValid()) {
+ if (!hasValidIndex_) {
+ mapper_->addMapping(ui_.applyTo, QtHighlightRulesItemModel::ApplyTo, "currentIndex");
+ mapper_->addMapping(ui_.senders, QtHighlightRulesItemModel::Sender, "plainText");
+ mapper_->addMapping(ui_.keywords, QtHighlightRulesItemModel::Keyword, "plainText");
+ mapper_->addMapping(ui_.nickIsKeyword, QtHighlightRulesItemModel::NickIsKeyword);
+ mapper_->addMapping(ui_.matchCase, QtHighlightRulesItemModel::MatchCase);
+ mapper_->addMapping(ui_.matchWholeWords, QtHighlightRulesItemModel::MatchWholeWords);
+ mapper_->addMapping(ui_.highlightText, QtHighlightRulesItemModel::HighlightText);
+ mapper_->addMapping(ui_.foreground, QtHighlightRulesItemModel::TextColor, "color");
+ mapper_->addMapping(ui_.background, QtHighlightRulesItemModel::TextBackground, "color");
+ mapper_->addMapping(ui_.playSound, QtHighlightRulesItemModel::PlaySound);
+ mapper_->addMapping(ui_.soundFile, QtHighlightRulesItemModel::SoundFile);
+ }
+ mapper_->setCurrentModelIndex(index);
+ ui_.customColors->setChecked(ui_.foreground->getColor().isValid() || ui_.background->getColor().isValid());
+ ui_.customSound->setChecked(!ui_.soundFile->text().isEmpty());
+ ui_.applyTo->focusWidget();
+ } else {
+ if (hasValidIndex_) {
+ mapper_->clearMapping();
+ }
+ }
+
+ hasValidIndex_ = index.isValid();
+}
+
+void QtHighlightRuleWidget::onCustomColorsToggled(bool enabled)
+{
+ if (!enabled) {
+ ui_.foreground->setColor(QColor());
+ ui_.background->setColor(QColor());
+ }
+ ui_.foreground->setEnabled(enabled);
+ ui_.background->setEnabled(enabled);
+}
+
+void QtHighlightRuleWidget::onCustomSoundToggled(bool enabled)
+{
+ if (enabled) {
+ if (ui_.soundFile->text().isEmpty()) {
+ onSoundFileButtonClicked();
+ }
+ } else {
+ ui_.soundFile->clear();
+ }
+ ui_.soundFile->setEnabled(enabled);
+ ui_.soundFileButton->setEnabled(enabled);
+}
+
+void QtHighlightRuleWidget::onSoundFileButtonClicked()
+{
+ QString s = QFileDialog::getOpenFileName(this, tr("Choose sound file"), QString(), tr("Sound files (*.wav)"));
+ if (!s.isEmpty()) {
+ ui_.soundFile->setText(s);
+ }
+}
+
+void QtHighlightRuleWidget::onHighlightTextToggled(bool enabled)
+{
+ ui_.customColors->setEnabled(enabled);
+}
+
+void QtHighlightRuleWidget::onPlaySoundToggled(bool enabled)
+{
+ ui_.customSound->setEnabled(enabled);
+}
+
+void QtHighlightRuleWidget::save()
+{
+ if (hasValidIndex_) {
+ mapper_->submit();
+ }
+}
+
+void QtHighlightRuleWidget::revert()
+{
+ if (hasValidIndex_) {
+ mapper_->revert();
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtHighlightRuleWidget.h b/Swift/QtUI/QtHighlightRuleWidget.h
new file mode 100644
index 0000000..8a59a14
--- /dev/null
+++ b/Swift/QtUI/QtHighlightRuleWidget.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QWidget>
+#include <QModelIndex>
+
+#include <Swift/QtUI/ui_QtHighlightRuleWidget.h>
+
+class QDataWidgetMapper;
+
+namespace Swift {
+
+ class QtHighlightRulesItemModel;
+
+ class QtHighlightRuleWidget : public QWidget
+ {
+ Q_OBJECT
+
+ public:
+ explicit QtHighlightRuleWidget(QWidget* parent = NULL);
+ ~QtHighlightRuleWidget();
+
+ void setModel(QtHighlightRulesItemModel* model);
+
+ public slots:
+ void setActiveIndex(const QModelIndex&);
+ void save();
+ void revert();
+
+ private slots:
+ void onHighlightTextToggled(bool);
+ void onCustomColorsToggled(bool);
+ void onPlaySoundToggled(bool);
+ void onCustomSoundToggled(bool);
+ void onSoundFileButtonClicked();
+
+ private:
+ QDataWidgetMapper * mapper_;
+ QtHighlightRulesItemModel * model_;
+ bool hasValidIndex_;
+ Ui::QtHighlightRuleWidget ui_;
+ };
+
+}
diff --git a/Swift/QtUI/QtHighlightRuleWidget.ui b/Swift/QtUI/QtHighlightRuleWidget.ui
new file mode 100644
index 0000000..9c465f9
--- /dev/null
+++ b/Swift/QtUI/QtHighlightRuleWidget.ui
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtHighlightRuleWidget</class>
+ <widget class="QWidget" name="QtHighlightRuleWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>361</width>
+ <height>524</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Rule conditions</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0" colspan="2">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Choose when this rule should be applied.
+If you want to provide more than one sender or keyword, input them in separate lines.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>&amp;Apply to:</string>
+ </property>
+ <property name="buddy">
+ <cstring>applyTo</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QComboBox" name="applyTo"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>&amp;Senders:</string>
+ </property>
+ <property name="buddy">
+ <cstring>senders</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QPlainTextEdit" name="senders"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>&amp;Keywords:</string>
+ </property>
+ <property name="buddy">
+ <cstring>keywords</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QPlainTextEdit" name="keywords"/>
+ </item>
+ <item row="5" column="1">
+ <widget class="QCheckBox" name="nickIsKeyword">
+ <property name="text">
+ <string>Treat &amp;nick as a keyword (in MUC)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QCheckBox" name="matchWholeWords">
+ <property name="text">
+ <string>Match whole &amp;words</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="QCheckBox" name="matchCase">
+ <property name="text">
+ <string>Match &amp;case</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Actions</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QCheckBox" name="highlightText">
+ <property name="text">
+ <string>&amp;Highlight text</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>28</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="customColors">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Custom c&amp;olors:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Swift::QtColorToolButton" name="foreground">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Foreground</string>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Swift::QtColorToolButton" name="background">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Background</string>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="playSound">
+ <property name="text">
+ <string>&amp;Play sound</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>28</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="customSound">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Custom soun&amp;d:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="soundFile">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="soundFileButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>101</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Swift::QtColorToolButton</class>
+ <extends>QToolButton</extends>
+ <header>QtColorToolButton.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Swift/QtUI/QtHighlightRulesItemModel.cpp b/Swift/QtUI/QtHighlightRulesItemModel.cpp
new file mode 100644
index 0000000..ff2f639
--- /dev/null
+++ b/Swift/QtUI/QtHighlightRulesItemModel.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <boost/algorithm/string.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <QStringList>
+#include <QColor>
+
+#include <Swift/Controllers/HighlightManager.h>
+#include <Swift/QtUI/QtHighlightRulesItemModel.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtHighlightRulesItemModel::QtHighlightRulesItemModel(QObject* parent) : QAbstractItemModel(parent), highlightManager_(NULL)
+{
+}
+
+void QtHighlightRulesItemModel::setHighlightManager(HighlightManager* highlightManager)
+{
+ emit layoutAboutToBeChanged();
+ highlightManager_ = highlightManager;
+ emit layoutChanged();
+}
+
+QVariant QtHighlightRulesItemModel::headerData(int section, Qt::Orientation /* orientation */, int role) const
+{
+ if (role == Qt::DisplayRole) {
+ switch (section) {
+ case ApplyTo: return QVariant(tr("Apply to"));
+ case Sender: return QVariant(tr("Sender"));
+ case Keyword: return QVariant(tr("Keyword"));
+ case Action: return QVariant(tr("Action"));
+ case NickIsKeyword: return QVariant(tr("Nick Is Keyword"));
+ case MatchCase: return QVariant(tr("Match Case"));
+ case MatchWholeWords: return QVariant(tr("Match Whole Words"));
+ case HighlightText: return QVariant(tr("Highlight Text"));
+ case TextColor: return QVariant(tr("Text Color"));
+ case TextBackground: return QVariant(tr("Text Background"));
+ case PlaySound: return QVariant(tr("Play Sounds"));
+ case SoundFile: return QVariant(tr("Sound File"));
+ }
+ }
+
+ return QVariant();
+}
+
+int QtHighlightRulesItemModel::columnCount(const QModelIndex& /* parent */) const
+{
+ return NumberOfColumns;
+}
+
+QVariant QtHighlightRulesItemModel::data(const QModelIndex &index, int role) const
+{
+ if (index.isValid() && highlightManager_ && (role == Qt::DisplayRole || role == Qt::EditRole)) {
+
+ const char* separator = (role == Qt::DisplayRole) ? " ; " : "\n";
+
+ if (boost::numeric_cast<std::vector<std::string>::size_type>(index.row()) < highlightManager_->getRules().size()) {
+ const HighlightRule& r = highlightManager_->getRules()[index.row()];
+ switch (index.column()) {
+ case ApplyTo: {
+ int applyTo = 0;
+ if (r.getMatchChat() && r.getMatchMUC()) {
+ applyTo = 1;
+ } else if (r.getMatchChat()) {
+ applyTo = 2;
+ } else if (r.getMatchMUC()) {
+ applyTo = 3;
+ }
+
+ if (role == Qt::DisplayRole) {
+ return QVariant(getApplyToString(applyTo));
+ } else {
+ return QVariant(applyTo);
+ }
+ }
+ case Sender: {
+ std::string s = boost::join(r.getSenders(), separator);
+ return QVariant(P2QSTRING(s));
+ }
+ case Keyword: {
+ std::string s = boost::join(r.getKeywords(), separator);
+ QString qs(P2QSTRING(s));
+ if (role == Qt::DisplayRole && r.getNickIsKeyword()) {
+ qs = tr("<nick>") + (qs.isEmpty() ? "" : separator + qs);
+ }
+ return QVariant(qs);
+ }
+ case Action: {
+ std::vector<std::string> v;
+ const HighlightAction & action = r.getAction();
+ if (action.highlightText()) {
+ v.push_back(Q2PSTRING(tr("Highlight text")));
+ }
+ if (action.playSound()) {
+ v.push_back(Q2PSTRING(tr("Play sound")));
+ }
+ std::string s = boost::join(v, separator);
+ return QVariant(P2QSTRING(s));
+ }
+ case NickIsKeyword: {
+ return QVariant(r.getNickIsKeyword());
+ }
+ case MatchCase: {
+ return QVariant(r.getMatchCase());
+ }
+ case MatchWholeWords: {
+ return QVariant(r.getMatchWholeWords());
+ }
+ case HighlightText: {
+ return QVariant(r.getAction().highlightText());
+ }
+ case TextColor: {
+ return QVariant(QColor(P2QSTRING(r.getAction().getTextColor())));
+ }
+ case TextBackground: {
+ return QVariant(QColor(P2QSTRING(r.getAction().getTextBackground())));
+ }
+ case PlaySound: {
+ return QVariant(r.getAction().playSound());
+ }
+ case SoundFile: {
+ return QVariant(P2QSTRING(r.getAction().getSoundFile()));
+ }
+ }
+ }
+ }
+ return QVariant();
+}
+
+bool QtHighlightRulesItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (index.isValid() && highlightManager_ && role == Qt::EditRole) {
+ if (boost::numeric_cast<std::vector<std::string>::size_type>(index.row()) < highlightManager_->getRules().size()) {
+ HighlightRule r = highlightManager_->getRule(index.row());
+ std::vector<int> changedColumns;
+ switch (index.column()) {
+ case ApplyTo: {
+ bool ok = false;
+ int applyTo = value.toInt(&ok);
+ if (!ok) {
+ return false;
+ }
+ r.setMatchChat(applyTo == ApplyToAll || applyTo == ApplyToChat);
+ r.setMatchMUC(applyTo == ApplyToAll || applyTo == ApplyToMUC);
+ break;
+ }
+ case Sender:
+ case Keyword: {
+ std::string s = Q2PSTRING(value.toString());
+ std::vector<std::string> v;
+ boost::split(v, s, boost::is_any_of("\n"));
+ v.erase(std::remove_if(v.begin(), v.end(), boost::lambda::_1 == ""), v.end());
+ if (index.column() == Sender) {
+ r.setSenders(v);
+ } else {
+ r.setKeywords(v);
+ }
+ break;
+ }
+ case NickIsKeyword: {
+ r.setNickIsKeyword(value.toBool());
+ changedColumns.push_back(Keyword); // "<nick>"
+ break;
+ }
+ case MatchCase: {
+ r.setMatchCase(value.toBool());
+ break;
+ }
+ case MatchWholeWords: {
+ r.setMatchWholeWords(value.toBool());
+ break;
+ }
+ case HighlightText: {
+ r.getAction().setHighlightText(value.toBool());
+ changedColumns.push_back(Action);
+ break;
+ }
+ case TextColor: {
+ QColor c = value.value<QColor>();
+ r.getAction().setTextColor(c.isValid() ? Q2PSTRING(c.name()) : "");
+ break;
+ }
+ case TextBackground: {
+ QColor c = value.value<QColor>();
+ r.getAction().setTextBackground(c.isValid() ? Q2PSTRING(c.name()) : "");
+ break;
+ }
+ case PlaySound: {
+ r.getAction().setPlaySound(value.toBool());
+ changedColumns.push_back(Action);
+ break;
+ }
+ case SoundFile: {
+ r.getAction().setSoundFile(Q2PSTRING(value.toString()));
+ break;
+ }
+ }
+
+ highlightManager_->setRule(index.row(), r);
+ emit dataChanged(index, index);
+ foreach (int column, changedColumns) {
+ QModelIndex i = createIndex(index.row(), column, 0);
+ emit dataChanged(i, i);
+ }
+ }
+ }
+
+ return false;
+}
+
+QModelIndex QtHighlightRulesItemModel::parent(const QModelIndex& /* child */) const
+{
+ return QModelIndex();
+}
+
+int QtHighlightRulesItemModel::rowCount(const QModelIndex& /* parent */) const
+{
+ return highlightManager_ ? highlightManager_->getRules().size() : 0;
+}
+
+QModelIndex QtHighlightRulesItemModel::index(int row, int column, const QModelIndex& /* parent */) const
+{
+ return createIndex(row, column, 0);
+}
+
+bool QtHighlightRulesItemModel::insertRows(int row, int count, const QModelIndex& /* parent */)
+{
+ if (highlightManager_) {
+ beginInsertRows(QModelIndex(), row, row + count);
+ while (count--) {
+ highlightManager_->insertRule(row, HighlightRule());
+ }
+ endInsertRows();
+ return true;
+ }
+ return false;
+}
+
+bool QtHighlightRulesItemModel::removeRows(int row, int count, const QModelIndex& /* parent */)
+{
+ if (highlightManager_) {
+ beginRemoveRows(QModelIndex(), row, row + count);
+ while (count--) {
+ highlightManager_->removeRule(row);
+ }
+ endRemoveRows();
+ return true;
+ }
+ return false;
+}
+
+bool QtHighlightRulesItemModel::swapRows(int row1, int row2)
+{
+ if (highlightManager_) {
+ assert(row1 >= 0 && row2 >= 0 && boost::numeric_cast<std::vector<std::string>::size_type>(row1) < highlightManager_->getRules().size() && boost::numeric_cast<std::vector<std::string>::size_type>(row2) < highlightManager_->getRules().size());
+ HighlightRule r = highlightManager_->getRule(row1);
+ highlightManager_->setRule(row1, highlightManager_->getRule(row2));
+ highlightManager_->setRule(row2, r);
+ emit dataChanged(index(row1, 0, QModelIndex()), index(row1, 0, QModelIndex()));
+ emit dataChanged(index(row2, 0, QModelIndex()), index(row2, 0, QModelIndex()));
+ return true;
+ }
+ return false;
+}
+
+QString QtHighlightRulesItemModel::getApplyToString(int applyTo)
+{
+ switch (applyTo) {
+ case ApplyToNone: return tr("None");
+ case ApplyToAll: return tr("Chat or MUC");
+ case ApplyToChat: return tr("Chat");
+ case ApplyToMUC: return tr("MUC");
+ default: return "";
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtHighlightRulesItemModel.h b/Swift/QtUI/QtHighlightRulesItemModel.h
new file mode 100644
index 0000000..ac85628
--- /dev/null
+++ b/Swift/QtUI/QtHighlightRulesItemModel.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QAbstractItemModel>
+
+namespace Swift {
+
+ class HighlightManager;
+
+ class QtHighlightRulesItemModel : public QAbstractItemModel {
+ Q_OBJECT
+
+ public:
+ QtHighlightRulesItemModel(QObject* parent = NULL);
+
+ void setHighlightManager(HighlightManager* highlightManager);
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ int columnCount(const QModelIndex& parent) const;
+ QVariant data(const QModelIndex& index, int role) const;
+ bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
+ QModelIndex parent(const QModelIndex& child) const;
+ int rowCount(const QModelIndex& parent) const;
+ QModelIndex index(int row, int column, const QModelIndex& parent) const;
+ bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex());
+ bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex());
+ bool swapRows(int row1, int row2);
+
+ static QString getApplyToString(int);
+
+ enum Columns {
+ ApplyTo = 0,
+ Sender,
+ Keyword,
+ Action,
+ NickIsKeyword,
+ MatchCase,
+ MatchWholeWords,
+ HighlightText,
+ TextColor,
+ TextBackground,
+ PlaySound,
+ SoundFile,
+ NumberOfColumns // end of list marker
+ };
+
+ enum ApplyToValues {
+ ApplyToNone = 0,
+ ApplyToAll,
+ ApplyToChat,
+ ApplyToMUC,
+ ApplyToEOL // end of list marker
+ };
+
+ private:
+ HighlightManager* highlightManager_;
+ };
+
+}
diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp
index c27edfb..cf22ad0 100644
--- a/Swift/QtUI/QtLoginWindow.cpp
+++ b/Swift/QtUI/QtLoginWindow.cpp
@@ -30,6 +30,7 @@
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/RequestXMLConsoleUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestFileTransferListUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestHighlightEditorUIEvent.h>
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/QtUI/QtUISettingConstants.h>
@@ -190,6 +191,10 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream, SettingsProvider* set
generalMenu_->addAction(fileTransferOverviewAction_);
#endif
+ highlightEditorAction_ = new QAction(tr("&Edit Highlight Rules"), this);
+ connect(highlightEditorAction_, SIGNAL(triggered()), SLOT(handleShowHighlightEditor()));
+ generalMenu_->addAction(highlightEditorAction_);
+
toggleSoundsAction_ = new QAction(tr("&Play Sounds"), this);
toggleSoundsAction_->setCheckable(true);
toggleSoundsAction_->setChecked(settings_->getSetting(SettingConstants::PLAY_SOUNDS));
@@ -438,6 +443,10 @@ void QtLoginWindow::handleShowFileTransferOverview() {
uiEventStream_->send(boost::make_shared<RequestFileTransferListUIEvent>());
}
+void QtLoginWindow::handleShowHighlightEditor() {
+ uiEventStream_->send(boost::make_shared<RequestHighlightEditorUIEvent>());
+}
+
void QtLoginWindow::handleToggleSounds(bool enabled) {
settings_->storeSetting(SettingConstants::PLAY_SOUNDS, enabled);
}
diff --git a/Swift/QtUI/QtLoginWindow.h b/Swift/QtUI/QtLoginWindow.h
index c1966d8..7415fbf 100644
--- a/Swift/QtUI/QtLoginWindow.h
+++ b/Swift/QtUI/QtLoginWindow.h
@@ -62,6 +62,7 @@ namespace Swift {
void handleQuit();
void handleShowXMLConsole();
void handleShowFileTransferOverview();
+ void handleShowHighlightEditor();
void handleToggleSounds(bool enabled);
void handleToggleNotifications(bool enabled);
void handleAbout();
@@ -103,6 +104,7 @@ namespace Swift {
SettingsProvider* settings_;
QAction* xmlConsoleAction_;
QAction* fileTransferOverviewAction_;
+ QAction* highlightEditorAction_;
TimerFactory* timerFactory_;
ClientOptions currentOptions_;
};
diff --git a/Swift/QtUI/QtSoundPlayer.cpp b/Swift/QtUI/QtSoundPlayer.cpp
index 387c6f3..63f76f0 100644
--- a/Swift/QtUI/QtSoundPlayer.cpp
+++ b/Swift/QtUI/QtSoundPlayer.cpp
@@ -16,10 +16,11 @@ namespace Swift {
QtSoundPlayer::QtSoundPlayer(ApplicationPathProvider* applicationPathProvider) : applicationPathProvider(applicationPathProvider) {
}
-void QtSoundPlayer::playSound(SoundEffect sound) {
+void QtSoundPlayer::playSound(SoundEffect sound, const std::string& soundResource) {
+
switch (sound) {
case MessageReceived:
- playSound("/sounds/message-received.wav");
+ playSound(soundResource.empty() ? "/sounds/message-received.wav" : soundResource);
break;
}
}
@@ -29,6 +30,9 @@ void QtSoundPlayer::playSound(const std::string& soundResource) {
if (boost::filesystem::exists(resourcePath)) {
QSound::play(resourcePath.string().c_str());
}
+ else if (boost::filesystem::exists(soundResource)) {
+ QSound::play(soundResource.c_str());
+ }
else {
std::cerr << "Unable to find sound: " << soundResource << std::endl;
}
diff --git a/Swift/QtUI/QtSoundPlayer.h b/Swift/QtUI/QtSoundPlayer.h
index 6945f45..f8da392 100644
--- a/Swift/QtUI/QtSoundPlayer.h
+++ b/Swift/QtUI/QtSoundPlayer.h
@@ -19,7 +19,7 @@ namespace Swift {
public:
QtSoundPlayer(ApplicationPathProvider* applicationPathProvider);
- void playSound(SoundEffect sound);
+ void playSound(SoundEffect sound, const std::string& soundResource);
private:
void playSound(const std::string& soundResource);
diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp
index 008d042..2ec2818 100644
--- a/Swift/QtUI/QtUIFactory.cpp
+++ b/Swift/QtUI/QtUIFactory.cpp
@@ -25,6 +25,7 @@
#include "QtContactEditWindow.h"
#include "QtAdHocCommandWindow.h"
#include "QtFileTransferListWidget.h"
+#include <QtHighlightEditorWidget.h>
#include "Whiteboard/QtWhiteboardWindow.h"
#include <Swift/Controllers/Settings/SettingsProviderHierachy.h>
#include <Swift/QtUI/QtUISettingConstants.h>
@@ -162,6 +163,10 @@ WhiteboardWindow* QtUIFactory::createWhiteboardWindow(boost::shared_ptr<Whiteboa
return new QtWhiteboardWindow(whiteboardSession);
}
+HighlightEditorWidget* QtUIFactory::createHighlightEditorWidget() {
+ return new QtHighlightEditorWidget();
+}
+
void QtUIFactory::createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command) {
new QtAdHocCommandWindow(command);
}
diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h
index 4cf91ca..a1baa82 100644
--- a/Swift/QtUI/QtUIFactory.h
+++ b/Swift/QtUI/QtUIFactory.h
@@ -48,6 +48,7 @@ namespace Swift {
virtual ContactEditWindow* createContactEditWindow();
virtual FileTransferListWidget* createFileTransferListWidget();
virtual WhiteboardWindow* createWhiteboardWindow(boost::shared_ptr<WhiteboardSession> whiteboardSession);
+ virtual HighlightEditorWidget* createHighlightEditorWidget();
virtual void createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command);
private slots:
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 607a8a6..cd0ed57 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -113,6 +113,10 @@ sources = [
"QtContactEditWindow.cpp",
"QtContactEditWidget.cpp",
"QtSingleWindow.cpp",
+ "QtHighlightEditorWidget.cpp",
+ "QtHighlightRulesItemModel.cpp",
+ "QtHighlightRuleWidget.cpp",
+ "QtColorToolButton.cpp",
"ChatSnippet.cpp",
"MessageSnippet.cpp",
"SystemMessageSnippet.cpp",
@@ -231,6 +235,8 @@ myenv.Uic4("QtAffiliationEditor.ui")
myenv.Uic4("QtJoinMUCWindow.ui")
myenv.Uic4("QtHistoryWindow.ui")
myenv.Uic4("QtConnectionSettings.ui")
+myenv.Uic4("QtHighlightRuleWidget.ui")
+myenv.Uic4("QtHighlightEditorWidget.ui")
myenv.Qrc("DefaultTheme.qrc")
myenv.Qrc("Swift.qrc")