summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/QtUI')
-rw-r--r--Swift/QtUI/.gitignore1
-rw-r--r--Swift/QtUI/ChatList/ChatListDelegate.cpp39
-rw-r--r--Swift/QtUI/ChatList/ChatListDelegate.h5
-rw-r--r--Swift/QtUI/ChatList/ChatListGroupItem.h7
-rw-r--r--Swift/QtUI/ChatList/ChatListMUCItem.cpp2
-rw-r--r--Swift/QtUI/ChatList/ChatListMUCItem.h14
-rw-r--r--Swift/QtUI/ChatList/ChatListModel.cpp22
-rw-r--r--Swift/QtUI/ChatList/ChatListModel.h11
-rw-r--r--Swift/QtUI/ChatList/ChatListRecentItem.cpp47
-rw-r--r--Swift/QtUI/ChatList/ChatListRecentItem.h35
-rw-r--r--Swift/QtUI/ChatList/QtChatListWindow.cpp32
-rw-r--r--Swift/QtUI/ChatList/QtChatListWindow.h9
-rw-r--r--Swift/QtUI/ChatSnippet.h9
-rw-r--r--Swift/QtUI/EventViewer/QtEventWindow.h2
-rw-r--r--Swift/QtUI/MUCSearch/MUCSearchRoomItem.h2
-rw-r--r--Swift/QtUI/MUCSearch/MUCSearchServiceItem.h2
-rw-r--r--Swift/QtUI/QtAdHocCommandWindow.cpp137
-rw-r--r--Swift/QtUI/QtAdHocCommandWindow.h48
-rw-r--r--Swift/QtUI/QtAvatarWidget.cpp8
-rw-r--r--Swift/QtUI/QtBookmarkDetailWindow.ui2
-rw-r--r--Swift/QtUI/QtChatTabs.cpp14
-rw-r--r--Swift/QtUI/QtChatTheme.cpp2
-rw-r--r--Swift/QtUI/QtChatTheme.h34
-rw-r--r--Swift/QtUI/QtChatView.cpp85
-rw-r--r--Swift/QtUI/QtChatView.h13
-rw-r--r--Swift/QtUI/QtChatWindow.cpp165
-rw-r--r--Swift/QtUI/QtChatWindow.h37
-rw-r--r--Swift/QtUI/QtChatWindowFactory.cpp25
-rw-r--r--Swift/QtUI/QtChatWindowFactory.h3
-rw-r--r--Swift/QtUI/QtContactEditWindow.cpp1
-rw-r--r--Swift/QtUI/QtDBUSURIHandler.cpp41
-rw-r--r--Swift/QtUI/QtDBUSURIHandler.h17
-rw-r--r--Swift/QtUI/QtFormWidget.cpp242
-rw-r--r--Swift/QtUI/QtFormWidget.h31
-rw-r--r--Swift/QtUI/QtJoinMUCWindow.cpp7
-rw-r--r--Swift/QtUI/QtJoinMUCWindow.h4
-rw-r--r--Swift/QtUI/QtLoginWindow.cpp42
-rw-r--r--Swift/QtUI/QtLoginWindow.h11
-rw-r--r--Swift/QtUI/QtMainWindow.cpp84
-rw-r--r--Swift/QtUI/QtMainWindow.h13
-rw-r--r--Swift/QtUI/QtSubscriptionRequestWindow.cpp2
-rw-r--r--Swift/QtUI/QtSwift.cpp42
-rw-r--r--Swift/QtUI/QtSwift.h6
-rw-r--r--Swift/QtUI/QtTextEdit.cpp16
-rw-r--r--Swift/QtUI/QtUIFactory.cpp34
-rw-r--r--Swift/QtUI/QtUIFactory.h8
-rw-r--r--Swift/QtUI/QtURIHandler.cpp36
-rw-r--r--Swift/QtUI/QtURIHandler.h22
-rw-r--r--Swift/QtUI/QtWebView.cpp9
-rw-r--r--Swift/QtUI/QtWebView.h4
-rw-r--r--Swift/QtUI/QtXMLConsoleWidget.cpp8
-rw-r--r--Swift/QtUI/QtXMLConsoleWidget.h4
-rw-r--r--Swift/QtUI/Roster/DelegateCommons.cpp88
-rw-r--r--Swift/QtUI/Roster/DelegateCommons.h11
-rw-r--r--Swift/QtUI/Roster/QtTreeWidgetItem.cpp242
-rw-r--r--Swift/QtUI/Roster/QtTreeWidgetItem.h86
-rw-r--r--Swift/QtUI/Roster/RosterDelegate.cpp81
-rw-r--r--Swift/QtUI/Roster/RosterDelegate.h4
-rw-r--r--Swift/QtUI/SConscript61
-rw-r--r--Swift/QtUI/main.cpp2
-rw-r--r--Swift/QtUI/swift-open-uri.cpp30
61 files changed, 1491 insertions, 610 deletions
diff --git a/Swift/QtUI/.gitignore b/Swift/QtUI/.gitignore
index f539e86..53acb9f 100644
--- a/Swift/QtUI/.gitignore
+++ b/Swift/QtUI/.gitignore
@@ -1,3 +1,4 @@
Swift
BuildVersion.h
*.dmg
+swift-open-uri
diff --git a/Swift/QtUI/ChatList/ChatListDelegate.cpp b/Swift/QtUI/ChatList/ChatListDelegate.cpp
index 274a10a..29dba62 100644
--- a/Swift/QtUI/ChatList/ChatListDelegate.cpp
+++ b/Swift/QtUI/ChatList/ChatListDelegate.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.
*/
@@ -11,6 +11,7 @@
#include "Swift/QtUI/Roster/GroupItemDelegate.h"
#include "Swift/QtUI/ChatList/ChatListItem.h"
#include "Swift/QtUI/ChatList/ChatListMUCItem.h"
+#include "Swift/QtUI/ChatList/ChatListRecentItem.h"
#include "Swift/QtUI/ChatList/ChatListGroupItem.h"
namespace Swift {
@@ -27,7 +28,11 @@ QSize ChatListDelegate::sizeHint(const QStyleOptionViewItem& option, const QMode
ChatListItem* item = static_cast<ChatListItem*>(index.internalPointer());
if (item && dynamic_cast<ChatListMUCItem*>(item)) {
return mucSizeHint(option, index);
- } else if (item && dynamic_cast<ChatListGroupItem*>(item)) {
+ }
+ else if (item && dynamic_cast<ChatListRecentItem*>(item)) {
+ return common_.contactSizeHint(option, index);
+ }
+ else if (item && dynamic_cast<ChatListGroupItem*>(item)) {
return groupDelegate_->sizeHint(option, index);
}
return QStyledItemDelegate::sizeHint(option, index);
@@ -40,14 +45,23 @@ QSize ChatListDelegate::mucSizeHint(const QStyleOptionViewItem& /*option*/, cons
return QSize(150, sizeByText);
}
+QSize ChatListDelegate::recentSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
+ return mucSizeHint(option, index);
+}
+
void ChatListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
ChatListItem* item = static_cast<ChatListItem*>(index.internalPointer());
if (item && dynamic_cast<ChatListMUCItem*>(item)) {
paintMUC(painter, option, dynamic_cast<ChatListMUCItem*>(item));
- } else if (item && dynamic_cast<ChatListGroupItem*>(item)) {
+ }
+ else if (item && dynamic_cast<ChatListRecentItem*>(item)) {
+ paintRecent(painter, option, dynamic_cast<ChatListRecentItem*>(item));
+ }
+ else if (item && dynamic_cast<ChatListGroupItem*>(item)) {
ChatListGroupItem* group = dynamic_cast<ChatListGroupItem*>(item);
groupDelegate_->paint(painter, option, group->data(Qt::DisplayRole).toString(), group->rowCount(), option.state & QStyle::State_Open);
- } else {
+ }
+ else {
QStyledItemDelegate::paint(painter, option, index);
}
}
@@ -78,9 +92,24 @@ void ChatListDelegate::paintMUC(QPainter* painter, const QStyleOptionViewItem& o
painter->setPen(QPen(QColor(160,160,160)));
QRect detailRegion(textRegion.adjusted(0, nameHeight, 0, 0));
- DelegateCommons::drawElidedText(painter, detailRegion, item->data(DetailTextRole).toString());
+ DelegateCommons::drawElidedText(painter, detailRegion, item->data(ChatListMUCItem::DetailTextRole).toString());
painter->restore();
}
+void ChatListDelegate::paintRecent(QPainter* painter, const QStyleOptionViewItem& option, ChatListRecentItem* item) const {
+ QColor nameColor = item->data(Qt::TextColorRole).value<QColor>();
+ QString avatarPath;
+ if (item->data(ChatListRecentItem::AvatarRole).isValid() && !item->data(ChatListRecentItem::AvatarRole).value<QString>().isNull()) {
+ avatarPath = item->data(ChatListRecentItem::AvatarRole).value<QString>();
+ }
+ QIcon presenceIcon = item->data(ChatListRecentItem::PresenceIconRole).isValid() && !item->data(ChatListRecentItem::PresenceIconRole).value<QIcon>().isNull()
+ ? item->data(ChatListRecentItem::PresenceIconRole).value<QIcon>()
+ : QIcon(":/icons/offline.png");
+ QString name = item->data(Qt::DisplayRole).toString();
+ //qDebug() << "Avatar for " << name << " = " << avatarPath;
+ QString statusText = item->data(ChatListRecentItem::DetailTextRole).toString();
+ common_.paintContact(painter, option, nameColor, avatarPath, presenceIcon, name, statusText, item->getChat().unreadCount);
+}
+
}
diff --git a/Swift/QtUI/ChatList/ChatListDelegate.h b/Swift/QtUI/ChatList/ChatListDelegate.h
index f6c6c40..a898df4 100644
--- a/Swift/QtUI/ChatList/ChatListDelegate.h
+++ b/Swift/QtUI/ChatList/ChatListDelegate.h
@@ -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.
*/
@@ -12,6 +12,7 @@
namespace Swift {
class ChatListMUCItem;
+ class ChatListRecentItem;
class ChatListDelegate : public QStyledItemDelegate {
public:
ChatListDelegate();
@@ -20,7 +21,9 @@ namespace Swift {
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
private:
void paintMUC(QPainter* painter, const QStyleOptionViewItem& option, ChatListMUCItem* item) const;
+ void paintRecent(QPainter* painter, const QStyleOptionViewItem& option, ChatListRecentItem* item) const;
QSize mucSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const;
+ QSize recentSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const;
DelegateCommons common_;
GroupItemDelegate* groupDelegate_;
diff --git a/Swift/QtUI/ChatList/ChatListGroupItem.h b/Swift/QtUI/ChatList/ChatListGroupItem.h
index cc4d4af..a1e479f 100644
--- a/Swift/QtUI/ChatList/ChatListGroupItem.h
+++ b/Swift/QtUI/ChatList/ChatListGroupItem.h
@@ -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,8 +13,8 @@
namespace Swift {
class ChatListGroupItem : public ChatListItem {
public:
- ChatListGroupItem(const QString& name, ChatListGroupItem* parent) : ChatListItem(parent), name_(name) {};
- void addItem(ChatListItem* item) {items_.push_back(item); qStableSort(items_.begin(), items_.end(), pointerItemLessThan);};
+ ChatListGroupItem(const QString& name, ChatListGroupItem* parent, bool sorted = true) : ChatListItem(parent), name_(name), sorted_(sorted) {};
+ void addItem(ChatListItem* item) {items_.push_back(item); if (sorted_) {qStableSort(items_.begin(), items_.end(), pointerItemLessThan);}};
void remove(int index) {items_.removeAt(index);};
int rowCount() {return items_.size();};
ChatListItem* item(int i) {return items_[i];};
@@ -30,5 +30,6 @@ namespace Swift {
QString name_;
QList<ChatListItem*> items_;
+ bool sorted_;
};
}
diff --git a/Swift/QtUI/ChatList/ChatListMUCItem.cpp b/Swift/QtUI/ChatList/ChatListMUCItem.cpp
index e374ed5..68f9581 100644
--- a/Swift/QtUI/ChatList/ChatListMUCItem.cpp
+++ b/Swift/QtUI/ChatList/ChatListMUCItem.cpp
@@ -13,7 +13,7 @@ ChatListMUCItem::ChatListMUCItem(const MUCBookmark& bookmark, ChatListGroupItem*
}
-const MUCBookmark& ChatListMUCItem::getBookmark() {
+const MUCBookmark& ChatListMUCItem::getBookmark() const {
return bookmark_;
}
diff --git a/Swift/QtUI/ChatList/ChatListMUCItem.h b/Swift/QtUI/ChatList/ChatListMUCItem.h
index 068f5d6..046d1d4 100644
--- a/Swift/QtUI/ChatList/ChatListMUCItem.h
+++ b/Swift/QtUI/ChatList/ChatListMUCItem.h
@@ -15,16 +15,16 @@
#include "Swift/QtUI/ChatList/ChatListItem.h"
namespace Swift {
- enum MUCItemRoles {
- DetailTextRole = Qt::UserRole/*,
- AvatarRole = Qt::UserRole + 1,
- PresenceIconRole = Qt::UserRole + 2,
- StatusShowTypeRole = Qt::UserRole + 3*/
- };
class ChatListMUCItem : public ChatListItem {
public:
+ enum MUCItemRoles {
+ DetailTextRole = Qt::UserRole/*,
+ AvatarRole = Qt::UserRole + 1,
+ PresenceIconRole = Qt::UserRole + 2,
+ StatusShowTypeRole = Qt::UserRole + 3*/
+ };
ChatListMUCItem(const MUCBookmark& bookmark, ChatListGroupItem* parent);
- const MUCBookmark& getBookmark();
+ const MUCBookmark& getBookmark() const;
QVariant data(int role) const;
private:
MUCBookmark bookmark_;
diff --git a/Swift/QtUI/ChatList/ChatListModel.cpp b/Swift/QtUI/ChatList/ChatListModel.cpp
index ba7b766..681c1c2 100644
--- a/Swift/QtUI/ChatList/ChatListModel.cpp
+++ b/Swift/QtUI/ChatList/ChatListModel.cpp
@@ -1,22 +1,25 @@
/*
- * 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.
*/
-#include "Swift/QtUI/ChatList/ChatListModel.h"
+#include <Swift/QtUI/ChatList/ChatListModel.h>
-#include "Swift/QtUI/ChatList/ChatListMUCItem.h"
+#include <Swift/QtUI/ChatList/ChatListMUCItem.h>
+#include <Swift/QtUI/ChatList/ChatListRecentItem.h>
namespace Swift {
ChatListModel::ChatListModel() {
- root_ = new ChatListGroupItem("", NULL);
+ root_ = new ChatListGroupItem("", NULL, false);
mucBookmarks_ = new ChatListGroupItem(tr("Bookmarked Rooms"), root_);
+ recents_ = new ChatListGroupItem(tr("Recent Chats"), root_, false);
+ root_->addItem(recents_);
root_->addItem(mucBookmarks_);
}
-void ChatListModel::clear() {
+void ChatListModel::clearBookmarks() {
emit layoutAboutToBeChanged();
mucBookmarks_->clear();
emit layoutChanged();
@@ -43,6 +46,15 @@ void ChatListModel::removeMUCBookmark(const Swift::MUCBookmark& bookmark) {
}
}
+void ChatListModel::setRecents(const std::list<ChatListWindow::Chat>& recents) {
+ emit layoutAboutToBeChanged();
+ recents_->clear();
+ foreach (const ChatListWindow::Chat chat, recents) {
+ recents_->addItem(new ChatListRecentItem(chat, recents_));
+ }
+ emit layoutChanged();
+}
+
int ChatListModel::columnCount(const QModelIndex& /*parent*/) const {
return 1;
}
diff --git a/Swift/QtUI/ChatList/ChatListModel.h b/Swift/QtUI/ChatList/ChatListModel.h
index adde148..8e7828c 100644
--- a/Swift/QtUI/ChatList/ChatListModel.h
+++ b/Swift/QtUI/ChatList/ChatListModel.h
@@ -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.
*/
@@ -11,9 +11,10 @@
#include <QAbstractItemModel>
#include <QList>
-#include "Swiften/MUC/MUCBookmark.h"
+#include <Swiften/MUC/MUCBookmark.h>
+#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
-#include "Swift/QtUI/ChatList/ChatListGroupItem.h"
+#include <Swift/QtUI/ChatList/ChatListGroupItem.h>
namespace Swift {
class ChatListModel : public QAbstractItemModel {
@@ -28,9 +29,11 @@ namespace Swift {
QModelIndex parent(const QModelIndex& index) const;
int rowCount(const QModelIndex& parent = QModelIndex()) const;
ChatListItem* getItemForIndex(const QModelIndex& index) const;
- void clear();
+ void clearBookmarks();
+ void setRecents(const std::list<ChatListWindow::Chat>& recents);
private:
ChatListGroupItem* mucBookmarks_;
+ ChatListGroupItem* recents_;
ChatListGroupItem* root_;
};
diff --git a/Swift/QtUI/ChatList/ChatListRecentItem.cpp b/Swift/QtUI/ChatList/ChatListRecentItem.cpp
new file mode 100644
index 0000000..6c9807f
--- /dev/null
+++ b/Swift/QtUI/ChatList/ChatListRecentItem.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/QtUI/ChatList/ChatListRecentItem.h>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+ChatListRecentItem::ChatListRecentItem(const ChatListWindow::Chat& chat, ChatListGroupItem* parent) : ChatListItem(parent), chat_(chat) {
+
+}
+
+const ChatListWindow::Chat& ChatListRecentItem::getChat() const {
+ return chat_;
+}
+
+QVariant ChatListRecentItem::data(int role) const {
+ switch (role) {
+ case Qt::DisplayRole: return P2QSTRING(chat_.chatName);
+ case DetailTextRole: return P2QSTRING(chat_.activity);
+ /*case Qt::TextColorRole: return textColor_;
+ case Qt::BackgroundColorRole: return backgroundColor_;
+ case Qt::ToolTipRole: return isContact() ? toolTipString() : QVariant();
+ case StatusTextRole: return statusText_;*/
+ case AvatarRole: return QVariant(QString(chat_.avatarPath.string().c_str()));
+ case PresenceIconRole: return getPresenceIcon();
+ default: return QVariant();
+ }
+}
+
+QIcon ChatListRecentItem::getPresenceIcon() const {
+ QString iconString;
+ switch (chat_.statusType) {
+ case StatusShow::Online: iconString = "online";break;
+ case StatusShow::Away: iconString = "away";break;
+ case StatusShow::XA: iconString = "away";break;
+ case StatusShow::FFC: iconString = "online";break;
+ case StatusShow::DND: iconString = "dnd";break;
+ case StatusShow::None: iconString = "offline";break;
+ }
+ return QIcon(":/icons/" + iconString + ".png");
+}
+
+}
diff --git a/Swift/QtUI/ChatList/ChatListRecentItem.h b/Swift/QtUI/ChatList/ChatListRecentItem.h
new file mode 100644
index 0000000..4e7bc3e
--- /dev/null
+++ b/Swift/QtUI/ChatList/ChatListRecentItem.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QList>
+#include <QIcon>
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/MUC/MUCBookmark.h>
+#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
+
+#include <Swift/QtUI/ChatList/ChatListItem.h>
+
+namespace Swift {
+ class ChatListRecentItem : public ChatListItem {
+ public:
+ enum RecentItemRoles {
+ DetailTextRole = Qt::UserRole,
+ AvatarRole = Qt::UserRole + 1,
+ PresenceIconRole = Qt::UserRole + 2/*,
+ StatusShowTypeRole = Qt::UserRole + 3*/
+ };
+ ChatListRecentItem(const ChatListWindow::Chat& chat, ChatListGroupItem* parent);
+ const ChatListWindow::Chat& getChat() const;
+ QVariant data(int role) const;
+ private:
+ QIcon getPresenceIcon() const;
+ ChatListWindow::Chat chat_;
+ };
+}
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.cpp b/Swift/QtUI/ChatList/QtChatListWindow.cpp
index b532cdb..9beb9dc 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.cpp
+++ b/Swift/QtUI/ChatList/QtChatListWindow.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.
*/
@@ -10,9 +10,11 @@
#include <QContextMenuEvent>
#include "Swift/QtUI/ChatList/ChatListMUCItem.h"
+#include "Swift/QtUI/ChatList/ChatListRecentItem.h"
#include "Swift/QtUI/QtAddBookmarkWindow.h"
#include "Swift/QtUI/QtEditBookmarkWindow.h"
#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
+#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
#include "Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h"
#include "Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h"
#include "Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h"
@@ -68,19 +70,21 @@ void QtChatListWindow::setupContextMenus() {
}
void QtChatListWindow::handleItemActivated(const QModelIndex& index) {
- if (!bookmarksEnabled_) {
- return;
- }
ChatListItem* item = model_->getItemForIndex(index);
- ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(item);
- if (mucItem) {
- boost::shared_ptr<UIEvent> event(new JoinMUCUIEvent(mucItem->getBookmark().getRoom(), mucItem->getBookmark().getNick()));
- eventStream_->send(event);
+ if (ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(item)) {
+ if (bookmarksEnabled_) {
+ onMUCBookmarkActivated(mucItem->getBookmark());
+ }
+ }
+ else if (ChatListRecentItem* recentItem = dynamic_cast<ChatListRecentItem*>(item)) {
+ if (!recentItem->getChat().isMUC || bookmarksEnabled_) {
+ onRecentActivated(recentItem->getChat());
+ }
}
}
-void QtChatListWindow::clear() {
- model_->clear();
+void QtChatListWindow::clearBookmarks() {
+ model_->clearBookmarks();
}
void QtChatListWindow::addMUCBookmark(const MUCBookmark& bookmark) {
@@ -91,6 +95,14 @@ void QtChatListWindow::removeMUCBookmark(const MUCBookmark& bookmark) {
model_->removeMUCBookmark(bookmark);
}
+void QtChatListWindow::setRecents(const std::list<ChatListWindow::Chat>& recents) {
+ model_->setRecents(recents);
+}
+
+void QtChatListWindow::setUnreadCount(int unread) {
+ emit onCountUpdated(unread);
+}
+
void QtChatListWindow::handleRemoveBookmark() {
ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(contextMenuItem_);
if (!mucItem) return;
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.h b/Swift/QtUI/ChatList/QtChatListWindow.h
index 3a3e95f..8775c3e 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.h
+++ b/Swift/QtUI/ChatList/QtChatListWindow.h
@@ -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.
*/
@@ -23,7 +23,12 @@ namespace Swift {
void addMUCBookmark(const MUCBookmark& bookmark);
void removeMUCBookmark(const MUCBookmark& bookmark);
void setBookmarksEnabled(bool enabled);
- void clear();
+ void setRecents(const std::list<ChatListWindow::Chat>& recents);
+ void setUnreadCount(int unread);
+ void clearBookmarks();
+
+ signals:
+ void onCountUpdated(int count);
private slots:
void handleItemActivated(const QModelIndex&);
void handleAddBookmark();
diff --git a/Swift/QtUI/ChatSnippet.h b/Swift/QtUI/ChatSnippet.h
index 3aa5fcc..0d864c1 100644
--- a/Swift/QtUI/ChatSnippet.h
+++ b/Swift/QtUI/ChatSnippet.h
@@ -17,16 +17,16 @@ namespace Swift {
public:
ChatSnippet(bool appendToPrevious);
virtual ~ChatSnippet();
-
+
virtual const QString& getContent() const = 0;
virtual QString getContinuationElementID() const { return ""; }
- boost::shared_ptr<ChatSnippet> getContinuationFallbackSnippet() {return continuationFallback_;}
+ boost::shared_ptr<ChatSnippet> getContinuationFallbackSnippet() const {return continuationFallback_;}
bool getAppendToPrevious() const {
return appendToPrevious_;
}
-
+
static QString escape(const QString& original) {
QString result(original);
result.replace("%message%", "&#37;message&#37;");
@@ -37,11 +37,12 @@ namespace Swift {
return result;
}
+ static QString timeToEscapedString(const QDateTime& time);
+
protected:
void setContinuationFallbackSnippet(boost::shared_ptr<ChatSnippet> continuationFallback) {
continuationFallback_ = continuationFallback;
}
- static QString timeToEscapedString(const QDateTime& time);
private:
bool appendToPrevious_;
boost::shared_ptr<ChatSnippet> continuationFallback_;
diff --git a/Swift/QtUI/EventViewer/QtEventWindow.h b/Swift/QtUI/EventViewer/QtEventWindow.h
index 03f009b..a20e5ab 100644
--- a/Swift/QtUI/EventViewer/QtEventWindow.h
+++ b/Swift/QtUI/EventViewer/QtEventWindow.h
@@ -6,7 +6,7 @@
#pragma once
-#include "boost/shared_ptr.hpp"
+#include <boost/shared_ptr.hpp>
#include <QTreeView>
diff --git a/Swift/QtUI/MUCSearch/MUCSearchRoomItem.h b/Swift/QtUI/MUCSearch/MUCSearchRoomItem.h
index 920aaae..a9eb74d 100644
--- a/Swift/QtUI/MUCSearch/MUCSearchRoomItem.h
+++ b/Swift/QtUI/MUCSearch/MUCSearchRoomItem.h
@@ -15,7 +15,7 @@ namespace Swift {
MUCSearchRoomItem(const QString& node, MUCSearchServiceItem* parent);
MUCSearchServiceItem* getParent();
QVariant data(int role);
- QString getNode() {return node_;}
+ QString getNode() const {return node_;}
private:
MUCSearchServiceItem* parent_;
QString node_;
diff --git a/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h b/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h
index 411727d..2a28922 100644
--- a/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h
+++ b/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h
@@ -24,7 +24,7 @@ namespace Swift {
default: return QVariant();
}
}
- QString getHost() {return jidString_;}
+ QString getHost() const {return jidString_;}
private:
QList<MUCSearchItem*> rooms_;
QString jidString_;
diff --git a/Swift/QtUI/QtAdHocCommandWindow.cpp b/Swift/QtUI/QtAdHocCommandWindow.cpp
new file mode 100644
index 0000000..a3bb077
--- /dev/null
+++ b/Swift/QtUI/QtAdHocCommandWindow.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/QtUI/QtAdHocCommandWindow.h>
+
+#include <boost/bind.hpp>
+#include <QBoxLayout>
+#include <Swift/QtUI/QtFormWidget.h>
+#include <Swiften/Elements/Command.h>
+
+namespace Swift {
+QtAdHocCommandWindow::QtAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command) : command_(command) {
+
+ formWidget_ = NULL;
+
+ setAttribute(Qt::WA_DeleteOnClose);
+ command->onNextStageReceived.connect(boost::bind(&QtAdHocCommandWindow::handleNextStageReceived, this, _1));
+ command->onError.connect(boost::bind(&QtAdHocCommandWindow::handleError, this, _1));
+ command->start();
+
+ QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
+ layout->setContentsMargins(0,0,0,0);
+ layout->setSpacing(2);
+ label_ = new QLabel(this);
+ layout->addWidget(label_);
+ QWidget* formContainer = new QWidget(this);
+ layout->addWidget(formContainer);
+ formLayout_ = new QBoxLayout(QBoxLayout::TopToBottom, formContainer);
+ QWidget* buttonsWidget = new QWidget(this);
+ layout->addWidget(buttonsWidget);
+
+ QBoxLayout* buttonsLayout = new QBoxLayout(QBoxLayout::LeftToRight, buttonsWidget);
+ cancelButton_ = new QPushButton(tr("Cancel"), buttonsWidget);
+ buttonsLayout->addWidget(cancelButton_);
+ connect(cancelButton_, SIGNAL(clicked()), this, SLOT(handleCancelClicked()));
+ backButton_ = new QPushButton(tr("Back"), buttonsWidget);
+ buttonsLayout->addWidget(backButton_);
+ connect(backButton_, SIGNAL(clicked()), this, SLOT(handlePrevClicked()));
+ nextButton_ = new QPushButton(tr("Next"), buttonsWidget);
+ buttonsLayout->addWidget(nextButton_);
+ connect(nextButton_, SIGNAL(clicked()), this, SLOT(handleNextClicked()));
+ completeButton_ = new QPushButton(tr("Complete"), buttonsWidget);
+ buttonsLayout->addWidget(completeButton_);
+ connect(completeButton_, SIGNAL(clicked()), this, SLOT(handleCompleteClicked()));
+ nextButton_->setEnabled(false);
+ backButton_->setEnabled(false);
+ completeButton_->setEnabled(false);
+ actions_[Command::Next] = nextButton_;
+ actions_[Command::Prev] = backButton_;
+ actions_[Command::Complete] = completeButton_;
+ actions_[Command::Cancel] = cancelButton_;
+ show();
+}
+
+QtAdHocCommandWindow::~QtAdHocCommandWindow() {
+
+}
+
+void QtAdHocCommandWindow::handleCancelClicked() {
+ command_->cancel();
+}
+
+void QtAdHocCommandWindow::handlePrevClicked() {
+ command_->goBack();
+}
+
+void QtAdHocCommandWindow::handleNextClicked() {
+ command_->goNext(formWidget_ ? formWidget_->getCompletedForm() : Form::ref());
+}
+
+void QtAdHocCommandWindow::handleCompleteClicked() {
+ command_->complete(formWidget_ ? formWidget_->getCompletedForm() : Form::ref());
+}
+
+void QtAdHocCommandWindow::handleNextStageReceived(Command::ref command) {
+ if (command->getForm()) {
+ setForm(command->getForm());
+ } else {
+ setNoForm();
+ }
+ QString notes;
+ foreach (Command::Note note, command->getNotes()) {
+ if (!notes.isEmpty()) {
+ notes += "\n";
+ QString qNote(note.note.c_str());
+ switch (note.type) {
+ case Command::Note::Error: notes += tr("Error: %1").arg(qNote); break;
+ case Command::Note::Warn: notes += tr("Warning: %1").arg(qNote); break;
+ case Command::Note::Info: notes += qNote; break;
+ }
+ }
+ }
+ label_->setText(notes);
+ setAvailableActions(command);
+}
+
+void QtAdHocCommandWindow::handleError(ErrorPayload::ref /*error*/) {
+ nextButton_->setEnabled(false);
+ backButton_->setEnabled(false);
+ completeButton_->setEnabled(false);
+ label_->setText(tr("Error executing command"));
+}
+
+void QtAdHocCommandWindow::setForm(Form::ref form) {
+ delete formWidget_;
+ formWidget_ = new QtFormWidget(form, this);
+ formLayout_->addWidget(formWidget_);
+}
+
+void QtAdHocCommandWindow::setNoForm() {
+ delete formWidget_;
+}
+
+typedef std::pair<Command::Action, QPushButton*> ActionButton;
+
+void QtAdHocCommandWindow::setAvailableActions(Command::ref /*commandResult*/) {
+ foreach (ActionButton pair, actions_) {
+ OutgoingAdHocCommandSession::ActionState state = command_->getActionState(pair.first);
+ if (state & OutgoingAdHocCommandSession::Present) {
+ pair.second->show();
+ }
+ else {
+ pair.second->hide();
+ }
+ if (state & OutgoingAdHocCommandSession::Enabled) {
+ pair.second->setEnabled(true);
+ }
+ else {
+ pair.second->setEnabled(false);
+ }
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtAdHocCommandWindow.h b/Swift/QtUI/QtAdHocCommandWindow.h
new file mode 100644
index 0000000..adeb3e6
--- /dev/null
+++ b/Swift/QtUI/QtAdHocCommandWindow.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QWidget>
+#include <QPushButton>
+#include <QLabel>
+
+#include <Swift/Controllers/UIInterfaces/AdHocCommandWindow.h>
+#include <Swiften/AdHoc/OutgoingAdHocCommandSession.h>
+
+class QBoxLayout;
+
+namespace Swift {
+ class QtFormWidget;
+ class QtAdHocCommandWindow : public QWidget, public AdHocCommandWindow {
+ Q_OBJECT
+ public:
+ QtAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command);
+ virtual ~QtAdHocCommandWindow();
+ private:
+ void handleNextStageReceived(Command::ref command);
+ void handleError(ErrorPayload::ref error);
+ void setForm(Form::ref);
+ void setNoForm();
+ void setAvailableActions(Command::ref commandResult);
+ private slots:
+ void handleCancelClicked();
+ void handlePrevClicked();
+ void handleNextClicked();
+ void handleCompleteClicked();
+ private:
+ boost::shared_ptr<OutgoingAdHocCommandSession> command_;
+ QtFormWidget* formWidget_;
+ QBoxLayout* formLayout_;
+ Form::ref form_;
+ QLabel* label_;
+ QPushButton* backButton_;
+ QPushButton* nextButton_;
+ QPushButton* completeButton_;
+ QPushButton* cancelButton_;
+ std::map<Command::Action, QPushButton*> actions_;
+ };
+}
diff --git a/Swift/QtUI/QtAvatarWidget.cpp b/Swift/QtUI/QtAvatarWidget.cpp
index 3e3aa69..1efb787 100644
--- a/Swift/QtUI/QtAvatarWidget.cpp
+++ b/Swift/QtUI/QtAvatarWidget.cpp
@@ -47,8 +47,8 @@ void QtAvatarWidget::setAvatar(const ByteArray& data, const std::string& type) {
this->type = type;
QImage image;
- if (!data.isEmpty()) {
- image.loadFromData(reinterpret_cast<const uchar*>(data.getData()), data.getSize());
+ if (!data.empty()) {
+ image.loadFromData(reinterpret_cast<const uchar*>(vecptr(data)), data.size());
}
if (image.isNull()) {
@@ -81,10 +81,10 @@ void QtAvatarWidget::mousePressEvent(QMouseEvent* event) {
QString fileName = QFileDialog::getOpenFileName(this, tr("Select picture"), "", tr("Image Files (*.png *.jpg *.gif)"));
if (!fileName.isEmpty()) {
ByteArray data;
- data.readFromFile(Q2PSTRING(fileName));
+ readByteArrayFromFile(data, Q2PSTRING(fileName));
QBuffer buffer;
- buffer.setData(reinterpret_cast<const char*>(data.getData()), data.getSize());
+ buffer.setData(reinterpret_cast<const char*>(vecptr(data)), data.size());
buffer.open(QIODevice::ReadOnly);
QString type = QImageReader::imageFormat(&buffer).toLower();
if (!type.isEmpty()) {
diff --git a/Swift/QtUI/QtBookmarkDetailWindow.ui b/Swift/QtUI/QtBookmarkDetailWindow.ui
index a77ac76..4a37b2f 100644
--- a/Swift/QtUI/QtBookmarkDetailWindow.ui
+++ b/Swift/QtUI/QtBookmarkDetailWindow.ui
@@ -90,7 +90,7 @@
<item row="4" column="1">
<widget class="QCheckBox" name="autojoin_">
<property name="text">
- <string>Join automatically</string>
+ <string>Enter automatically</string>
</property>
<property name="checked">
<bool>true</bool>
diff --git a/Swift/QtUI/QtChatTabs.cpp b/Swift/QtUI/QtChatTabs.cpp
index 25c7ca2..249080b 100644
--- a/Swift/QtUI/QtChatTabs.cpp
+++ b/Swift/QtUI/QtChatTabs.cpp
@@ -7,6 +7,10 @@
#include "QtChatTabs.h"
#include <algorithm>
+#include <vector>
+
+#include <Swift/Controllers/ChatMessageSummarizer.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
#include <QCloseEvent>
#include <QDesktopWidget>
@@ -236,16 +240,18 @@ void QtChatTabs::handleTabTitleUpdated(QWidget* widget) {
default : tabTextColor = QColor();
}
tabs_->tabBar()->setTabTextColor(index, tabTextColor);
- int unread = 0;
+
+ std::vector<std::pair<std::string, int> > unreads;
for (int i = 0; i < tabs_->count(); i++) {
QtTabbable* tab = qobject_cast<QtTabbable*>(tabs_->widget(i));
if (tab) {
- unread += tab->getCount();
+ unreads.push_back(std::pair<std::string, int>(Q2PSTRING(tab->windowTitle()), tab->getCount()));
}
}
- QtTabbable* current = qobject_cast<QtTabbable*>(tabs_->currentWidget());
- setWindowTitle(unread > 0 ? QString("(%1) %2").arg(unread).arg(current->windowTitle()) : current->windowTitle());
+ std::string current(Q2PSTRING(qobject_cast<QtTabbable*>(tabs_->currentWidget())->windowTitle()));
+ ChatMessageSummarizer summary;
+ setWindowTitle(summary.getSummary(current, unreads).c_str());
}
void QtChatTabs::flash() {
diff --git a/Swift/QtUI/QtChatTheme.cpp b/Swift/QtUI/QtChatTheme.cpp
index afcf665..1d7a970 100644
--- a/Swift/QtUI/QtChatTheme.cpp
+++ b/Swift/QtUI/QtChatTheme.cpp
@@ -60,7 +60,7 @@ QtChatTheme::QtChatTheme(const QString& themePath) : qrc_(themePath.isEmpty()),
}
-QString QtChatTheme::getBase() {
+QString QtChatTheme::getBase() const {
return qrc_ ? "qrc" + themePath_ : "file://" + themePath_;
}
diff --git a/Swift/QtUI/QtChatTheme.h b/Swift/QtUI/QtChatTheme.h
index 199c66d..c6b02a0 100644
--- a/Swift/QtUI/QtChatTheme.h
+++ b/Swift/QtUI/QtChatTheme.h
@@ -13,23 +13,23 @@ namespace Swift {
class QtChatTheme {
public:
QtChatTheme(const QString& themePath);
- QString getHeader() {return fileContents_[Header];};
- QString getFooter() {return fileContents_[Footer];};
- QString getContent() {return fileContents_[Content];};
- QString getStatus() {return fileContents_[Status];};
- QString getTopic() {return fileContents_[Topic];};
- QString getFileTransferRequest() {return fileContents_[FileTransferRequest];};
- QString getIncomingContent() {return fileContents_[IncomingContent];};
- QString getIncomingNextContent() {return fileContents_[IncomingNextContent];};
- QString getIncomingContext() {return fileContents_[IncomingContext];};
- QString getIncomingNextContext() {return fileContents_[IncomingNextContext];};
- QString getOutgoingContent() {return fileContents_[OutgoingContent];};
- QString getOutgoingNextContent() {return fileContents_[OutgoingNextContent];};
- QString getOutgoingContext() {return fileContents_[OutgoingContext];};
- QString getOutgoingNextContext() {return fileContents_[OutgoingNextContext];};
- QString getTemplate() {return fileContents_[Template];}
- QString getMainCSS() {return fileContents_[MainCSS];}
- QString getBase();
+ QString getHeader() const {return fileContents_[Header];};
+ QString getFooter() const {return fileContents_[Footer];};
+ QString getContent() const {return fileContents_[Content];};
+ QString getStatus() const {return fileContents_[Status];};
+ QString getTopic() const {return fileContents_[Topic];};
+ QString getFileTransferRequest() const {return fileContents_[FileTransferRequest];};
+ QString getIncomingContent() const {return fileContents_[IncomingContent];};
+ QString getIncomingNextContent() const {return fileContents_[IncomingNextContent];};
+ QString getIncomingContext() const {return fileContents_[IncomingContext];};
+ QString getIncomingNextContext() const {return fileContents_[IncomingNextContext];};
+ QString getOutgoingContent() const {return fileContents_[OutgoingContent];};
+ QString getOutgoingNextContent() const {return fileContents_[OutgoingNextContent];};
+ QString getOutgoingContext() const {return fileContents_[OutgoingContext];};
+ QString getOutgoingNextContext() const {return fileContents_[OutgoingNextContext];};
+ QString getTemplate() const {return fileContents_[Template];}
+ QString getMainCSS() const {return fileContents_[MainCSS];}
+ QString getBase() const;
private:
enum files {Header = 0, Footer, Content, Status, Topic, FileTransferRequest, IncomingContent, IncomingNextContent, IncomingContext, IncomingNextContext, OutgoingContent, OutgoingNextContent, OutgoingContext, OutgoingNextContext, Template, MainCSS, TemplateDefault, EndMarker};
diff --git a/Swift/QtUI/QtChatView.cpp b/Swift/QtUI/QtChatView.cpp
index 521b072..4c6a729 100644
--- a/Swift/QtUI/QtChatView.cpp
+++ b/Swift/QtUI/QtChatView.cpp
@@ -24,7 +24,7 @@
namespace Swift {
-QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent) : QWidget(parent) {
+QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent) : QWidget(parent), fontSizeSteps_(0) {
theme_ = theme;
QVBoxLayout* mainLayout = new QVBoxLayout(this);
@@ -35,6 +35,8 @@ QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent) : QWidget(parent) {
connect(webView_, SIGNAL(loadFinished(bool)), SLOT(handleViewLoadFinished(bool)));
connect(webView_, SIGNAL(gotFocus()), SIGNAL(gotFocus()));
connect(webView_, SIGNAL(clearRequested()), SLOT(handleClearRequested()));
+ connect(webView_, SIGNAL(fontGrowRequested()), SLOT(increaseFontSize()));
+ connect(webView_, SIGNAL(fontShrinkRequested()), SLOT(decreaseFontSize()));
#ifdef Q_WS_X11
/* To give a border on Linux, where it looks bad without */
QStackedWidget* stack = new QStackedWidget(this);
@@ -77,13 +79,14 @@ void QtChatView::addMessage(boost::shared_ptr<ChatSnippet> snippet) {
if (viewReady_) {
addToDOM(snippet);
} else {
- queuedSnippets_.append(snippet);
+ /* If this asserts, the previous queuing code was necessary and should be reinstated */
+ assert(false);
}
}
QWebElement QtChatView::snippetToDOM(boost::shared_ptr<ChatSnippet> snippet) {
QWebElement newElement = newInsertPoint_.clone();
- newElement.setInnerXml(snippet->getContent()); /* FIXME: Outer, surely? */
+ newElement.setInnerXml(snippet->getContent());
Q_ASSERT(!newElement.isNull());
return newElement;
}
@@ -103,12 +106,31 @@ void QtChatView::addToDOM(boost::shared_ptr<ChatSnippet> snippet) {
newInsertPoint_.prependOutside(newElement);
}
lastElement_ = newElement;
- //qApp->processEvents();
+ if (fontSizeSteps_ != 0) {
+ double size = 1.0 + 0.2 * fontSizeSteps_;
+ QString sizeString(QString().setNum(size, 'g', 3) + "em");
+ const QWebElementCollection spans = lastElement_.findAll("span");
+ foreach (QWebElement span, spans) {
+ span.setStyleProperty("font-size", sizeString);
+ }
+ }
+}
+
+void QtChatView::addLastSeenLine() {
+ if (lineSeparator_.isNull()) {
+ lineSeparator_ = newInsertPoint_.clone();
+ lineSeparator_.setInnerXml(QString("<hr/>"));
+ newInsertPoint_.prependOutside(lineSeparator_);
+ }
+ else {
+ QWebElement lineSeparatorC = lineSeparator_.clone();
+ lineSeparatorC.removeFromDocument();
+ }
+ newInsertPoint_.prependOutside(lineSeparator_);
}
void QtChatView::replaceLastMessage(const QString& newMessage) {
assert(viewReady_);
- /* FIXME: must be queued? */
rememberScrolledToBottom();
assert(!lastElement_.isNull());
QWebElement replace = lastElement_.findFirst("span.swift_message");
@@ -125,6 +147,25 @@ void QtChatView::replaceLastMessage(const QString& newMessage, const QString& no
replace.setInnerXml(ChatSnippet::escape(note));
}
+QString QtChatView::getLastSentMessage() {
+ return lastElement_.toPlainText();
+}
+
+void QtChatView::replaceMessage(const QString& newMessage, const QString& id, const QDateTime& editTime) {
+ rememberScrolledToBottom();
+ QWebElement message = document_.findFirst("#" + id);
+ if (!message.isNull()) {
+ QWebElement replaceContent = message.findFirst("span.swift_message");
+ assert(!replaceContent.isNull());
+ QString old = replaceContent.toOuterXml();
+ replaceContent.setInnerXml(ChatSnippet::escape(newMessage));
+ QWebElement replaceTime = message.findFirst("span.swift_time");
+ assert(!replaceTime.isNull());
+ old = replaceTime.toOuterXml();
+ replaceTime.setInnerXml(ChatSnippet::escape(tr("%1 edited").arg(ChatSnippet::timeToEscapedString(editTime))));
+ }
+}
+
void QtChatView::copySelectionToClipboard() {
if (!webPage_->selectedText().isEmpty()) {
webPage_->triggerAction(QWebPage::Copy);
@@ -160,17 +201,35 @@ void QtChatView::handleLinkClicked(const QUrl& url) {
QDesktopServices::openUrl(url);
}
-void QtChatView::addQueuedSnippets() {
- for (int i = 0; i < queuedSnippets_.count(); i++) {
- addToDOM(queuedSnippets_[i]);
- }
- queuedSnippets_.clear();
-}
-
void QtChatView::handleViewLoadFinished(bool ok) {
Q_ASSERT(ok);
viewReady_ = true;
- addQueuedSnippets();
+}
+
+void QtChatView::increaseFontSize(int numSteps) {
+ //qDebug() << "Increasing";
+ fontSizeSteps_ += numSteps;
+ emit fontResized(fontSizeSteps_);
+}
+
+void QtChatView::decreaseFontSize() {
+ fontSizeSteps_--;
+ if (fontSizeSteps_ < 0) {
+ fontSizeSteps_ = 0;
+ }
+ emit fontResized(fontSizeSteps_);
+}
+
+void QtChatView::resizeFont(int fontSizeSteps) {
+ fontSizeSteps_ = fontSizeSteps;
+ double size = 1.0 + 0.2 * fontSizeSteps_;
+ QString sizeString(QString().setNum(size, 'g', 3) + "em");
+ //qDebug() << "Setting to " << sizeString;
+ const QWebElementCollection spans = document_.findAll("span");
+ foreach (QWebElement span, spans) {
+ span.setStyleProperty("font-size", sizeString);
+ }
+ webView_->setFontSizeIsMinimal(size == 1.0);
}
void QtChatView::resetView() {
diff --git a/Swift/QtUI/QtChatView.h b/Swift/QtUI/QtChatView.h
index 58b33df..eda7e42 100644
--- a/Swift/QtUI/QtChatView.h
+++ b/Swift/QtUI/QtChatView.h
@@ -26,15 +26,18 @@ namespace Swift {
Q_OBJECT
public:
QtChatView(QtChatTheme* theme, QWidget* parent);
-
void addMessage(boost::shared_ptr<ChatSnippet> snippet);
+ void addLastSeenLine();
void replaceLastMessage(const QString& newMessage);
void replaceLastMessage(const QString& newMessage, const QString& note);
+ void replaceMessage(const QString& newMessage, const QString& id, const QDateTime& time);
void rememberScrolledToBottom();
void setAckXML(const QString& id, const QString& xml);
+ QString getLastSentMessage();
signals:
void gotFocus();
+ void fontResized(int);
public slots:
void copySelectionToClipboard();
@@ -42,6 +45,9 @@ namespace Swift {
void handleLinkClicked(const QUrl&);
void handleKeyPressEvent(QKeyEvent* event);
void resetView();
+ void increaseFontSize(int numSteps = 1);
+ void decreaseFontSize();
+ void resizeFont(int fontSizeSteps);
private slots:
void handleViewLoadFinished(bool);
@@ -51,7 +57,6 @@ namespace Swift {
private:
void headerEncode();
void messageEncode();
- void addQueuedSnippets();
void addToDOM(boost::shared_ptr<ChatSnippet> snippet);
QWebElement snippetToDOM(boost::shared_ptr<ChatSnippet> snippet);
@@ -59,10 +64,10 @@ namespace Swift {
bool isAtBottom_;
QtWebView* webView_;
QWebPage* webPage_;
- QList<boost::shared_ptr<ChatSnippet> > queuedSnippets_;
-
+ int fontSizeSteps_;
QtChatTheme* theme_;
QWebElement newInsertPoint_;
+ QWebElement lineSeparator_;
QWebElement lastElement_;
QWebElement document_;
};
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) {
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index 910019b..bc1045d 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -1,21 +1,25 @@
/*
- * 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.
*/
-#ifndef SWIFT_QtChatWindow_H
-#define SWIFT_QtChatWindow_H
+#pragma once
#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
#include "QtTabbable.h"
+#include "SwifTools/LastLineTracker.h"
+
#include "Swiften/Base/IDGenerator.h"
class QTextEdit;
class QLineEdit;
class QComboBox;
+class QLabel;
+class QSplitter;
+class QPushButton;
namespace Swift {
class QtChatView;
@@ -35,6 +39,7 @@ namespace Swift {
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 show();
void activate();
void setUnreadMessageCount(int count);
@@ -54,9 +59,19 @@ namespace Swift {
void replaceLastMessage(const std::string& message);
void setAckState(const std::string& id, AckState state);
void flash();
+ QByteArray getSplitterState();
+
+ public slots:
+ void handleChangeSplitterState(QByteArray state);
+ void handleFontResized(int fontSizeSteps);
+ void setAlert(const std::string& alertText, const std::string& buttonText = "");
+ void cancelAlert();
+ void setCorrectionEnabled(Tristate enabled);
signals:
void geometryChanged();
+ void splitterMoved();
+ void fontResized(int);
protected slots:
void qAppFocusChanged(QWidget* old, QWidget* now);
@@ -71,22 +86,33 @@ namespace Swift {
void returnPressed();
void handleInputChanged();
void handleKeyPressEvent(QKeyEvent* event);
+ void handleSplitterMoved(int pos, int index);
+ void handleAlertButtonClicked();
private:
void updateTitleWithUnreadCount();
void tabComplete();
+ void beginCorrection();
+ void cancelCorrection();
std::string addMessage(const std::string &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);
int unreadCount_;
bool contactIsTyping_;
+ LastLineTracker lastLineTracker_;
QString contact_;
+ QString lastSentMessage_;
QtChatView* messageLog_;
QtChatTheme* theme_;
QtTextEdit* input_;
QComboBox* labelsWidget_;
QtTreeWidget* treeWidget_;
+ QLabel* correctingLabel_;
+ QLabel* alertLabel_;
+ QWidget* alertWidget_;
+ QPushButton* alertButton_;
TabComplete* completer_;
std::vector<SecurityLabelsCatalog::Item> availableLabels_;
+ bool isCorrection_;
bool previousMessageWasSelf_;
bool previousMessageWasSystem_;
bool previousMessageWasPresence_;
@@ -95,7 +121,8 @@ namespace Swift {
UIEventStream* eventStream_;
bool inputEnabled_;
IDGenerator id_;
+ QSplitter *logRosterSplitter_;
+ Tristate correctionEnabled_;
+ QString alertStyleSheet_;
};
}
-
-#endif
diff --git a/Swift/QtUI/QtChatWindowFactory.cpp b/Swift/QtUI/QtChatWindowFactory.cpp
index d146474..4943c0e 100644
--- a/Swift/QtUI/QtChatWindowFactory.cpp
+++ b/Swift/QtUI/QtChatWindowFactory.cpp
@@ -16,6 +16,10 @@
namespace Swift {
+
+static const QString SPLITTER_STATE = "mucSplitterState";
+static const QString CHAT_TABS_GEOMETRY = "chatTabsGeometry";
+
QtChatWindowFactory::QtChatWindowFactory(QSplitter* splitter, QtSettingsProvider* settings, QtChatTabs* tabs, const QString& themePath) : themePath_(themePath) {
settings_ = settings;
tabs_ = tabs;
@@ -23,7 +27,7 @@ QtChatWindowFactory::QtChatWindowFactory(QSplitter* splitter, QtSettingsProvider
if (splitter) {
splitter->addWidget(tabs_);
} else if (tabs_) {
- QVariant chatTabsGeometryVariant = settings_->getQSettings()->value("chatTabsGeometry");
+ QVariant chatTabsGeometryVariant = settings_->getQSettings()->value(CHAT_TABS_GEOMETRY);
if (chatTabsGeometryVariant.isValid()) {
tabs_->restoreGeometry(chatTabsGeometryVariant.toByteArray());
}
@@ -43,11 +47,20 @@ ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact,UIEventStre
theme_ = new QtChatTheme(""); /* Use the inbuilt theme */
}
}
+
QtChatWindow *chatWindow = new QtChatWindow(P2QSTRING(contact.toString()), theme_, eventStream);
+ connect(chatWindow, SIGNAL(splitterMoved()), this, SLOT(handleSplitterMoved()));
+ connect(this, SIGNAL(changeSplitterState(QByteArray)), chatWindow, SLOT(handleChangeSplitterState(QByteArray)));
+
+ QVariant splitterState = settings_->getQSettings()->value(SPLITTER_STATE);
+ if(splitterState.isValid()) {
+ chatWindow->handleChangeSplitterState(splitterState.toByteArray());
+ }
+
if (tabs_) {
tabs_->addTab(chatWindow);
} else {
- QVariant chatGeometryVariant = settings_->getQSettings()->value("chatTabsGeometry");
+ QVariant chatGeometryVariant = settings_->getQSettings()->value(CHAT_TABS_GEOMETRY);
if (chatGeometryVariant.isValid()) {
chatWindow->restoreGeometry(chatGeometryVariant.toByteArray());
}
@@ -57,7 +70,13 @@ ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact,UIEventStre
}
void QtChatWindowFactory::handleWindowGeometryChanged() {
- settings_->getQSettings()->setValue("chatTabsGeometry", qobject_cast<QWidget*>(sender())->saveGeometry());
+ settings_->getQSettings()->setValue(CHAT_TABS_GEOMETRY, qobject_cast<QWidget*>(sender())->saveGeometry());
+}
+
+void QtChatWindowFactory::handleSplitterMoved() {
+ QByteArray splitterState = qobject_cast<QtChatWindow*>(sender())->getSplitterState();
+ settings_->getQSettings()->setValue(SPLITTER_STATE, QVariant(splitterState));
+ emit changeSplitterState(splitterState);
}
}
diff --git a/Swift/QtUI/QtChatWindowFactory.h b/Swift/QtUI/QtChatWindowFactory.h
index 0d47854..f3e8956 100644
--- a/Swift/QtUI/QtChatWindowFactory.h
+++ b/Swift/QtUI/QtChatWindowFactory.h
@@ -22,8 +22,11 @@ namespace Swift {
QtChatWindowFactory(QSplitter* splitter, QtSettingsProvider* settings, QtChatTabs* tabs, const QString& themePath);
~QtChatWindowFactory();
ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream);
+ signals:
+ void changeSplitterState(QByteArray);
private slots:
void handleWindowGeometryChanged();
+ void handleSplitterMoved();
private:
QString themePath_;
QtSettingsProvider* settings_;
diff --git a/Swift/QtUI/QtContactEditWindow.cpp b/Swift/QtUI/QtContactEditWindow.cpp
index 4be2939..9b24b23 100644
--- a/Swift/QtUI/QtContactEditWindow.cpp
+++ b/Swift/QtUI/QtContactEditWindow.cpp
@@ -42,6 +42,7 @@ QtContactEditWindow::QtContactEditWindow() : contactEditWidget_(NULL) {
connect(removeButton, SIGNAL(clicked()), this, SLOT(handleRemoveContact()));
buttonLayout->addWidget(removeButton);
QPushButton* okButton = new QPushButton(tr("OK"), this);
+ okButton->setDefault( true );
connect(okButton, SIGNAL(clicked()), this, SLOT(handleUpdateContact()));
buttonLayout->addStretch();
buttonLayout->addWidget(okButton);
diff --git a/Swift/QtUI/QtDBUSURIHandler.cpp b/Swift/QtUI/QtDBUSURIHandler.cpp
new file mode 100644
index 0000000..9b69ca6
--- /dev/null
+++ b/Swift/QtUI/QtDBUSURIHandler.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "QtDBUSURIHandler.h"
+
+#include <QDBusAbstractAdaptor>
+#include <QDBusConnection>
+
+#include "QtSwiftUtil.h"
+
+using namespace Swift;
+
+namespace {
+ class DBUSAdaptor: public QDBusAbstractAdaptor {
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "im.swift.Swift.URIHandler");
+ public:
+ DBUSAdaptor(QtDBUSURIHandler* uriHandler) : QDBusAbstractAdaptor(uriHandler), uriHandler(uriHandler) {
+ }
+
+ public slots:
+ void openURI(const QString& uri) {
+ uriHandler->onURI(Q2PSTRING(uri));
+ }
+
+ private:
+ QtDBUSURIHandler* uriHandler;
+ };
+}
+
+QtDBUSURIHandler::QtDBUSURIHandler() {
+ new DBUSAdaptor(this);
+ QDBusConnection connection = QDBusConnection::sessionBus();
+ connection.registerService("im.swift.Swift.URIHandler");
+ connection.registerObject("/", this);
+}
+
+#include "QtDBUSURIHandler.moc"
diff --git a/Swift/QtUI/QtDBUSURIHandler.h b/Swift/QtUI/QtDBUSURIHandler.h
new file mode 100644
index 0000000..be1872e
--- /dev/null
+++ b/Swift/QtUI/QtDBUSURIHandler.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QObject>
+#include <SwifTools/URIHandler/URIHandler.h>
+
+namespace Swift {
+ class QtDBUSURIHandler : public QObject, public URIHandler {
+ public:
+ QtDBUSURIHandler();
+ };
+}
diff --git a/Swift/QtUI/QtFormWidget.cpp b/Swift/QtUI/QtFormWidget.cpp
new file mode 100644
index 0000000..050ff27
--- /dev/null
+++ b/Swift/QtUI/QtFormWidget.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/QtUI/QtFormWidget.h>
+
+#include <QGridLayout>
+#include <QLabel>
+#include <QListWidget>
+#include <QLineEdit>
+#include <QTextEdit>
+#include <QCheckBox>
+#include <QScrollArea>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+#include <Swiften/Base/foreach.h>
+
+namespace Swift {
+
+QtFormWidget::QtFormWidget(Form::ref form, QWidget* parent) : QWidget(parent), form_(form) {
+ QGridLayout* thisLayout = new QGridLayout(this);
+ int row = 0;
+ if (!form->getTitle().empty()) {
+ QLabel* instructions = new QLabel(("<b>" + form->getTitle() + "</b>").c_str(), this);
+ thisLayout->addWidget(instructions, row++, 0, 1, 2);
+ }
+ if (!form->getInstructions().empty()) {
+ QLabel* instructions = new QLabel(form->getInstructions().c_str(), this);
+ thisLayout->addWidget(instructions, row++, 0, 1, 2);
+ }
+ QScrollArea* scrollArea = new QScrollArea(this);
+ thisLayout->addWidget(scrollArea);
+ QWidget* scroll = new QWidget(this);
+ QGridLayout* layout = new QGridLayout(scroll);
+ foreach (boost::shared_ptr<FormField> field, form->getFields()) {
+ QWidget* widget = createWidget(field);
+ if (widget) {
+ layout->addWidget(new QLabel(field->getLabel().c_str(), this), row, 0);
+ layout->addWidget(widget, row++, 1);
+ }
+ }
+ scrollArea->setWidget(scroll);
+ scrollArea->setWidgetResizable(true);
+}
+
+QtFormWidget::~QtFormWidget() {
+
+}
+
+QListWidget* QtFormWidget::createList(FormField::ref field) {
+ QListWidget* listWidget = new QListWidget(this);
+ listWidget->setSortingEnabled(false);
+ listWidget->setSelectionMode(boost::dynamic_pointer_cast<ListMultiFormField>(field) ? QAbstractItemView::MultiSelection : QAbstractItemView::SingleSelection);
+ foreach (FormField::Option option, field->getOptions()) {
+ listWidget->addItem(option.label.c_str());
+ }
+ boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field);
+ boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field);
+ for (int i = 0; i < listWidget->count(); i++) {
+ QListWidgetItem* item = listWidget->item(i);
+ bool selected = false;
+ if (listSingleField) {
+ selected = (item->text() == QString(listSingleField->getValue().c_str()));
+ }
+ else if (listMultiField) {
+ std::string text = Q2PSTRING(item->text());
+ selected = (std::find(listMultiField->getValue().begin(), listMultiField->getValue().end(), text) != listMultiField->getValue().end());
+ }
+ item->setSelected(selected);
+ }
+ return listWidget;
+}
+
+QWidget* QtFormWidget::createWidget(FormField::ref field) {
+ QWidget* widget = NULL;
+ boost::shared_ptr<BooleanFormField> booleanField = boost::dynamic_pointer_cast<BooleanFormField>(field);
+ if (booleanField) {
+ QCheckBox* checkWidget = new QCheckBox(this);
+ checkWidget->setCheckState(booleanField->getValue() ? Qt::Checked : Qt::Unchecked);
+ widget = checkWidget;
+ }
+ boost::shared_ptr<FixedFormField> fixedField = boost::dynamic_pointer_cast<FixedFormField>(field);
+ if (fixedField) {
+ QString value = fixedField->getValue().c_str();
+ widget = new QLabel(value, this);
+ }
+ boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field);
+ if (listSingleField) {
+ widget = createList(field);
+ }
+ boost::shared_ptr<TextMultiFormField> textMultiField = boost::dynamic_pointer_cast<TextMultiFormField>(field);
+ if (textMultiField) {
+ QString value = textMultiField->getValue().c_str();
+ widget = new QTextEdit(value, this);
+ }
+ boost::shared_ptr<TextPrivateFormField> textPrivateField = boost::dynamic_pointer_cast<TextPrivateFormField>(field);
+ if (textPrivateField) {
+ QString value = textPrivateField->getValue().c_str();
+ QLineEdit* lineWidget = new QLineEdit(value, this);
+ lineWidget->setEchoMode(QLineEdit::Password);
+ widget = lineWidget;
+ }
+ boost::shared_ptr<TextSingleFormField> textSingleField = boost::dynamic_pointer_cast<TextSingleFormField>(field);
+ if (textSingleField) {
+ QString value = textSingleField->getValue().c_str();
+ widget = new QLineEdit(value, this);
+ }
+ boost::shared_ptr<JIDSingleFormField> jidSingleField = boost::dynamic_pointer_cast<JIDSingleFormField>(field);
+ if (jidSingleField) {
+ QString value = jidSingleField->getValue().toString().c_str();
+ widget = new QLineEdit(value, this);
+ }
+ boost::shared_ptr<JIDMultiFormField> jidMultiField = boost::dynamic_pointer_cast<JIDMultiFormField>(field);
+ if (jidMultiField) {
+ QString text;
+ bool prev = false;
+ foreach (JID line, jidMultiField->getValue()) {
+ if (prev) {
+ text += "\n";
+ }
+ prev = true;
+ text += line.toString().c_str();
+ }
+ widget = new QTextEdit(text, this);
+ }
+ boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field);
+ if (listMultiField) {
+ widget = createList(field);
+ }
+ boost::shared_ptr<HiddenFormField> hiddenField = boost::dynamic_pointer_cast<HiddenFormField>(field);
+ if (hiddenField) {
+ }
+ fields_[field->getName()] = widget;
+ return widget;
+}
+
+Form::ref QtFormWidget::getCompletedForm() {
+ Form::ref result(new Form(Form::SubmitType));
+ foreach (boost::shared_ptr<FormField> field, form_->getFields()) {
+ boost::shared_ptr<FormField> resultField;
+ boost::shared_ptr<BooleanFormField> booleanField = boost::dynamic_pointer_cast<BooleanFormField>(field);
+ if (booleanField) {
+ resultField = FormField::ref(BooleanFormField::create(qobject_cast<QCheckBox*>(fields_[field->getName()])->checkState() == Qt::Checked));
+ }
+ boost::shared_ptr<FixedFormField> fixedField = boost::dynamic_pointer_cast<FixedFormField>(field);
+ if (fixedField) {
+ resultField = FormField::ref(FixedFormField::create(fixedField->getValue()));
+ }
+ boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field);
+ if (listSingleField) {
+ QListWidget* listWidget = qobject_cast<QListWidget*>(fields_[field->getName()]);
+ if (listWidget->selectedItems().size() > 0) {
+ int i = listWidget->row(listWidget->selectedItems()[0]);
+ resultField = FormField::ref(ListSingleFormField::create(field->getOptions()[i].value));
+ }
+ else {
+ resultField = FormField::ref(ListSingleFormField::create());
+ }
+ }
+ boost::shared_ptr<TextMultiFormField> textMultiField = boost::dynamic_pointer_cast<TextMultiFormField>(field);
+ if (textMultiField) {
+ QTextEdit* widget = qobject_cast<QTextEdit*>(fields_[field->getName()]);
+ QString string = widget->toPlainText();
+ if (string.isEmpty()) {
+ resultField = FormField::ref(TextMultiFormField::create());
+ }
+ else {
+ resultField = FormField::ref(TextMultiFormField::create(Q2PSTRING(string)));
+ }
+ }
+ boost::shared_ptr<TextPrivateFormField> textPrivateField = boost::dynamic_pointer_cast<TextPrivateFormField>(field);
+ if (textPrivateField) {
+ QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]);
+ QString string = widget->text();
+ if (string.isEmpty()) {
+ resultField = FormField::ref(TextPrivateFormField::create());
+ }
+ else {
+ resultField = FormField::ref(TextPrivateFormField::create(Q2PSTRING(string)));
+ }
+ }
+ boost::shared_ptr<TextSingleFormField> textSingleField = boost::dynamic_pointer_cast<TextSingleFormField>(field);
+ if (textSingleField) {
+ QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]);
+ QString string = widget->text();
+ if (string.isEmpty()) {
+ resultField = FormField::ref(TextSingleFormField::create());
+ }
+ else {
+ resultField = FormField::ref(TextSingleFormField::create(Q2PSTRING(string)));
+ }
+ }
+ boost::shared_ptr<JIDSingleFormField> jidSingleField = boost::dynamic_pointer_cast<JIDSingleFormField>(field);
+ if (jidSingleField) {
+ QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]);
+ QString string = widget->text();
+ JID jid(Q2PSTRING(string));
+ if (string.isEmpty()) {
+ resultField = FormField::ref(JIDSingleFormField::create());
+ }
+ else {
+ resultField = FormField::ref(JIDSingleFormField::create(jid));
+ }
+ }
+ boost::shared_ptr<JIDMultiFormField> jidMultiField = boost::dynamic_pointer_cast<JIDMultiFormField>(field);
+ if (jidMultiField) {
+ QTextEdit* widget = qobject_cast<QTextEdit*>(fields_[field->getName()]);
+ QString string = widget->toPlainText();
+ if (string.isEmpty()) {
+ resultField = FormField::ref(JIDMultiFormField::create());
+ }
+ else {
+ QStringList lines = string.split("\n");
+ std::vector<JID> value;
+ foreach (QString line, lines) {
+ value.push_back(JID(Q2PSTRING(line)));
+ }
+ resultField = FormField::ref(JIDMultiFormField::create(value));
+ }
+ }
+ boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field);
+ if (listMultiField) {
+ QListWidget* listWidget = qobject_cast<QListWidget*>(fields_[field->getName()]);
+ std::vector<std::string> values;
+ foreach (QListWidgetItem* item, listWidget->selectedItems()) {
+ values.push_back(field->getOptions()[listWidget->row(item)].value);
+ }
+ resultField = FormField::ref(ListMultiFormField::create(values));
+ }
+ boost::shared_ptr<HiddenFormField> hiddenField = boost::dynamic_pointer_cast<HiddenFormField>(field);
+ if (hiddenField) {
+ resultField = FormField::ref(HiddenFormField::create(hiddenField->getValue()));
+ }
+ resultField->setName(field->getName());
+ result->addField(resultField);
+ }
+ return result;
+}
+
+}
diff --git a/Swift/QtUI/QtFormWidget.h b/Swift/QtUI/QtFormWidget.h
new file mode 100644
index 0000000..2fb7b98
--- /dev/null
+++ b/Swift/QtUI/QtFormWidget.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QWidget>
+
+#include <map>
+#include <Swiften/Elements/Form.h>
+
+class QListWidget;
+
+namespace Swift {
+
+class QtFormWidget : public QWidget {
+ Q_OBJECT
+ public:
+ QtFormWidget(Form::ref form, QWidget* parent = NULL);
+ virtual ~QtFormWidget();
+ Form::ref getCompletedForm();
+ private:
+ QWidget* createWidget(FormField::ref field);
+ QListWidget* createList(FormField::ref field);
+ std::map<std::string, QWidget*> fields_;
+ Form::ref form_;
+};
+
+}
diff --git a/Swift/QtUI/QtJoinMUCWindow.cpp b/Swift/QtUI/QtJoinMUCWindow.cpp
index 7980a17..a44cdaf 100644
--- a/Swift/QtUI/QtJoinMUCWindow.cpp
+++ b/Swift/QtUI/QtJoinMUCWindow.cpp
@@ -6,10 +6,13 @@
#include "QtJoinMUCWindow.h"
#include "QtSwiftUtil.h"
+#include <boost/smart_ptr/make_shared.hpp>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
namespace Swift {
-QtJoinMUCWindow::QtJoinMUCWindow() {
+QtJoinMUCWindow::QtJoinMUCWindow(UIEventStream* uiEventStream) : uiEventStream(uiEventStream) {
ui.setupUi(this);
#if QT_VERSION >= 0x040700
ui.room->setPlaceholderText(tr("someroom@rooms.example.com"));
@@ -35,7 +38,7 @@ void QtJoinMUCWindow::handleJoin() {
lastSetNick = Q2PSTRING(ui.nickName->text());
JID room(Q2PSTRING(ui.room->text()));
- onJoinMUC(room, lastSetNick, ui.joinAutomatically->isChecked());
+ uiEventStream->send(boost::make_shared<JoinMUCUIEvent>(room, lastSetNick, ui.joinAutomatically->isChecked()));
hide();
}
diff --git a/Swift/QtUI/QtJoinMUCWindow.h b/Swift/QtUI/QtJoinMUCWindow.h
index 6e8e846..90b4f3f 100644
--- a/Swift/QtUI/QtJoinMUCWindow.h
+++ b/Swift/QtUI/QtJoinMUCWindow.h
@@ -11,10 +11,11 @@
#include <Swift/QtUI/ui_QtJoinMUCWindow.h>
namespace Swift {
+ class UIEventStream;
class QtJoinMUCWindow : public QWidget, public JoinMUCWindow {
Q_OBJECT
public:
- QtJoinMUCWindow();
+ QtJoinMUCWindow(UIEventStream* uiEventStream);
virtual void setNick(const std::string& nick);
virtual void setMUC(const std::string& nick);
@@ -28,5 +29,6 @@ namespace Swift {
private:
Ui::QtJoinMUCWindow ui;
std::string lastSetNick;
+ UIEventStream* uiEventStream;
};
}
diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp
index fc92792..475863c 100644
--- a/Swift/QtUI/QtLoginWindow.cpp
+++ b/Swift/QtUI/QtLoginWindow.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.
*/
@@ -39,7 +39,7 @@
namespace Swift{
-QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() {
+QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow(), forgetful_(false) {
uiEventStream_ = uiEventStream;
setWindowTitle("Swift");
@@ -56,9 +56,9 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() {
stack_ = new QStackedWidget(centralWidget);
topLayout->addWidget(stack_);
topLayout->setMargin(0);
- QWidget *wrapperWidget = new QWidget(this);
- wrapperWidget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
- QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, wrapperWidget);
+ loginWidgetWrapper_ = new QWidget(this);
+ loginWidgetWrapper_->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+ QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, loginWidgetWrapper_);
layout->addStretch(2);
QLabel* logo = new QLabel(this);
@@ -139,7 +139,7 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() {
layout->addWidget(loginAutomatically_);
connect(loginButton_, SIGNAL(clicked()), SLOT(loginClicked()));
- stack_->addWidget(wrapperWidget);
+ stack_->addWidget(loginWidgetWrapper_);
#ifdef SWIFTEN_PLATFORM_MACOSX
menuBar_ = new QMenuBar(NULL);
#else
@@ -162,9 +162,9 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() {
connect(aboutAction, SIGNAL(triggered()), SLOT(handleAbout()));
swiftMenu_->addAction(aboutAction);
- QAction* xmlConsoleAction = new QAction(tr("&Show Debug Console"), this);
- connect(xmlConsoleAction, SIGNAL(triggered()), SLOT(handleShowXMLConsole()));
- generalMenu_->addAction(xmlConsoleAction);
+ xmlConsoleAction_ = new QAction(tr("&Show Debug Console"), this);
+ connect(xmlConsoleAction_, SIGNAL(triggered()), SLOT(handleShowXMLConsole()));
+ generalMenu_->addAction(xmlConsoleAction_);
toggleSoundsAction_ = new QAction(tr("&Play Sounds"), this);
toggleSoundsAction_->setCheckable(true);
@@ -197,6 +197,17 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() {
this->show();
}
+void QtLoginWindow::setRememberingAllowed(bool allowed) {
+ forgetful_ = true;
+ remember_->setEnabled(allowed);
+ loginAutomatically_->setEnabled(allowed);
+ xmlConsoleAction_->setEnabled(allowed);
+ if (!allowed) {
+ remember_->setChecked(false);
+ loginAutomatically_->setChecked(false);
+ }
+}
+
bool QtLoginWindow::eventFilter(QObject *obj, QEvent *event) {
if (obj == username_->view() && event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
@@ -284,11 +295,9 @@ void QtLoginWindow::handleUsernameTextChanged() {
}
void QtLoginWindow::loggedOut() {
- if (stack_->count() > 1) {
- QWidget* current = stack_->currentWidget();
- stack_->setCurrentIndex(0);
- stack_->removeWidget(current);
- }
+ stack_->removeWidget(stack_->currentWidget());
+ stack_->addWidget(loginWidgetWrapper_);
+ stack_->setCurrentWidget(loginWidgetWrapper_);
setInitialMenus();
setIsLoggingIn(false);
}
@@ -306,6 +315,10 @@ void QtLoginWindow::setIsLoggingIn(bool loggingIn) {
void QtLoginWindow::loginClicked() {
if (username_->isEnabled()) {
onLoginRequest(Q2PSTRING(username_->currentText()), Q2PSTRING(password_->text()), Q2PSTRING(certificateFile_), remember_->isChecked(), loginAutomatically_->isChecked());
+ if (forgetful_) { /* Mustn't remember logins */
+ username_->clearEditText();
+ password_->setText("");
+ }
} else {
onCancelLoginRequest();
}
@@ -370,6 +383,7 @@ void QtLoginWindow::setInitialMenus() {
void QtLoginWindow::morphInto(MainWindow *mainWindow) {
QtMainWindow *qtMainWindow = dynamic_cast<QtMainWindow*>(mainWindow);
assert(qtMainWindow);
+ stack_->removeWidget(loginWidgetWrapper_);
stack_->addWidget(qtMainWindow);
stack_->setCurrentWidget(qtMainWindow);
setEnabled(true);
diff --git a/Swift/QtUI/QtLoginWindow.h b/Swift/QtUI/QtLoginWindow.h
index 3f3b5f8..4628af7 100644
--- a/Swift/QtUI/QtLoginWindow.h
+++ b/Swift/QtUI/QtLoginWindow.h
@@ -1,11 +1,10 @@
/*
- * 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.
*/
-#ifndef SWIFT_QtLoginWindow_H
-#define SWIFT_QtLoginWindow_H
+#pragma once
#include <QMainWindow>
#include <QPointer>
@@ -37,6 +36,7 @@ namespace Swift {
virtual void removeAvailableAccount(const std::string& jid);
virtual void setLoginAutomatically(bool loginAutomatically);
virtual void setIsLoggingIn(bool loggingIn);
+ virtual void setRememberingAllowed(bool allowed);
void selectUser(const std::string& user);
bool askUserToTrustCertificatePermanently(const std::string& message, Certificate::ref certificate);
void hide();
@@ -65,6 +65,7 @@ namespace Swift {
private:
void setInitialMenus();
+ QWidget* loginWidgetWrapper_;
QStringList usernames_;
QStringList passwords_;
QStringList certificateFiles_;
@@ -85,7 +86,7 @@ namespace Swift {
QAction* toggleNotificationsAction_;
UIEventStream* uiEventStream_;
QPointer<QtAboutWidget> aboutDialog_;
+ bool forgetful_;
+ QAction* xmlConsoleAction_;
};
}
-
-#endif
diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp
index 6391961..51aaf3e 100644
--- a/Swift/QtUI/QtMainWindow.cpp
+++ b/Swift/QtUI/QtMainWindow.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.
*/
@@ -21,20 +21,25 @@
#include <QAction>
#include <QTabWidget>
-#include "QtSwiftUtil.h"
-#include "QtTabWidget.h"
-#include "Roster/QtTreeWidget.h"
-#include "Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h"
-#include "Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h"
-#include "Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h"
-#include "Swift/Controllers/UIEvents/RequestProfileEditorUIEvent.h"
-#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
-#include "Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h"
+#include <Swift/QtUI/QtSwiftUtil.h>
+#include <Swift/QtUI/QtTabWidget.h>
+#include <Swift/QtUI/QtSettingsProvider.h>
+#include <Roster/QtTreeWidget.h>
+#include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestProfileEditorUIEvent.h>
+#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestAdHocUIEvent.h>
namespace Swift {
+#define CURRENT_ROSTER_TAB "current_roster_tab"
+
QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventStream) : QWidget(), MainWindow(false) {
uiEventStream_ = uiEventStream;
+ settings_ = settings;
setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
QBoxLayout *mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this);
mainLayout->setContentsMargins(0,0,0,0);
@@ -67,9 +72,14 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS
connect(eventWindow_, SIGNAL(onNewEventCountUpdated(int)), this, SLOT(handleEventCountUpdated(int)));
chatListWindow_ = new QtChatListWindow(uiEventStream_);
+ connect(chatListWindow_, SIGNAL(onCountUpdated(int)), this, SLOT(handleChatCountUpdated(int)));
- tabs_->addTab(eventWindow_, tr("&Notices"));
tabs_->addTab(chatListWindow_, tr("C&hats"));
+ tabs_->addTab(eventWindow_, tr("&Notices"));
+
+ tabs_->setCurrentIndex(settings_->getIntSetting(CURRENT_ROSTER_TAB, 0));
+
+ connect(tabs_, SIGNAL(currentChanged(int)), this, SLOT(handleTabChanged(int)));
this->setLayout(mainLayout);
@@ -99,6 +109,8 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS
chatUserAction_ = new QAction(tr("Start &Chat"), this);
connect(chatUserAction_, SIGNAL(triggered(bool)), this, SLOT(handleChatUserActionTriggered(bool)));
actionsMenu->addAction(chatUserAction_);
+ serverAdHocMenu_ = new QMenu(tr("Run Server Command"), this);
+ actionsMenu->addMenu(serverAdHocMenu_);
actionsMenu->addSeparator();
QAction* signOutAction = new QAction(tr("&Sign Out"), this);
connect(signOutAction, SIGNAL(triggered()), SLOT(handleSignOutAction()));
@@ -106,6 +118,12 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS
connect(treeWidget_, SIGNAL(onSomethingSelectedChanged(bool)), editUserAction_, SLOT(setEnabled(bool)));
+ setAvailableAdHocCommands(std::vector<DiscoItems::Item>());
+ QAction* adHocAction = new QAction(tr("Collecting commands..."), this);
+ adHocAction->setEnabled(false);
+ serverAdHocMenu_->addAction(adHocAction);
+ serverAdHocCommandActions_.append(adHocAction);
+
lastOfflineState_ = false;
uiEventStream_->onUIEvent.connect(boost::bind(&QtMainWindow::handleUIEvent, this, _1));
}
@@ -114,6 +132,10 @@ QtMainWindow::~QtMainWindow() {
uiEventStream_->onUIEvent.disconnect(boost::bind(&QtMainWindow::handleUIEvent, this, _1));
}
+void QtMainWindow::handleTabChanged(int index) {
+ settings_->storeInt(CURRENT_ROSTER_TAB, index);
+}
+
QtEventWindow* QtMainWindow::getEventWindow() {
return eventWindow_;
}
@@ -132,7 +154,7 @@ void QtMainWindow::handleEditProfileRequest() {
void QtMainWindow::handleEventCountUpdated(int count) {
QColor eventTabColor = (count == 0) ? QColor() : QColor(255, 0, 0); // invalid resets to default
- int eventIndex = 1;
+ int eventIndex = 2;
tabs_->tabBar()->setTabTextColor(eventIndex, eventTabColor);
QString text = tr("&Notices");
if (count > 0) {
@@ -141,6 +163,17 @@ void QtMainWindow::handleEventCountUpdated(int count) {
tabs_->setTabText(eventIndex, text);
}
+void QtMainWindow::handleChatCountUpdated(int count) {
+ QColor chatTabColor = (count == 0) ? QColor() : QColor(255, 0, 0); // invalid resets to default
+ int chatIndex = 1;
+ tabs_->tabBar()->setTabTextColor(chatIndex, chatTabColor);
+ QString text = tr("&Chats");
+ if (count > 0) {
+ text += QString(" (%1)").arg(count);
+ }
+ tabs_->setTabText(chatIndex, text);
+}
+
void QtMainWindow::handleAddUserActionTriggered(bool /*checked*/) {
boost::shared_ptr<UIEvent> event(new RequestAddUserDialogUIEvent());
uiEventStream_->send(event);
@@ -206,6 +239,33 @@ void QtMainWindow::setConnecting() {
meView_->setConnecting();
}
+void QtMainWindow::handleAdHocActionTriggered(bool /*checked*/) {
+ QAction* action = qobject_cast<QAction*>(sender());
+ assert(action);
+ DiscoItems::Item command = serverAdHocCommands_[serverAdHocCommandActions_.indexOf(action)];
+ uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestAdHocUIEvent(command)));
+}
+
+void QtMainWindow::setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) {
+ serverAdHocCommands_ = commands;
+ foreach (QAction* action, serverAdHocCommandActions_) {
+ delete action;
+ }
+ serverAdHocMenu_->clear();
+ serverAdHocCommandActions_.clear();
+ foreach (DiscoItems::Item command, commands) {
+ QAction* action = new QAction(P2QSTRING(command.getName()), this);
+ connect(action, SIGNAL(triggered(bool)), this, SLOT(handleAdHocActionTriggered(bool)));
+ serverAdHocMenu_->addAction(action);
+ serverAdHocCommandActions_.append(action);
+ }
+ if (serverAdHocCommandActions_.isEmpty()) {
+ QAction* action = new QAction(tr("No Available Commands"), this);
+ action->setEnabled(false);
+ serverAdHocMenu_->addAction(action);
+ serverAdHocCommandActions_.append(action);
+ }
+}
}
diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h
index 3462bb0..bb3e9df 100644
--- a/Swift/QtUI/QtMainWindow.h
+++ b/Swift/QtUI/QtMainWindow.h
@@ -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.
*/
@@ -8,6 +8,7 @@
#include <QWidget>
#include <QMenu>
+#include <QList>
#include "Swift/Controllers/UIInterfaces/MainWindow.h"
#include "Swift/QtUI/QtRosterHeader.h"
#include "Swift/QtUI/EventViewer/QtEventWindow.h"
@@ -20,7 +21,7 @@ class QLineEdit;
class QPushButton;
class QToolBar;
class QAction;
-
+class QMenu;
class QTabWidget;
namespace Swift {
@@ -46,6 +47,7 @@ namespace Swift {
QtEventWindow* getEventWindow();
QtChatListWindow* getChatListWindow();
void setRosterModel(Roster* roster);
+ void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands);
private slots:
void handleStatusChanged(StatusShow::Type showType, const QString &statusMessage);
void handleUIEvent(boost::shared_ptr<UIEvent> event);
@@ -55,10 +57,14 @@ namespace Swift {
void handleEditProfileAction();
void handleAddUserActionTriggered(bool checked);
void handleChatUserActionTriggered(bool checked);
+ void handleAdHocActionTriggered(bool checked);
void handleEventCountUpdated(int count);
+ void handleChatCountUpdated(int count);
void handleEditProfileRequest();
+ void handleTabChanged(int index);
private:
+ QtSettingsProvider* settings_;
std::vector<QMenu*> menus_;
QtTreeWidget* treeWidget_;
QtRosterHeader* meView_;
@@ -66,6 +72,7 @@ namespace Swift {
QAction* editUserAction_;
QAction* chatUserAction_;
QAction* showOfflineAction_;
+ QMenu* serverAdHocMenu_;
QtTabWidget* tabs_;
QWidget* contactsTabWidget_;
QWidget* eventsTabWidget_;
@@ -73,5 +80,7 @@ namespace Swift {
QtChatListWindow* chatListWindow_;
UIEventStream* uiEventStream_;
bool lastOfflineState_;
+ std::vector<DiscoItems::Item> serverAdHocCommands_;
+ QList<QAction*> serverAdHocCommandActions_;
};
}
diff --git a/Swift/QtUI/QtSubscriptionRequestWindow.cpp b/Swift/QtUI/QtSubscriptionRequestWindow.cpp
index 7828103..d22cbd0 100644
--- a/Swift/QtUI/QtSubscriptionRequestWindow.cpp
+++ b/Swift/QtUI/QtSubscriptionRequestWindow.cpp
@@ -28,10 +28,12 @@ QtSubscriptionRequestWindow::QtSubscriptionRequestWindow(boost::shared_ptr<Subsc
layout->addWidget(okButton);
} else {
QPushButton* yesButton = new QPushButton(tr("Yes"), this);
+ yesButton->setDefault(true);
connect(yesButton, SIGNAL(clicked()), this, SLOT(handleYes()));
QPushButton* noButton = new QPushButton(tr("No"), this);
connect(noButton, SIGNAL(clicked()), this, SLOT(handleNo()));
QPushButton* deferButton = new QPushButton(tr("Defer"), this);
+ deferButton->setShortcut(QKeySequence(Qt::Key_Escape));
connect(deferButton, SIGNAL(clicked()), this, SLOT(handleDefer()));
QHBoxLayout* buttonLayout = new QHBoxLayout();
diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp
index 7830150..57f4175 100644
--- a/Swift/QtUI/QtSwift.cpp
+++ b/Swift/QtUI/QtSwift.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.
*/
@@ -18,13 +18,11 @@
#include "QtUIFactory.h"
#include "QtChatWindowFactory.h"
#include <Swiften/Base/Log.h>
-#include <Swift/Controllers/CertificateFileStorageFactory.h>
+#include <Swift/Controllers/Storages/CertificateFileStorageFactory.h>
+#include "Swift/Controllers/Storages/FileStoragesFactory.h"
#include "SwifTools/Application/PlatformApplicationPathProvider.h"
-#include "Swiften/Avatars/AvatarFileStorage.h"
-#include "Swiften/Disco/CapsFileStorage.h"
#include <string>
#include "Swiften/Base/Platform.h"
-#include "Swift/Controllers/FileStoragesFactory.h"
#include "Swiften/Elements/Presence.h"
#include "Swiften/Client/Client.h"
#include "Swift/Controllers/MainController.h"
@@ -32,20 +30,30 @@
#include "Swift/Controllers/BuildVersion.h"
#include "SwifTools/AutoUpdater/AutoUpdater.h"
#include "SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.h"
+
#if defined(SWIFTEN_PLATFORM_WINDOWS)
#include "WindowsNotifier.h"
-#endif
-#if defined(HAVE_GROWL)
+#elif defined(HAVE_GROWL)
#include "SwifTools/Notifier/GrowlNotifier.h"
#elif defined(SWIFTEN_PLATFORM_LINUX)
#include "FreeDesktopNotifier.h"
#else
#include "SwifTools/Notifier/NullNotifier.h"
#endif
+
#if defined(SWIFTEN_PLATFORM_MACOSX)
#include "SwifTools/Dock/MacOSXDock.h"
-#endif
+#else
#include "SwifTools/Dock/NullDock.h"
+#endif
+
+#if defined(SWIFTEN_PLATFORM_MACOSX)
+#include "QtURIHandler.h"
+#elif defined(SWIFTEN_PLATFORM_WIN32)
+#include <SwifTools/URIHandler/NullURIHandler.h>
+#else
+#include "QtDBUSURIHandler.h"
+#endif
namespace Swift{
@@ -66,12 +74,13 @@ po::options_description QtSwift::getOptionsDescription() {
("latency-debug", "Use latency debugging (unsupported)")
("multi-account", po::value<int>()->default_value(1), "Number of accounts to open windows for (unsupported)")
("start-minimized", "Don't show the login/roster window at startup")
+ ("eagle-mode", "Settings more suitable for military/secure deployments")
;
return result;
}
-QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMainThreadCaller_), autoUpdater_(NULL) {
+QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMainThreadCaller_), autoUpdater_(NULL), idleDetector_(&idleQuerier_, networkFactories_.getTimerFactory(), 1000) {
if (options.count("netbook-mode")) {
splitter_ = new QSplitter();
} else {
@@ -96,6 +105,7 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
tabs_ = options.count("no-tabs") && !(splitter_ > 0) ? NULL : new QtChatTabs();
bool startMinimized = options.count("start-minimized") > 0;
+ bool eagleMode = options.count("eagle-mode") > 0;
settings_ = new QtSettingsProvider();
applicationPathProvider_ = new PlatformApplicationPathProvider(SWIFT_APPLICATION_NAME);
storagesFactory_ = new FileStoragesFactory(applicationPathProvider_->getDataDir());
@@ -124,6 +134,14 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
dock_ = new NullDock();
#endif
+#if defined(SWIFTEN_PLATFORM_MACOSX)
+ uriHandler_ = new QtURIHandler();
+#elif defined(SWIFTEN_PLATFORM_WIN32)
+ uriHandler_ = new NullURIHandler();
+#else
+ uriHandler_ = new QtDBUSURIHandler();
+#endif
+
if (splitter_) {
splitter_->show();
}
@@ -146,7 +164,10 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
certificateStorageFactory_,
dock_,
notifier_,
- options.count("latency-debug") > 0);
+ uriHandler_,
+ &idleDetector_,
+ options.count("latency-debug") > 0,
+ eagleMode);
mainControllers_.push_back(mainController);
}
@@ -173,6 +194,7 @@ QtSwift::~QtSwift() {
}
delete tabs_;
delete splitter_;
+ delete uriHandler_;
delete dock_;
delete soundPlayer_;
delete chatWindowFactory_;
diff --git a/Swift/QtUI/QtSwift.h b/Swift/QtUI/QtSwift.h
index 978fa14..7f33475 100644
--- a/Swift/QtUI/QtSwift.h
+++ b/Swift/QtUI/QtSwift.h
@@ -21,6 +21,8 @@
#if defined(SWIFTEN_PLATFORM_WINDOWS)
#include "WindowsNotifier.h"
#endif
+#include "SwifTools/Idle/PlatformIdleQuerier.h"
+#include "SwifTools/Idle/ActualIdleDetector.h"
namespace po = boost::program_options;
@@ -44,6 +46,7 @@ namespace Swift {
class QtMUCSearchWindowFactory;
class QtUserSearchWindowFactory;
class EventLoop;
+ class URIHandler;
class QtSwift : public QObject {
Q_OBJECT
@@ -63,12 +66,15 @@ namespace Swift {
QSplitter* splitter_;
QtSoundPlayer* soundPlayer_;
Dock* dock_;
+ URIHandler* uriHandler_;
QtChatTabs* tabs_;
ApplicationPathProvider* applicationPathProvider_;
StoragesFactory* storagesFactory_;
CertificateStorageFactory* certificateStorageFactory_;
AutoUpdater* autoUpdater_;
Notifier* notifier_;
+ PlatformIdleQuerier idleQuerier_;
+ ActualIdleDetector idleDetector_;
#if defined(SWIFTEN_PLATFORM_MACOSX)
CocoaApplication cocoaApplication_;
#endif
diff --git a/Swift/QtUI/QtTextEdit.cpp b/Swift/QtUI/QtTextEdit.cpp
index 3668220..3a62325 100644
--- a/Swift/QtUI/QtTextEdit.cpp
+++ b/Swift/QtUI/QtTextEdit.cpp
@@ -4,7 +4,7 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "QtTextEdit.h"
+#include <Swift/QtUI/QtTextEdit.h>
#include <QFontMetrics>
#include <QKeyEvent>
@@ -22,19 +22,25 @@ void QtTextEdit::keyPressEvent(QKeyEvent* event) {
if ((key == Qt::Key_Enter || key == Qt::Key_Return)
&& (modifiers == Qt::NoModifier || modifiers == Qt::KeypadModifier)) {
emit returnPressed();
- } else if (((key == Qt::Key_PageUp || key == Qt::Key_PageDown) && modifiers == Qt::ShiftModifier)
+ }
+ else if (((key == Qt::Key_PageUp || key == Qt::Key_PageDown) && modifiers == Qt::ShiftModifier)
|| (key == Qt::Key_C && modifiers == Qt::ControlModifier && textCursor().selectedText().isEmpty())
|| (key == Qt::Key_W && modifiers == Qt::ControlModifier)
|| (key == Qt::Key_PageUp && modifiers == Qt::ControlModifier)
|| (key == Qt::Key_PageDown && modifiers == Qt::ControlModifier)
-// || (key == Qt::Key_Left && modifiers == (Qt::ControlModifier | Qt::ShiftModifier))
-// || (key == Qt::Key_Right && modifiers == (Qt::ControlModifier | Qt::ShiftModifier))
|| (key == Qt::Key_Tab && modifiers == Qt::ControlModifier)
|| (key == Qt::Key_A && modifiers == Qt::AltModifier)
|| (key == Qt::Key_Tab)
) {
emit unhandledKeyPressEvent(event);
- } else {
+ }
+ else if ((key == Qt::Key_Up)
+ || (key == Qt::Key_Down)
+ ){
+ emit unhandledKeyPressEvent(event);
+ QTextEdit::keyPressEvent(event);
+ }
+ else {
QTextEdit::keyPressEvent(event);
}
}
diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp
index 35fbfcd..bd936d4 100644
--- a/Swift/QtUI/QtUIFactory.cpp
+++ b/Swift/QtUI/QtUIFactory.cpp
@@ -23,10 +23,14 @@
#include "UserSearch/QtUserSearchWindow.h"
#include "QtProfileWindow.h"
#include "QtContactEditWindow.h"
+#include "QtAdHocCommandWindow.h"
+
+#define CHATWINDOW_FONT_SIZE "chatWindowFontSize"
namespace Swift {
QtUIFactory::QtUIFactory(QtSettingsProvider* settings, QtChatTabs* tabs, QSplitter* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, bool startMinimized) : settings(settings), tabs(tabs), netbookSplitter(netbookSplitter), systemTray(systemTray), chatWindowFactory(chatWindowFactory), lastMainWindow(NULL), loginWindow(NULL), startMinimized(startMinimized) {
+ chatFontSize = settings->getIntSetting(CHATWINDOW_FONT_SIZE, 0);
}
XMLConsoleWidget* QtUIFactory::createXMLConsoleWidget() {
@@ -80,15 +84,36 @@ MUCSearchWindow* QtUIFactory::createMUCSearchWindow() {
}
ChatWindow* QtUIFactory::createChatWindow(const JID& contact, UIEventStream* eventStream) {
- return chatWindowFactory->createChatWindow(contact, eventStream);
+ QtChatWindow* window = dynamic_cast<QtChatWindow*>(chatWindowFactory->createChatWindow(contact, eventStream));
+ chatWindows.push_back(window);
+ std::vector<QPointer<QtChatWindow> > deletions;
+ foreach (QPointer<QtChatWindow> existingWindow, chatWindows) {
+ if (existingWindow.isNull()) {
+ deletions.push_back(existingWindow);
+ } else {
+ connect(window, SIGNAL(fontResized(int)), existingWindow, SLOT(handleFontResized(int)));
+ connect(existingWindow, SIGNAL(fontResized(int)), window, SLOT(handleFontResized(int)));
+ }
+ }
+ foreach (QPointer<QtChatWindow> deletedWindow, deletions) {
+ chatWindows.erase(std::remove(chatWindows.begin(), chatWindows.end(), deletedWindow), chatWindows.end());
+ }
+ connect(window, SIGNAL(fontResized(int)), this, SLOT(handleChatWindowFontResized(int)));
+ window->handleFontResized(chatFontSize);
+ return window;
+}
+
+void QtUIFactory::handleChatWindowFontResized(int size) {
+ chatFontSize = size;
+ settings->storeInt(CHATWINDOW_FONT_SIZE, size);
}
UserSearchWindow* QtUIFactory::createUserSearchWindow(UserSearchWindow::Type type, UIEventStream* eventStream, const std::set<std::string>& groups) {
return new QtUserSearchWindow(eventStream, type, groups);
};
-JoinMUCWindow* QtUIFactory::createJoinMUCWindow() {
- return new QtJoinMUCWindow();
+JoinMUCWindow* QtUIFactory::createJoinMUCWindow(UIEventStream* uiEventStream) {
+ return new QtJoinMUCWindow(uiEventStream);
}
ProfileWindow* QtUIFactory::createProfileWindow() {
@@ -99,5 +124,8 @@ ContactEditWindow* QtUIFactory::createContactEditWindow() {
return new QtContactEditWindow();
}
+void QtUIFactory::createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command) {
+ new QtAdHocCommandWindow(command);
+}
}
diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h
index ddaaf6e..e7ea6c6 100644
--- a/Swift/QtUI/QtUIFactory.h
+++ b/Swift/QtUI/QtUIFactory.h
@@ -7,6 +7,7 @@
#pragma once
#include <QObject>
+#include <QPointer>
#include <Swift/Controllers/UIInterfaces/UIFactory.h>
@@ -20,6 +21,7 @@ namespace Swift {
class QtMainWindow;
class QtChatTheme;
class QtChatWindowFactory;
+ class QtChatWindow;
class QtUIFactory : public QObject, public UIFactory {
Q_OBJECT
@@ -34,12 +36,14 @@ namespace Swift {
virtual MUCSearchWindow* createMUCSearchWindow();
virtual ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream);
virtual UserSearchWindow* createUserSearchWindow(UserSearchWindow::Type type, UIEventStream* eventStream, const std::set<std::string>& groups);
- virtual JoinMUCWindow* createJoinMUCWindow();
+ virtual JoinMUCWindow* createJoinMUCWindow(UIEventStream* uiEventStream);
virtual ProfileWindow* createProfileWindow();
virtual ContactEditWindow* createContactEditWindow();
+ virtual void createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command);
private slots:
void handleLoginWindowGeometryChanged();
+ void handleChatWindowFontResized(int);
private:
QtSettingsProvider* settings;
@@ -49,6 +53,8 @@ namespace Swift {
QtChatWindowFactory* chatWindowFactory;
QtMainWindow* lastMainWindow;
QtLoginWindow* loginWindow;
+ std::vector<QPointer<QtChatWindow> > chatWindows;
bool startMinimized;
+ int chatFontSize;
};
}
diff --git a/Swift/QtUI/QtURIHandler.cpp b/Swift/QtUI/QtURIHandler.cpp
new file mode 100644
index 0000000..43f3ed1
--- /dev/null
+++ b/Swift/QtUI/QtURIHandler.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "QtURIHandler.h"
+
+#include <QCoreApplication>
+#include <QFileOpenEvent>
+#include <QUrl>
+
+#include "QtSwiftUtil.h"
+#ifdef Q_WS_MAC
+#include <SwifTools/URIHandler/MacOSXURIHandlerHelpers.h>
+#endif
+
+using namespace Swift;
+
+QtURIHandler::QtURIHandler() {
+ qApp->installEventFilter(this);
+#ifdef Q_WS_MAC
+ registerAppAsDefaultXMPPURIHandler();
+#endif
+}
+
+bool QtURIHandler::eventFilter(QObject*, QEvent* event) {
+ if (event->type() == QEvent::FileOpen) {
+ QFileOpenEvent* fileOpenEvent = static_cast<QFileOpenEvent*>(event);
+ if (fileOpenEvent->url().scheme() == "xmpp") {
+ onURI(Q2PSTRING(fileOpenEvent->url().toString()));
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/Swift/QtUI/QtURIHandler.h b/Swift/QtUI/QtURIHandler.h
new file mode 100644
index 0000000..a02114a
--- /dev/null
+++ b/Swift/QtUI/QtURIHandler.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QObject>
+#include <SwifTools/URIHandler/URIHandler.h>
+
+class QUrl;
+
+namespace Swift {
+ class QtURIHandler : public QObject, public URIHandler {
+ public:
+ QtURIHandler();
+
+ private:
+ bool eventFilter(QObject* obj, QEvent* event);
+ };
+}
diff --git a/Swift/QtUI/QtWebView.cpp b/Swift/QtUI/QtWebView.cpp
index 9d12010..5f9539e 100644
--- a/Swift/QtUI/QtWebView.cpp
+++ b/Swift/QtUI/QtWebView.cpp
@@ -39,6 +39,10 @@ void QtWebView::dragEnterEvent(QDragEnterEvent*) {
}
+void QtWebView::setFontSizeIsMinimal(bool minimum) {
+ fontSizeIsMinimal = minimum;
+}
+
void QtWebView::contextMenuEvent(QContextMenuEvent* ev) {
// Filter out the relevant actions from the standard actions
QMenu* menu = page()->createStandardContextMenu();
@@ -59,6 +63,11 @@ void QtWebView::contextMenuEvent(QContextMenuEvent* ev) {
// Add our own custom actions
menu->addAction(tr("Clear"), this, SIGNAL(clearRequested()));
+ menu->addAction(tr("Increase font size"), this, SIGNAL(fontGrowRequested()));
+ QAction* shrink = new QAction(tr("Decrease font size"), this);
+ shrink->setEnabled(!fontSizeIsMinimal);
+ connect(shrink, SIGNAL(triggered()), this, SIGNAL(fontShrinkRequested()));
+ menu->addAction(shrink);
menu->exec(ev->globalPos());
delete menu;
diff --git a/Swift/QtUI/QtWebView.h b/Swift/QtUI/QtWebView.h
index fbd31e3..202037f 100644
--- a/Swift/QtUI/QtWebView.h
+++ b/Swift/QtUI/QtWebView.h
@@ -18,15 +18,19 @@ namespace Swift {
void keyPressEvent(QKeyEvent* event);
void dragEnterEvent(QDragEnterEvent *event);
void contextMenuEvent(QContextMenuEvent* ev);
+ void setFontSizeIsMinimal(bool minimum);
signals:
void gotFocus();
void clearRequested();
+ void fontGrowRequested();
+ void fontShrinkRequested();
protected:
void focusInEvent(QFocusEvent* event);
private:
std::vector<QWebPage::WebAction> filteredActions;
+ bool fontSizeIsMinimal;
};
}
diff --git a/Swift/QtUI/QtXMLConsoleWidget.cpp b/Swift/QtUI/QtXMLConsoleWidget.cpp
index c1b1d0d..b0c0385 100644
--- a/Swift/QtUI/QtXMLConsoleWidget.cpp
+++ b/Swift/QtUI/QtXMLConsoleWidget.cpp
@@ -71,12 +71,12 @@ void QtXMLConsoleWidget::closeEvent(QCloseEvent* event) {
event->accept();
}
-void QtXMLConsoleWidget::handleDataRead(const std::string& data) {
- appendTextIfEnabled(std::string(tr("<!-- IN -->").toUtf8()) + "\n" + data + "\n", QColor(33,98,33));
+void QtXMLConsoleWidget::handleDataRead(const SafeByteArray& data) {
+ appendTextIfEnabled(std::string(tr("<!-- IN -->").toUtf8()) + "\n" + safeByteArrayToString(data) + "\n", QColor(33,98,33));
}
-void QtXMLConsoleWidget::handleDataWritten(const std::string& data) {
- appendTextIfEnabled(std::string(tr("<!-- OUT -->").toUtf8()) + "\n" + data + "\n", QColor(155,1,0));
+void QtXMLConsoleWidget::handleDataWritten(const SafeByteArray& data) {
+ appendTextIfEnabled(std::string(tr("<!-- OUT -->").toUtf8()) + "\n" + safeByteArrayToString(data) + "\n", QColor(155,1,0));
}
void QtXMLConsoleWidget::appendTextIfEnabled(const std::string& data, const QColor& color) {
diff --git a/Swift/QtUI/QtXMLConsoleWidget.h b/Swift/QtUI/QtXMLConsoleWidget.h
index a345495..73a3bad 100644
--- a/Swift/QtUI/QtXMLConsoleWidget.h
+++ b/Swift/QtUI/QtXMLConsoleWidget.h
@@ -23,8 +23,8 @@ namespace Swift {
void show();
void activate();
- virtual void handleDataRead(const std::string& data);
- virtual void handleDataWritten(const std::string& data);
+ virtual void handleDataRead(const SafeByteArray& data);
+ virtual void handleDataWritten(const SafeByteArray& data);
private:
virtual void closeEvent(QCloseEvent* event);
diff --git a/Swift/QtUI/Roster/DelegateCommons.cpp b/Swift/QtUI/Roster/DelegateCommons.cpp
index 164b80f..290794d 100644
--- a/Swift/QtUI/Roster/DelegateCommons.cpp
+++ b/Swift/QtUI/Roster/DelegateCommons.cpp
@@ -6,18 +6,102 @@
#include "DelegateCommons.h"
+#include <QtScaledAvatarCache.h>
+#include <QFileInfo>
+
namespace Swift {
-void DelegateCommons::drawElidedText(QPainter* painter, const QRect& region, const QString& text) {
+void DelegateCommons::drawElidedText(QPainter* painter, const QRect& region, const QString& text, int flags) {
QString adjustedText(painter->fontMetrics().elidedText(text, Qt::ElideRight, region.width(), Qt::TextShowMnemonic));
- painter->drawText(region, Qt::AlignTop, adjustedText);
+ painter->drawText(region, flags, adjustedText);
}
+void DelegateCommons::paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QColor& nameColor, const QString& avatarPath, const QIcon& presenceIcon, const QString& name, const QString& statusText, int unreadCount) const {
+ painter->save();
+ QRect fullRegion(option.rect);
+ if ( option.state & QStyle::State_Selected ) {
+ painter->fillRect(fullRegion, option.palette.highlight());
+ painter->setPen(option.palette.highlightedText().color());
+ } else {
+ painter->setPen(QPen(nameColor));
+ }
+
+ QRect presenceIconRegion(QPoint(farLeftMargin, fullRegion.top()), QSize(presenceIconWidth, fullRegion.height() - verticalMargin));
+
+ int calculatedAvatarSize = presenceIconRegion.height();
+ //This overlaps the presenceIcon, so must be painted first
+ QRect avatarRegion(QPoint(presenceIconRegion.right() - presenceIconWidth / 2, presenceIconRegion.top()), QSize(calculatedAvatarSize, calculatedAvatarSize));
+
+ QPixmap avatarPixmap;
+ if (!avatarPath.isEmpty()) {
+ QString scaledAvatarPath = QtScaledAvatarCache(avatarRegion.height()).getScaledAvatarPath(avatarPath);
+ if (QFileInfo(scaledAvatarPath).exists()) {
+ avatarPixmap.load(scaledAvatarPath);
+ }
+ }
+ if (avatarPixmap.isNull()) {
+ avatarPixmap = QPixmap(":/icons/avatar.png").scaled(avatarRegion.height(), avatarRegion.width(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ }
+
+ painter->drawPixmap(avatarRegion.topLeft() + QPoint(((avatarRegion.width() - avatarPixmap.width()) / 2), (avatarRegion.height() - avatarPixmap.height()) / 2), avatarPixmap);
+
+ //Paint the presence icon over the top of the avatar
+ presenceIcon.paint(painter, presenceIconRegion, Qt::AlignBottom | Qt::AlignHCenter);
+
+ QFontMetrics nameMetrics(nameFont);
+ painter->setFont(nameFont);
+ int extraFontWidth = nameMetrics.width("H");
+ int leftOffset = avatarRegion.right() + horizontalMargin * 2 + extraFontWidth / 2;
+ QRect textRegion(fullRegion.adjusted(leftOffset, 0, 0/*-leftOffset*/, 0));
+
+ int nameHeight = nameMetrics.height() + verticalMargin;
+ QRect nameRegion(textRegion.adjusted(0, verticalMargin, 0, 0));
+
+ DelegateCommons::drawElidedText(painter, nameRegion, name);
+
+
+ painter->setFont(detailFont);
+ painter->setPen(QPen(QColor(160,160,160)));
+
+ QRect statusTextRegion(textRegion.adjusted(0, nameHeight, 0, 0));
+ DelegateCommons::drawElidedText(painter, statusTextRegion, statusText);
+
+ if (unreadCount > 0) {
+ QRect unreadRect(fullRegion.right() - unreadCountSize - horizontalMargin, fullRegion.top() + (fullRegion.height() - unreadCountSize) / 2, unreadCountSize, unreadCountSize);
+ QPen pen(QColor("black"));
+ pen.setWidth(1);
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ painter->setPen(pen);
+ painter->setBrush(QBrush(QColor("red"), Qt::SolidPattern));
+ //painter->setBackgroundMode(Qt::OpaqueMode);
+ painter->drawEllipse(unreadRect);
+ painter->setBackgroundMode(Qt::TransparentMode);
+ painter->setPen(QColor("white"));
+ drawElidedText(painter, unreadRect, QString("%1").arg(unreadCount), Qt::AlignCenter);
+ }
+
+ painter->restore();
+}
+
+QSize DelegateCommons::contactSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const {
+ int heightByAvatar = avatarSize + verticalMargin * 2;
+ QFontMetrics nameMetrics(nameFont);
+ QFontMetrics statusMetrics(detailFont);
+ int sizeByText = 2 * verticalMargin + nameMetrics.height() + statusMetrics.height();
+ //Doesn't work, yay! FIXME: why?
+ //QSize size = (option.state & QStyle::State_Selected) ? QSize(150, 80) : QSize(150, avatarSize_ + margin_ * 2);
+ //qDebug() << "Returning size" << size;
+ return QSize(150, sizeByText > heightByAvatar ? sizeByText : heightByAvatar);
+}
const int DelegateCommons::horizontalMargin = 2;
const int DelegateCommons::verticalMargin = 2;
const int DelegateCommons::farLeftMargin = 2;
+const int DelegateCommons::avatarSize = 20;
+const int DelegateCommons::presenceIconHeight = 16;
+const int DelegateCommons::presenceIconWidth = 16;
+const int DelegateCommons::unreadCountSize = 16;
diff --git a/Swift/QtUI/Roster/DelegateCommons.h b/Swift/QtUI/Roster/DelegateCommons.h
index 9213ef5..e5e4ff9 100644
--- a/Swift/QtUI/Roster/DelegateCommons.h
+++ b/Swift/QtUI/Roster/DelegateCommons.h
@@ -11,6 +11,8 @@
#include <QPainter>
#include <QRect>
#include <QString>
+#include <QIcon>
+#include <QStyleOptionViewItem>
namespace Swift {
class DelegateCommons {
@@ -21,7 +23,10 @@ namespace Swift {
detailFont.setPointSize(nameFont.pointSize() - detailFontSizeDrop);
}
- static void drawElidedText(QPainter* painter, const QRect& region, const QString& text);
+ static void drawElidedText(QPainter* painter, const QRect& region, const QString& text, int flags = Qt::AlignTop);
+
+ QSize contactSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
+ void paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QColor& nameColor, const QString& avatarPath, const QIcon& presenceIcon, const QString& name, const QString& statusText, int unreadCount) const;
int detailFontSizeDrop;
QFont nameFont;
@@ -29,5 +34,9 @@ namespace Swift {
static const int horizontalMargin;
static const int verticalMargin;
static const int farLeftMargin;
+ static const int avatarSize;
+ static const int presenceIconHeight;
+ static const int presenceIconWidth;
+ static const int unreadCountSize;
};
}
diff --git a/Swift/QtUI/Roster/QtTreeWidgetItem.cpp b/Swift/QtUI/Roster/QtTreeWidgetItem.cpp
deleted file mode 100644
index fcd8691..0000000
--- a/Swift/QtUI/Roster/QtTreeWidgetItem.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#include "Swift/QtUI/Roster/QtTreeWidgetItem.h"
-#include "Swift/QtUI/Roster/QtTreeWidget.h"
-
-#include <qdebug.h>
-#include <QtAlgorithms>
-#include <algorithm>
-
-namespace Swift {
-
-QtTreeWidgetItem::QtTreeWidgetItem(QtTreeWidgetItem* parentItem) : QObject(), textColor_(0,0,0), backgroundColor_(255,255,255) {
- parent_ = parentItem;
- shown_ = true;
- expanded_ = true;
-}
-
-
-void QtTreeWidgetItem::setText(const std::string& text) {
- displayName_ = P2QSTRING(text);
- displayNameLower_ = displayName_.toLower();
- emit changed(this);
-}
-
-void QtTreeWidgetItem::setStatusText(const std::string& text) {
- statusText_ = P2QSTRING(text);
- emit changed(this);
-}
-
-void QtTreeWidgetItem::setAvatarPath(const std::string& path) {
- avatar_ = QIcon(P2QSTRING(path));
- emit changed(this);
-}
-
-void QtTreeWidgetItem::setStatusShow(StatusShow::Type show) {
- statusShowType_ = show;
- int color = 0;
- switch (show) {
- case StatusShow::Online: color = 0x000000; mergedShowType_ = StatusShow::Online; break;
- case StatusShow::Away: color = 0x336699; mergedShowType_ = StatusShow::Away; break;
- case StatusShow::XA: color = 0x336699; mergedShowType_ = StatusShow::Away; break;
- case StatusShow::FFC: color = 0x000000; mergedShowType_ = StatusShow::Online; break;
- case StatusShow::DND: color = 0x990000; mergedShowType_ = show; break;
- case StatusShow::None: color = 0x7F7F7F; mergedShowType_ = show; break;
- }
- setTextColor(color);
- emit changed(this);
-}
-
-void QtTreeWidgetItem::setTextColor(unsigned long color) {
- textColor_ = QColor(
- ((color & 0xFF0000)>>16),
- ((color & 0xFF00)>>8),
- (color & 0xFF));
-}
-
-void QtTreeWidgetItem::setBackgroundColor(unsigned long color) {
- backgroundColor_ = QColor(
- ((color & 0xFF0000)>>16),
- ((color & 0xFF00)>>8),
- (color & 0xFF));
-}
-
-void QtTreeWidgetItem::setExpanded(bool expanded) {
- expanded_ = expanded;
- emit changed(this);
-}
-
-void QtTreeWidgetItem::hide() {
- shown_ = false;
- emit changed(this);
-}
-
-void QtTreeWidgetItem::show() {
- shown_ = true;
- emit changed(this);
-}
-
-bool QtTreeWidgetItem::isShown() {
- return isContact() ? shown_ : shownChildren_.size() > 0;
-}
-
-QWidget* QtTreeWidgetItem::getCollapsedRosterWidget() {
- QWidget* widget = new QWidget();
- return widget;
-}
-
-QWidget* QtTreeWidgetItem::getExpandedRosterWidget() {
- QWidget* widget = new QWidget();
- return widget;
-}
-
-QtTreeWidgetItem::~QtTreeWidgetItem() {
- //It's possible (due to the way the roster deletes items in unknown order when it is deleted)
- // That the children will be deleted before the groups, or that the groups are deleted
- // before the children. If the children are deleted first, they will let the parent know that
- // They've been deleted. If the parent is deleted first, it must tell the children not to
- // tell it when they're deleted. Everything will be deleted in the end, because all the
- // widgets are owned by the Roster in Swiften.
- if (parent_) {
- parent_->removeChild(this);
- }
-
- for (int i = 0; i < children_.size(); i++) {
- children_[i]->parentItemHasBeenDeleted();
- }
-}
-
-void QtTreeWidgetItem::parentItemHasBeenDeleted() {
- parent_ = NULL;
-}
-
-QtTreeWidgetItem* QtTreeWidgetItem::getParentItem() {
- return parent_;
-}
-
-void QtTreeWidgetItem::addChild(QtTreeWidgetItem* child) {
- children_.append(child);
- connect(child, SIGNAL(changed(QtTreeWidgetItem*)), this, SLOT(handleChanged(QtTreeWidgetItem*)));
- handleChanged(child);
-}
-
-void QtTreeWidgetItem::removeChild(QtTreeWidgetItem* child) {
- children_.removeAll(child);
- handleChanged(this);
-}
-
-void bubbleSort(QList<QtTreeWidgetItem*>& list) {
- bool done = false;
- for (int i = 0; i < list.size() - 1 && !done; i++) {
- done = true;
- for (int j = i + 1; j < list.size(); j++) {
- if (*(list[j]) < *(list[j - 1])) {
- done = false;
- QtTreeWidgetItem* lower = list[j];
- list[j] = list[j - 1];
- list[j - 1] = lower;
- }
- }
- }
-}
-
-void QtTreeWidgetItem::handleChanged(QtTreeWidgetItem* child) {
- /*We don't use the much faster qStableSort because it causes changed(child) and all sorts of nasty recursion*/
- //qStableSort(children_.begin(), children_.end(), itemLessThan);
- //bubbleSort(children_);
- std::stable_sort(children_.begin(), children_.end(), itemLessThan);
- shownChildren_.clear();
- for (int i = 0; i < children_.size(); i++) {
- if (children_[i]->isShown()) {
- shownChildren_.append(children_[i]);
- }
- }
- emit changed(child);
-}
-
-int QtTreeWidgetItem::rowCount() {
- //qDebug() << "Returning size of " << children_.size() << " for item " << displayName_;
- return shownChildren_.size();
-}
-
-int QtTreeWidgetItem::rowOf(QtTreeWidgetItem* item) {
- return shownChildren_.indexOf(item);
-}
-
-int QtTreeWidgetItem::row() {
- return parent_ ? parent_->rowOf(this) : 0;
-}
-
-QtTreeWidgetItem* QtTreeWidgetItem::getItem(int row) {
- //qDebug() << "Returning row " << row << " from item " << displayName_;
- Q_ASSERT(row >= 0);
- Q_ASSERT(row < rowCount());
- return shownChildren_[row];
-}
-
-
-QVariant QtTreeWidgetItem::data(int role) {
- if (!isContact()) {
- setTextColor(0xFFFFFF);
- setBackgroundColor(0x969696);
- }
- switch (role) {
- case Qt::DisplayRole: return displayName_;
- case Qt::TextColorRole: return textColor_;
- case Qt::BackgroundColorRole: return backgroundColor_;
- case Qt::ToolTipRole: return isContact() ? toolTipString() : QVariant();
- case StatusTextRole: return statusText_;
- case AvatarRole: return avatar_;
- case PresenceIconRole: return getPresenceIcon();
- default: return QVariant();
- }
-}
-
-QString QtTreeWidgetItem::toolTipString() {
- return displayName_ + "\n " + statusText_;
-}
-
-QIcon QtTreeWidgetItem::getPresenceIcon() {
- QString iconString;
- switch (statusShowType_) {
- case StatusShow::Online: iconString = "online";break;
- case StatusShow::Away: iconString = "away";break;
- case StatusShow::XA: iconString = "away";break;
- case StatusShow::FFC: iconString = "online";break;
- case StatusShow::DND: iconString = "dnd";break;
- case StatusShow::None: iconString = "offline";break;
- }
- return QIcon(":/icons/" + iconString + ".png");
-}
-
-bool QtTreeWidgetItem::isContact() const {
- return children_.size() == 0;
-}
-
-bool QtTreeWidgetItem::isExpanded() {
- return expanded_;
-}
-
-bool QtTreeWidgetItem::operator<(const QtTreeWidgetItem& item) const {
- if (isContact()) {
- if (!item.isContact()) {
- return false;
- }
- return getStatusShowMerged() == item.getStatusShowMerged() ? getLowerName() < item.getLowerName() : getStatusShowMerged() < item.getStatusShowMerged();
- } else {
- if (item.isContact()) {
- return true;
- }
- return getLowerName() < item.getLowerName();
- }
-}
-
-bool itemLessThan(QtTreeWidgetItem* left, QtTreeWidgetItem* right) {
- return *left < *right;
-}
-
-}
diff --git a/Swift/QtUI/Roster/QtTreeWidgetItem.h b/Swift/QtUI/Roster/QtTreeWidgetItem.h
deleted file mode 100644
index 6855989..0000000
--- a/Swift/QtUI/Roster/QtTreeWidgetItem.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <QColor>
-#include <QVariant>
-#include <string>
-
-#include "Swiften/Roster/TreeWidgetFactory.h"
-#include "Swiften/Roster/TreeWidget.h"
-#include "Swiften/Roster/TreeWidgetItem.h"
-#include "Swift/QtUI/QtSwiftUtil.h"
-
-namespace Swift {
- enum RosterRoles {
- StatusTextRole = Qt::UserRole,
- AvatarRole = Qt::UserRole + 1,
- PresenceIconRole = Qt::UserRole + 2,
- StatusShowTypeRole = Qt::UserRole + 3
- };
-
-class QtTreeWidget;
-class QtTreeWidgetItem : public QObject, public TreeWidgetItem {
- Q_OBJECT
- public:
- ~QtTreeWidgetItem();
- void addChild(QtTreeWidgetItem* child);
- void removeChild(QtTreeWidgetItem* child);
- QtTreeWidgetItem* getParentItem();
- int rowCount();
- int rowOf(QtTreeWidgetItem* item);
- int row();
- QtTreeWidgetItem* getItem(int row);
- QVariant data(int role);
- QIcon getPresenceIcon();
- QtTreeWidgetItem(QtTreeWidgetItem* parentItem);
- void setText(const std::string& text);
- void setAvatarPath(const std::string& path);
- void setStatusText(const std::string& text);
- void setStatusShow(StatusShow::Type show);
- void setTextColor(unsigned long color);
- void setBackgroundColor(unsigned long color);
- void setExpanded(bool b);
- void parentItemHasBeenDeleted();
- void hide();
- void show();
- bool isShown();
- bool isContact() const;
- bool isExpanded();
- const QString& getName() const {return displayName_;};
- const QString& getLowerName() const {return displayNameLower_;};
- StatusShow::Type getStatusShow() const {return statusShowType_;};
- StatusShow::Type getStatusShowMerged() const {return mergedShowType_;};
-
- QWidget* getCollapsedRosterWidget();
- QWidget* getExpandedRosterWidget();
- bool operator<(const QtTreeWidgetItem& item) const;
-
- signals:
- void changed(QtTreeWidgetItem*);
- private slots:
- void handleChanged(QtTreeWidgetItem* item);
- private:
- QString toolTipString();
- QList<QtTreeWidgetItem*> children_;
- QList<QtTreeWidgetItem*> shownChildren_;
- QtTreeWidgetItem* parent_;
- QString displayName_;
- QString displayNameLower_;
- QString statusText_;
- QColor textColor_;
- QColor backgroundColor_;
- QVariant avatar_;
- bool shown_;
- bool expanded_;
- StatusShow::Type statusShowType_;
- StatusShow::Type mergedShowType_;
-};
-
-bool itemLessThan(QtTreeWidgetItem* left, QtTreeWidgetItem* right);
-
-}
diff --git a/Swift/QtUI/Roster/RosterDelegate.cpp b/Swift/QtUI/Roster/RosterDelegate.cpp
index aaa6236..e40907a 100644
--- a/Swift/QtUI/Roster/RosterDelegate.cpp
+++ b/Swift/QtUI/Roster/RosterDelegate.cpp
@@ -12,7 +12,6 @@
#include <QBrush>
#include <QFontMetrics>
#include <QPainterPath>
-#include <QFileInfo>
#include <QPolygon>
#include <qdebug.h>
#include <QBitmap>
@@ -22,7 +21,6 @@
#include "QtTreeWidget.h"
#include "RosterModel.h"
-#include "QtScaledAvatarCache.h"
namespace Swift {
@@ -43,15 +41,8 @@ QSize RosterDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelI
return contactSizeHint(option, index);
}
-QSize RosterDelegate::contactSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const {
- int heightByAvatar = avatarSize_ + common_.verticalMargin * 2;
- QFontMetrics nameMetrics(common_.nameFont);
- QFontMetrics statusMetrics(common_.detailFont);
- int sizeByText = 2 * common_.verticalMargin + nameMetrics.height() + statusMetrics.height();
- //Doesn't work, yay! FIXME: why?
- //QSize size = (option.state & QStyle::State_Selected) ? QSize(150, 80) : QSize(150, avatarSize_ + margin_ * 2);
- //qDebug() << "Returning size" << size;
- return QSize(150, sizeByText > heightByAvatar ? sizeByText : heightByAvatar);
+QSize RosterDelegate::contactSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index ) const {
+ return common_.contactSizeHint(option, index);
}
void RosterDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
@@ -70,70 +61,18 @@ void RosterDelegate::paintGroup(QPainter* painter, const QStyleOptionViewItem& o
}
void RosterDelegate::paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
- //qDebug() << "painting" << index.data(Qt::DisplayRole).toString();
- painter->save();
- //QStyledItemDelegate::paint(painter, option, index);
- //initStyleOption(option, index);
- QRect fullRegion(option.rect);
- if ( option.state & QStyle::State_Selected ) {
- painter->fillRect(fullRegion, option.palette.highlight());
- painter->setPen(option.palette.highlightedText().color());
- } else {
- QColor nameColor = index.data(Qt::TextColorRole).value<QColor>();
- painter->setPen(QPen(nameColor));
- }
-
- QRect presenceIconRegion(QPoint(common_.farLeftMargin, fullRegion.top()), QSize(presenceIconWidth_, fullRegion.height() - common_.verticalMargin));
-
- int calculatedAvatarSize = presenceIconRegion.height();
- //This overlaps the presenceIcon, so must be painted first
- QRect avatarRegion(QPoint(presenceIconRegion.right() - presenceIconWidth_ / 2, presenceIconRegion.top()), QSize(calculatedAvatarSize, calculatedAvatarSize));
-
- QPixmap avatarPixmap;
+ QColor nameColor = index.data(Qt::TextColorRole).value<QColor>();
+ QString avatarPath;
if (index.data(AvatarRole).isValid() && !index.data(AvatarRole).value<QString>().isNull()) {
- QString avatarPath = index.data(AvatarRole).value<QString>();
- QString scaledAvatarPath = QtScaledAvatarCache(avatarRegion.height()).getScaledAvatarPath(avatarPath);
- if (QFileInfo(scaledAvatarPath).exists()) {
- avatarPixmap.load(scaledAvatarPath);
- }
+ avatarPath = index.data(AvatarRole).value<QString>();
}
- if (avatarPixmap.isNull()) {
- avatarPixmap = QPixmap(":/icons/avatar.png").scaled(avatarRegion.height(), avatarRegion.width(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
- }
-
- painter->drawPixmap(avatarRegion.topLeft() + QPoint(((avatarRegion.width() - avatarPixmap.width()) / 2), (avatarRegion.height() - avatarPixmap.height()) / 2), avatarPixmap);
-
- //Paint the presence icon over the top of the avatar
QIcon presenceIcon = index.data(PresenceIconRole).isValid() && !index.data(PresenceIconRole).value<QIcon>().isNull()
- ? index.data(PresenceIconRole).value<QIcon>()
- : QIcon(":/icons/offline.png");
- presenceIcon.paint(painter, presenceIconRegion, Qt::AlignBottom | Qt::AlignHCenter);
-
- QFontMetrics nameMetrics(common_.nameFont);
- painter->setFont(common_.nameFont);
- int extraFontWidth = nameMetrics.width("H");
- int leftOffset = avatarRegion.right() + common_.horizontalMargin * 2 + extraFontWidth / 2;
- QRect textRegion(fullRegion.adjusted(leftOffset, 0, 0/*-leftOffset*/, 0));
-
- int nameHeight = nameMetrics.height() + common_.verticalMargin;
- QRect nameRegion(textRegion.adjusted(0, common_.verticalMargin, 0, 0));
-
- DelegateCommons::drawElidedText(painter, nameRegion, index.data(Qt::DisplayRole).toString());
-
-
- painter->setFont(common_.detailFont);
- painter->setPen(QPen(QColor(160,160,160)));
-
- QRect statusTextRegion(textRegion.adjusted(0, nameHeight, 0, 0));
- DelegateCommons::drawElidedText(painter, statusTextRegion, index.data(StatusTextRole).toString());
-
- painter->restore();
+ ? index.data(PresenceIconRole).value<QIcon>()
+ : QIcon(":/icons/offline.png");
+ QString name = index.data(Qt::DisplayRole).toString();
+ QString statusText = index.data(StatusTextRole).toString();
+ common_.paintContact(painter, option, nameColor, avatarPath, presenceIcon, name, statusText, 0);
}
-
-const int RosterDelegate::avatarSize_ = 20;
-const int RosterDelegate::presenceIconHeight_ = 16;
-const int RosterDelegate::presenceIconWidth_ = 16;
-
}
diff --git a/Swift/QtUI/Roster/RosterDelegate.h b/Swift/QtUI/Roster/RosterDelegate.h
index e6a16f2..253c11a 100644
--- a/Swift/QtUI/Roster/RosterDelegate.h
+++ b/Swift/QtUI/Roster/RosterDelegate.h
@@ -28,9 +28,5 @@ namespace Swift {
DelegateCommons common_;
GroupItemDelegate* groupDelegate_;
QtTreeWidget* tree_;
- static const int avatarSize_;
- static const int presenceIconHeight_;
- static const int presenceIconWidth_;
-
};
}
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 494731c..24299fb 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -25,16 +25,12 @@ myenv.MergeFlags(env["SWIFT_CONTROLLERS_FLAGS"])
myenv.MergeFlags(env["SWIFTOOLS_FLAGS"])
if myenv["HAVE_XSS"] :
myenv.MergeFlags(env["XSS_FLAGS"])
+if env["PLATFORM"] == "posix" :
+ myenv.Append(LIBS = ["X11"])
if myenv["HAVE_SPARKLE"] :
myenv.MergeFlags(env["SPARKLE_FLAGS"])
myenv.MergeFlags(env["SWIFTEN_FLAGS"])
-myenv.MergeFlags(env["LIBIDN_FLAGS"])
-myenv.MergeFlags(env["BOOST_FLAGS"])
-myenv.MergeFlags(env.get("SQLITE_FLAGS", {}))
-myenv.MergeFlags(env["ZLIB_FLAGS"])
-myenv.MergeFlags(env["OPENSSL_FLAGS"])
-myenv.MergeFlags(env.get("LIBXML_FLAGS", ""))
-myenv.MergeFlags(env.get("EXPAT_FLAGS", ""))
+myenv.MergeFlags(env["SWIFTEN_DEP_FLAGS"])
if myenv.get("HAVE_GROWL", False) :
myenv.MergeFlags(myenv["GROWL_FLAGS"])
myenv.Append(CPPDEFINES = ["HAVE_GROWL"])
@@ -59,7 +55,7 @@ if env["PLATFORM"] == "win32" :
myenv.Append(LINKFLAGS = ["/SUBSYSTEM:WINDOWS"])
myenv.Append(LIBS = "qtmain")
-myenv.WriteVal("DefaultTheme.qrc", myenv.Value(generateDefaultTheme(myenv.Dir("../resources/themes/Default"))))
+myenv.WriteVal("DefaultTheme.qrc", myenv.Value(generateDefaultTheme(myenv.Dir("#/Swift/resources/themes/Default"))))
sources = [
"main.cpp",
@@ -77,6 +73,7 @@ sources = [
"QtStatusWidget.cpp",
"QtScaledAvatarCache.cpp",
"QtSwift.cpp",
+ "QtURIHandler.cpp",
"QtChatView.cpp",
"QtChatTheme.cpp",
"QtChatTabs.cpp",
@@ -87,6 +84,7 @@ sources = [
"QtTabWidget.cpp",
"QtTextEdit.cpp",
"QtXMLConsoleWidget.cpp",
+ "QtAdHocCommandWindow.cpp",
"QtUtilities.cpp",
"QtBookmarkDetailWindow.cpp",
"QtAddBookmarkWindow.cpp",
@@ -97,6 +95,7 @@ sources = [
"MessageSnippet.cpp",
"SystemMessageSnippet.cpp",
"QtElidingLabel.cpp",
+ "QtFormWidget.cpp",
"QtLineEdit.cpp",
"QtJoinMUCWindow.cpp",
"Roster/RosterModel.cpp",
@@ -114,6 +113,7 @@ sources = [
"ChatList/ChatListModel.cpp",
"ChatList/ChatListDelegate.cpp",
"ChatList/ChatListMUCItem.cpp",
+ "ChatList/ChatListRecentItem.cpp",
"MUCSearch/QtMUCSearchWindow.cpp",
"MUCSearch/MUCSearchModel.cpp",
"MUCSearch/MUCSearchRoomItem.cpp",
@@ -136,20 +136,31 @@ sources = [
myenv["SWIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift")
if env["PLATFORM"] == "win32" :
- myenv.RES("../resources/Windows/Swift.rc")
+ res = myenv.RES("#/Swift/resources/Windows/Swift.rc")
+ # For some reason, SCons isn't picking up the dependency correctly
+ # Adding it explicitly until i figure out why
+ myenv.Depends(res, "../Controllers/BuildVersion.h")
sources += [
"WindowsNotifier.cpp",
- "../resources/Windows/Swift.res"
+ "#/Swift/resources/Windows/Swift.res"
]
if env["PLATFORM"] == "posix" :
- sources += ["FreeDesktopNotifier.cpp"]
+ sources += [
+ "FreeDesktopNotifier.cpp",
+ "QtDBUSURIHandler.cpp",
+ ]
if env["PLATFORM"] == "darwin" or env["PLATFORM"] == "win32" :
swiftProgram = myenv.Program("Swift", sources)
else :
swiftProgram = myenv.Program("swift", sources)
+if env["PLATFORM"] != "darwin" and env["PLATFORM"] != "win32" :
+ openURIProgram = myenv.Program("swift-open-uri", "swift-open-uri.cpp")
+else :
+ openURIProgram = []
+
myenv.Uic4("MUCSearch/QtMUCSearchWindow.ui")
myenv.Uic4("UserSearch/QtUserSearchWizard.ui")
myenv.Uic4("UserSearch/QtUserSearchFirstPage.ui")
@@ -162,7 +173,7 @@ myenv.Qrc("Swift.qrc")
# Resources
commonResources = {
- "": ["../resources/sounds"]
+ "": ["#/Swift/resources/sounds"]
}
################################################################################
@@ -171,16 +182,16 @@ commonResources = {
# Collect available languages
translation_languages = []
-for file in os.listdir(Dir("../Translations").abspath) :
+for file in os.listdir(Dir("#/Swift/Translations").abspath) :
if file.startswith("swift_") and file.endswith(".ts") :
translation_languages.append(file[6:-3])
# Generate translation modules
-translation_sources = [env.File("../Translations/swift.ts").abspath]
+translation_sources = [env.File("#/Swift/Translations/swift.ts").abspath]
translation_modules = []
for lang in translation_languages :
- translation_resource = "../resources/translations/swift_" + lang + ".qm"
- translation_source = "../Translations/swift_" + lang + ".ts"
+ translation_resource = "#/Swift/resources/translations/swift_" + lang + ".qm"
+ translation_source = "#/Swift/Translations/swift_" + lang + ".ts"
translation_sources.append(env.File(translation_source).abspath)
translation_modules.append(env.File(translation_resource).abspath)
myenv.Qm(translation_resource, translation_source)
@@ -214,20 +225,20 @@ if env["PLATFORM"] == "darwin" :
frameworks.append(env["SPARKLE_FRAMEWORK"])
if env["HAVE_GROWL"] :
frameworks.append(env["GROWL_FRAMEWORK"])
- commonResources[""] = commonResources.get("", []) + ["../resources/MacOSX/Swift.icns"]
- app = myenv.AppBundle("Swift", version = myenv["SWIFT_VERSION"], resources = commonResources, frameworks = frameworks)
+ commonResources[""] = commonResources.get("", []) + ["#/Swift/resources/MacOSX/Swift.icns"]
+ app = myenv.AppBundle("Swift", version = myenv["SWIFT_VERSION"], resources = commonResources, frameworks = frameworks, handlesXMPPURIs = True)
if env["DIST"] :
myenv.Command(["Swift-${SWIFT_VERSION}.dmg"], [app], ["Swift/Packaging/MacOSX/package.sh " + app.path + " Swift/Packaging/MacOSX/Swift.dmg.gz $TARGET $QTDIR"])
if env.get("SWIFT_INSTALLDIR", "") :
- env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "bin"), swiftProgram)
- env.InstallAs(os.path.join(env["SWIFT_INSTALLDIR"], "share", "pixmaps", "swift.xpm"), "../resources/logo/logo-icon-32.xpm")
+ env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "bin"), swiftProgram + openURIProgram)
+ env.InstallAs(os.path.join(env["SWIFT_INSTALLDIR"], "share", "pixmaps", "swift.xpm"), "#/Swift/resources/logo/logo-icon-32.xpm")
icons_path = os.path.join(env["SWIFT_INSTALLDIR"], "share", "icons", "hicolor")
- env.InstallAs(os.path.join(icons_path, "32x32", "apps", "swift.xpm"), "../resources/logo/logo-icon-32.xpm")
- env.InstallAs(os.path.join(icons_path, "scalable", "apps", "swift.svg"), "../resources/logo/logo-icon.svg")
+ env.InstallAs(os.path.join(icons_path, "32x32", "apps", "swift.xpm"), "#/Swift/resources/logo/logo-icon-32.xpm")
+ env.InstallAs(os.path.join(icons_path, "scalable", "apps", "swift.svg"), "#/Swift/resources/logo/logo-icon.svg")
for i in ["16", "22", "24", "64", "128"] :
- env.InstallAs(os.path.join(icons_path, i + "x" + i, "apps", "swift.png"), "../resources/logo/logo-icon-" + i + ".png")
- env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "share", "applications"), "../resources/swift.desktop")
+ env.InstallAs(os.path.join(icons_path, i + "x" + i, "apps", "swift.png"), "#/Swift/resources/logo/logo-icon-" + i + ".png")
+ env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "share", "applications"), "#/Swift/resources/swift.desktop")
for dir, resource in commonResources.items() :
env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "share", "swift", dir), resource)
@@ -236,7 +247,7 @@ if env["PLATFORM"] == "win32" :
commonResources[""] = commonResources.get("", []) + [
os.path.join(env["OPENSSL_DIR"], "bin", "ssleay32.dll"),
os.path.join(env["OPENSSL_DIR"], "bin", "libeay32.dll"),
- "../resources/images",
+ "#/Swift/resources/images",
]
myenv.WindowsBundle("Swift",
resources = commonResources,
diff --git a/Swift/QtUI/main.cpp b/Swift/QtUI/main.cpp
index 0146769..2eef379 100644
--- a/Swift/QtUI/main.cpp
+++ b/Swift/QtUI/main.cpp
@@ -44,7 +44,7 @@ int main(int argc, char* argv[]) {
boost::program_options::variables_map vm;
try {
boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
- } catch (boost::program_options::unknown_option option) {
+ } catch (const boost::program_options::unknown_option& option) {
#if BOOST_VERSION >= 104200
std::cout << "Ignoring unknown option " << option.get_option_name() << " but continuing." << std::endl;
#else
diff --git a/Swift/QtUI/swift-open-uri.cpp b/Swift/QtUI/swift-open-uri.cpp
new file mode 100644
index 0000000..2d5ef19
--- /dev/null
+++ b/Swift/QtUI/swift-open-uri.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <QCoreApplication>
+#include <QDBusConnection>
+#include <QDBusMessage>
+#include <iostream>
+
+int main(int argc, char* argv[]) {
+ QCoreApplication app(argc, argv);
+
+ QDBusConnection bus = QDBusConnection::sessionBus();
+ if (!bus.isConnected()) {
+ return -1;
+ }
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " uri" << std::endl;
+ return -1;
+ }
+
+ QDBusMessage msg = QDBusMessage::createMethodCall("im.swift.Swift.URIHandler", "/", "im.swift.Swift.URIHandler", "openURI");
+ msg << argv[1];
+
+ bus.call(msg);
+
+ return 0;
+}