From b566cac68d7bb91f726b5353318b3a5eddd8f3c2 Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Fri, 30 Apr 2010 16:56:33 +0000
Subject: Support adding/removing bookmarks from the UI

Doesn't support editing meaningfully, nor do changes get saved.

diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 6aacdbd..d0b4716 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -15,6 +15,9 @@
 #include "Swift/Controllers/Chat/MUCController.h"
 #include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
 #include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
+#include "Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h"
+#include "Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h"
+#include "Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h"
 #include "Swift/Controllers/UIInterfaces/ChatListWindowFactory.h"
 #include "Swiften/Presence/PresenceSender.h"
 #include "Swiften/Elements/ChatState.h"
@@ -83,10 +86,27 @@ void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) {
 	boost::shared_ptr<RequestChatUIEvent> chatEvent = boost::dynamic_pointer_cast<RequestChatUIEvent>(event);
 	if (chatEvent) {
 		handleChatRequest(chatEvent->getContact());
+		return;
 	}
 	boost::shared_ptr<JoinMUCUIEvent> joinMUCEvent = boost::dynamic_pointer_cast<JoinMUCUIEvent>(event);
 	if (joinMUCEvent) {
 		handleJoinMUCRequest(joinMUCEvent->getJID(), joinMUCEvent->getNick());
+		return;
+	}
+	boost::shared_ptr<RemoveMUCBookmarkUIEvent> removeMUCBookmarkEvent = boost::dynamic_pointer_cast<RemoveMUCBookmarkUIEvent>(event);
+	if (removeMUCBookmarkEvent) {
+		mucBookmarkManager_->removeBookmark(removeMUCBookmarkEvent->getBookmark());
+		return;
+	}
+	boost::shared_ptr<AddMUCBookmarkUIEvent> addMUCBookmarkEvent = boost::dynamic_pointer_cast<AddMUCBookmarkUIEvent>(event);
+	if (addMUCBookmarkEvent) {
+		mucBookmarkManager_->addBookmark(addMUCBookmarkEvent->getBookmark());
+		return;
+	}
+	boost::shared_ptr<EditMUCBookmarkUIEvent> editMUCBookmarkEvent = boost::dynamic_pointer_cast<EditMUCBookmarkUIEvent>(event);
+	if (editMUCBookmarkEvent) {
+		mucBookmarkManager_->replaceBookmark(editMUCBookmarkEvent->getOldBookmark(), editMUCBookmarkEvent->getNewBookmark());
+		return;
 	}
 }
 
diff --git a/Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h b/Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h
new file mode 100644
index 0000000..715798b
--- /dev/null
+++ b/Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include "Swift/Controllers/UIEvents/UIEvent.h"
+#include "Swiften/MUC/MUCBookmark.h"
+
+namespace Swift {
+	class AddMUCBookmarkUIEvent : public UIEvent {
+		public:
+			AddMUCBookmarkUIEvent(const boost::shared_ptr<MUCBookmark> bookmark) : bookmark_(bookmark) {};
+			boost::shared_ptr<MUCBookmark> getBookmark() {return bookmark_;};
+		private:
+			boost::shared_ptr<MUCBookmark> bookmark_;
+	};
+}
diff --git a/Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h b/Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h
new file mode 100644
index 0000000..bcbcb76
--- /dev/null
+++ b/Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include "Swift/Controllers/UIEvents/UIEvent.h"
+#include "Swiften/MUC/MUCBookmark.h"
+
+namespace Swift {
+	class EditMUCBookmarkUIEvent : public UIEvent {
+		public:
+			EditMUCBookmarkUIEvent(const boost::shared_ptr<MUCBookmark> oldBookmark, const boost::shared_ptr<MUCBookmark> newBookmark) : oldBookmark_(oldBookmark) , newBookmark_(newBookmark) {};
+			boost::shared_ptr<MUCBookmark> getOldBookmark() {return oldBookmark_;};
+			boost::shared_ptr<MUCBookmark> getNewBookmark() {return newBookmark_;};
+		private:
+			boost::shared_ptr<MUCBookmark> oldBookmark_;
+			boost::shared_ptr<MUCBookmark> newBookmark_;
+	};
+}
diff --git a/Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h b/Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h
new file mode 100644
index 0000000..4a59b2c
--- /dev/null
+++ b/Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include "Swift/Controllers/UIEvents/UIEvent.h"
+#include "Swiften/MUC/MUCBookmark.h"
+
+namespace Swift {
+	class RemoveMUCBookmarkUIEvent : public UIEvent {
+		public:
+			RemoveMUCBookmarkUIEvent(const boost::shared_ptr<MUCBookmark> bookmark) : bookmark_(bookmark) {};
+			boost::shared_ptr<MUCBookmark> getBookmark() {return bookmark_;};
+		private:
+			boost::shared_ptr<MUCBookmark> bookmark_;
+	};
+}
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.cpp b/Swift/QtUI/ChatList/QtChatListWindow.cpp
index 793d89a..7d307f9 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.cpp
+++ b/Swift/QtUI/ChatList/QtChatListWindow.cpp
@@ -5,8 +5,17 @@
  */
 
 #include "Swift/QtUI/ChatList/QtChatListWindow.h"
+
+#include <QMenu>
+#include <QContextMenuEvent>
+
 #include "Swift/QtUI/ChatList/ChatListMUCItem.h"
+#include "Swift/QtUI/QtAddBookmarkWindow.h"
+#include "Swift/QtUI/QtEditBookmarkWindow.h"
 #include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
+#include "Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h"
+#include "Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h"
+#include "Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h"
 
 namespace Swift {
 
@@ -23,12 +32,25 @@ QtChatListWindow::QtChatListWindow(UIEventStream *uiEventStream, QWidget* parent
 	setAnimated(true);
 	setIndentation(0);
 	setRootIsDecorated(true);
+	setupContextMenus();
 	connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleItemActivated(const QModelIndex&)));
 }
 
 QtChatListWindow::~QtChatListWindow() {
 	delete model_;
 	delete delegate_;
+	delete mucMenu_;
+	delete emptyMenu_;
+}
+
+void QtChatListWindow::setupContextMenus() {
+	mucMenu_ = new QMenu();
+	mucMenu_->addAction("Add New Bookmark", this, SLOT(handleAddBookmark()));
+	mucMenu_->addAction("Edit Bookmark", this, SLOT(handleEditBookmark()));
+	mucMenu_->addAction("Remove Bookmark", this, SLOT(handleRemoveBookmark()));
+	emptyMenu_ = new QMenu();
+	emptyMenu_->addAction("Add New Bookmark", this, SLOT(handleAddBookmark()));
+	
 }
 
 void QtChatListWindow::handleItemActivated(const QModelIndex& index) {
@@ -48,4 +70,37 @@ void QtChatListWindow::removeMUCBookmark(boost::shared_ptr<MUCBookmark> bookmark
 	model_->removeMUCBookmark(bookmark);
 }
 
+void QtChatListWindow::handleRemoveBookmark() {
+	ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(contextMenuItem_);
+	if (!mucItem) return;
+	eventStream_->send(boost::shared_ptr<UIEvent>(new RemoveMUCBookmarkUIEvent(mucItem->getBookmark())));
+}
+
+void QtChatListWindow::handleAddBookmark() {
+	(new QtAddBookmarkWindow(eventStream_))->show();
+}
+
+
+void QtChatListWindow::handleEditBookmark() {
+	ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(contextMenuItem_);
+	if (!mucItem) return;
+	QtEditBookmarkWindow* window = new QtEditBookmarkWindow(eventStream_, mucItem->getBookmark());
+	window->show();
+}
+
+
+void QtChatListWindow::contextMenuEvent(QContextMenuEvent* event) {
+	QModelIndex index = indexAt(event->pos());
+	ChatListItem* baseItem = index.isValid() ? static_cast<ChatListItem*>(index.internalPointer()) : NULL;
+	contextMenuItem_ = baseItem;
+	if (!baseItem) {
+		emptyMenu_->exec(QCursor::pos());
+		return;
+	}
+	ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(baseItem);
+	if (mucItem) {
+		mucMenu_->exec(QCursor::pos());
+	}
+}
+
 }
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.h b/Swift/QtUI/ChatList/QtChatListWindow.h
index af4d3bf..2055e6b 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.h
+++ b/Swift/QtUI/ChatList/QtChatListWindow.h
@@ -12,6 +12,7 @@
 #include "Swift/Controllers/UIEvents/UIEventStream.h"
 #include "Swift/QtUI/ChatList/ChatListModel.h"
 #include "Swift/QtUI/ChatList/ChatListDelegate.h"
+#include "Swift/QtUI/ContextMenus/QtContextMenu.h"
 
 namespace Swift {
 
@@ -24,10 +25,21 @@ namespace Swift {
 			void removeMUCBookmark(boost::shared_ptr<MUCBookmark> bookmark);
 		private slots:
 			void handleItemActivated(const QModelIndex&);
+			void handleAddBookmark();
+			void handleEditBookmark();
+			void handleRemoveBookmark();
+
+		protected:
+			void contextMenuEvent(QContextMenuEvent* event);
 		private:
+			void setupContextMenus();
 			UIEventStream* eventStream_;
 			ChatListModel* model_;
 			ChatListDelegate* delegate_;
+			QtContextMenu* contextMenu_;
+			QMenu* mucMenu_;
+			QMenu* emptyMenu_;
+			ChatListItem* contextMenuItem_;
 	};
 
 }
diff --git a/Swift/QtUI/QtAddBookmarkWindow.cpp b/Swift/QtUI/QtAddBookmarkWindow.cpp
new file mode 100644
index 0000000..863e98c
--- /dev/null
+++ b/Swift/QtUI/QtAddBookmarkWindow.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "QtAddBookmarkWindow.h"
+
+#include <qdebug.h>
+
+namespace Swift {
+QtAddBookmarkWindow::QtAddBookmarkWindow(UIEventStream* eventStream) : eventStream_(eventStream) {
+
+}
+
+void QtAddBookmarkWindow::commit() {
+	qDebug() << "committing";
+	eventStream_->send(boost::shared_ptr<UIEvent>(new AddMUCBookmarkUIEvent(createBookmarkFromForm())));
+}
+
+}
diff --git a/Swift/QtUI/QtAddBookmarkWindow.h b/Swift/QtUI/QtAddBookmarkWindow.h
new file mode 100644
index 0000000..8e33180
--- /dev/null
+++ b/Swift/QtUI/QtAddBookmarkWindow.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "QtBookmarkDetailWindow.h"
+
+#include "Swift/Controllers/UIEvents/UIEventStream.h"
+#include "Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h"
+
+namespace Swift {
+	class QtAddBookmarkWindow : public QtBookmarkDetailWindow {
+		Q_OBJECT
+		public:
+			QtAddBookmarkWindow(UIEventStream* eventStream);
+			void commit();
+		private:
+			UIEventStream* eventStream_;
+	};
+}
diff --git a/Swift/QtUI/QtAddContactDialog.cpp b/Swift/QtUI/QtAddContactDialog.cpp
index a5f5a10..6cd26ad 100644
--- a/Swift/QtUI/QtAddContactDialog.cpp
+++ b/Swift/QtUI/QtAddContactDialog.cpp
@@ -13,8 +13,8 @@ QtAddContactDialog::QtAddContactDialog(QWidget* parent) : QDialog(parent) {
 	setupUi(this);
 	errorLabel_->hide();
 	setAttribute(Qt::WA_DeleteOnClose, true);
-	connect(buttons_, SIGNAL(accepted()), SLOT(accept()));
-	connect(buttons_, SIGNAL(rejected()), SLOT(reject()));
+//	connect(buttons_, SIGNAL(accepted()), SLOT(accept()));
+//	connect(buttons_, SIGNAL(rejected()), SLOT(reject()));
 }
 
 void QtAddContactDialog::accept() {
diff --git a/Swift/QtUI/QtBookmarkDetailWindow.cpp b/Swift/QtUI/QtBookmarkDetailWindow.cpp
new file mode 100644
index 0000000..ef524c3
--- /dev/null
+++ b/Swift/QtUI/QtBookmarkDetailWindow.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "QtBookmarkDetailWindow.h"
+#include "QtSwiftUtil.h"
+
+namespace Swift {
+
+QtBookmarkDetailWindow::QtBookmarkDetailWindow(QWidget* parent) : QDialog(parent) {
+	setupUi(this);
+	setAttribute(Qt::WA_DeleteOnClose, true);
+	//connect(buttons_, SIGNAL(accepted()), SLOT(accept()));
+	//connect(buttons_, SIGNAL(rejected()), SLOT(reject()));
+}
+
+void QtBookmarkDetailWindow::accept() {
+	commit();
+	QDialog::accept();
+}
+
+boost::shared_ptr<MUCBookmark> QtBookmarkDetailWindow::createBookmarkFromForm() {
+	//check room
+	//check bookmarkName
+	JID room(Q2PSTRING(room_->text()));
+	String name(Q2PSTRING(name_->text()));
+	String nick(Q2PSTRING(nick_->text()));
+	String password(Q2PSTRING(password_->text()));
+	bool autojoin = autojoin_->isChecked();
+	boost::shared_ptr<MUCBookmark> bookmark(new MUCBookmark(room, name));
+	if (!nick.isEmpty()) {
+		bookmark->setNick(nick);
+	}
+	if (!password.isEmpty()) {
+		bookmark->setPassword(password);
+	}
+	bookmark->setAutojoin(autojoin);
+	return bookmark;
+}
+
+}
diff --git a/Swift/QtUI/QtBookmarkDetailWindow.h b/Swift/QtUI/QtBookmarkDetailWindow.h
new file mode 100644
index 0000000..82bfe9b
--- /dev/null
+++ b/Swift/QtUI/QtBookmarkDetailWindow.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "ui_QtBookmarkDetailWindow.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <QDialog>
+
+#include "Swiften/MUC/MUCBookmark.h"
+
+namespace Swift {
+	class QtBookmarkDetailWindow : public QDialog, protected Ui::QtBookmarkDetailWindow {
+		Q_OBJECT
+		public:
+			QtBookmarkDetailWindow(QWidget* parent = NULL);
+			virtual void commit() = 0;
+			boost::shared_ptr<MUCBookmark> createBookmarkFromForm();
+		public slots:
+			void accept();
+	};
+}
+
diff --git a/Swift/QtUI/QtBookmarkDetailWindow.ui b/Swift/QtUI/QtBookmarkDetailWindow.ui
new file mode 100644
index 0000000..4d9d472
--- /dev/null
+++ b/Swift/QtUI/QtBookmarkDetailWindow.ui
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtBookmarkDetailWindow</class>
+ <widget class="QDialog" name="QtBookmarkDetailWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>396</width>
+    <height>282</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>false</bool>
+  </property>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>10</x>
+     <y>20</y>
+     <width>371</width>
+     <height>241</height>
+    </rect>
+   </property>
+   <layout class="QVBoxLayout" name="verticalLayout">
+    <item>
+     <layout class="QFormLayout" name="formLayout">
+      <item row="0" column="0">
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>Bookmark Name</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QLineEdit" name="name_"/>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Room JID</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QLineEdit" name="room_"/>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Your Nickname</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QLineEdit" name="nick_"/>
+      </item>
+      <item row="3" column="0">
+       <widget class="QLabel" name="label_4">
+        <property name="text">
+         <string>Room password</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="1">
+       <widget class="QLineEdit" name="password_"/>
+      </item>
+      <item row="4" column="0">
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="4" column="1">
+       <widget class="QCheckBox" name="autojoin_">
+        <property name="text">
+         <string>Join automatically</string>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item>
+     <widget class="QDialogButtonBox" name="buttons_">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <property name="standardButtons">
+       <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttons_</sender>
+   <signal>accepted()</signal>
+   <receiver>QtBookmarkDetailWindow</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttons_</sender>
+   <signal>rejected()</signal>
+   <receiver>QtBookmarkDetailWindow</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/Swift/QtUI/QtEditBookmarkWindow.cpp b/Swift/QtUI/QtEditBookmarkWindow.cpp
new file mode 100644
index 0000000..016f17e
--- /dev/null
+++ b/Swift/QtUI/QtEditBookmarkWindow.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "QtEditBookmarkWindow.h"
+
+namespace Swift {
+QtEditBookmarkWindow::QtEditBookmarkWindow(UIEventStream* eventStream, boost::shared_ptr<MUCBookmark> bookmark) : eventStream_(eventStream), bookmark_(bookmark) {
+
+}
+
+void QtEditBookmarkWindow::commit() {
+	eventStream_->send(boost::shared_ptr<UIEvent>(new EditMUCBookmarkUIEvent(bookmark_, createBookmarkFromForm())));
+}
+
+}
+
diff --git a/Swift/QtUI/QtEditBookmarkWindow.h b/Swift/QtUI/QtEditBookmarkWindow.h
new file mode 100644
index 0000000..3c11fbe
--- /dev/null
+++ b/Swift/QtUI/QtEditBookmarkWindow.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+#include "QtBookmarkDetailWindow.h"
+
+#include "Swift/Controllers/UIEvents/UIEventStream.h"
+#include "Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h"
+
+namespace Swift {
+	class QtEditBookmarkWindow : public QtBookmarkDetailWindow {
+		Q_OBJECT
+		public:
+			QtEditBookmarkWindow(UIEventStream* eventStream, boost::shared_ptr<MUCBookmark> bookmark);
+			void commit();
+	
+		private:
+			UIEventStream* eventStream_;
+			boost::shared_ptr<MUCBookmark> bookmark_;
+	};
+}
diff --git a/Swift/QtUI/QtJoinMUCDialog.cpp b/Swift/QtUI/QtJoinMUCDialog.cpp
index d459947..694ce32 100644
--- a/Swift/QtUI/QtJoinMUCDialog.cpp
+++ b/Swift/QtUI/QtJoinMUCDialog.cpp
@@ -13,8 +13,8 @@ QtJoinMUCDialog::QtJoinMUCDialog(const QString&, const QString&, QWidget* parent
 	setupUi(this);
 	errorLabel_->hide();
 	setAttribute(Qt::WA_DeleteOnClose, true);
-	connect(buttons_, SIGNAL(accepted()), SLOT(accept()));
-	connect(buttons_, SIGNAL(rejected()), SLOT(reject()));
+//	connect(buttons_, SIGNAL(accepted()), SLOT(accept()));
+//	connect(buttons_, SIGNAL(rejected()), SLOT(reject()));
 }
 
 void QtJoinMUCDialog::accept() {
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index af7dd68..b4f8f64 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -72,6 +72,9 @@ sources = [
     "QtXMLConsoleWidgetFactory.cpp",
     "QtXMLConsoleWidget.cpp",
     "QtUtilities.cpp",
+    "QtBookmarkDetailWindow.cpp",
+    "QtAddBookmarkWindow.cpp",
+    "QtEditBookmarkWindow.cpp",
     "ChatSnippet.cpp",
     "MessageSnippet.cpp",
     "SystemMessageSnippet.cpp",
@@ -114,6 +117,7 @@ else :
 
 myenv.Uic4("QtJoinMUCDialog.ui")
 myenv.Uic4("QtAddContactDialog.ui")
+myenv.Uic4("QtBookmarkDetailWindow.ui")
 myenv.Qrc("DefaultTheme.qrc")
 myenv.Qrc("Swift.qrc")
 
diff --git a/Swiften/MUC/MUCBookmark.h b/Swiften/MUC/MUCBookmark.h
index 333a253..2b31f90 100644
--- a/Swiften/MUC/MUCBookmark.h
+++ b/Swiften/MUC/MUCBookmark.h
@@ -23,6 +23,7 @@ namespace Swift {
 			const boost::optional<String>& getPassword() const {return password_;};
 			const String& getName() const {return name_;};
 			const JID& getRoom() const {return room_;};
+			bool operator==(const MUCBookmark& rhs) {return rhs.room_ == room_ && rhs.name_ == name_ && rhs.nick_ == nick_ && rhs.password_ == password_ && rhs.autojoin_ == autojoin_;};
 		private:
 			JID room_;
 			String name_;
diff --git a/Swiften/MUC/MUCBookmarkManager.cpp b/Swiften/MUC/MUCBookmarkManager.cpp
index d99bdff..72e63f2 100644
--- a/Swiften/MUC/MUCBookmarkManager.cpp
+++ b/Swiften/MUC/MUCBookmarkManager.cpp
@@ -7,6 +7,7 @@
 #include "MUCBookmarkManager.h"
 
 #include <boost/bind.hpp>
+#include <iostream>
 
 #include "Swiften/Queries/IQRouter.h"
 
@@ -24,7 +25,7 @@ void MUCBookmarkManager::handleBookmarksReceived(boost::shared_ptr<Storage> payl
 	if (error) {
 		return;
 	}
-	std::vector<boost::shared_ptr<MUCBookmark> > newBookmarks;
+	std::vector<boost::shared_ptr<MUCBookmark> > receivedBookmarks;
 	foreach (Storage::Conference conference, payload->getConferences()) {
 		String name = (!conference.name.isEmpty()) ? conference.name : conference.jid.getNode();
 		boost::shared_ptr<MUCBookmark> bookmark(new MUCBookmark(conference.jid, name));
@@ -35,25 +36,54 @@ void MUCBookmarkManager::handleBookmarksReceived(boost::shared_ptr<Storage> payl
 		if (!conference.password.isEmpty()) {
 			bookmark->setPassword(conference.password);
 		}
-		newBookmarks.push_back(bookmark);
+		receivedBookmarks.push_back(bookmark);
 	}
 
-	//FIXME: This needs to be fixed before we start doing anything supporting updates
+	std::vector<boost::shared_ptr<MUCBookmark> > newBookmarks;
 	foreach (boost::shared_ptr<MUCBookmark> oldBookmark, bookmarks_) {
-		onBookmarkRemoved(oldBookmark);
+		if (containsEquivalent(receivedBookmarks, oldBookmark)) {
+			newBookmarks.push_back(oldBookmark);
+		} else {
+			onBookmarkRemoved(oldBookmark);
+		} 
 	}
 
-	foreach (boost::shared_ptr<MUCBookmark> newBookmark, newBookmarks) {
-		onBookmarkAdded(newBookmark);
+	foreach (boost::shared_ptr<MUCBookmark> newBookmark, receivedBookmarks) {
+		if (!containsEquivalent(bookmarks_, newBookmark)) {
+			newBookmarks.push_back(newBookmark);
+			onBookmarkAdded(newBookmark);
+		}
 	}
+	bookmarks_ = newBookmarks;
+}
 
+bool MUCBookmarkManager::containsEquivalent(std::vector<boost::shared_ptr<MUCBookmark> > list, boost::shared_ptr<MUCBookmark> bookmark) {
+	foreach (boost::shared_ptr<MUCBookmark> listBookmark, list) {
+		if (*listBookmark == *bookmark) {
+			return true;
+		}
+	}
+	return false;
+}
 
+void MUCBookmarkManager::replaceBookmark(boost::shared_ptr<MUCBookmark> oldBookmark, boost::shared_ptr<MUCBookmark> newBookmark) {
+	for (size_t i = 0; i < bookmarks_.size(); i++) {
+		boost::shared_ptr<MUCBookmark> bookmark(bookmarks_[i]);
+		if (bookmark.get() == oldBookmark.get()) {
+			bookmarks_[i] = newBookmark;
+			flush();
+			onBookmarkRemoved(oldBookmark);
+			onBookmarkAdded(newBookmark);
+			return;
+		}
+	}
 }
 
 void MUCBookmarkManager::addBookmark(boost::shared_ptr<MUCBookmark> bookmark) {
+	std::cout << "adding bookmark with pointer " << bookmark.get() << std::endl;
 	bookmarks_.push_back(bookmark);
-	flush();
 	onBookmarkAdded(bookmark);
+	flush();
 }
 
 
@@ -63,10 +93,9 @@ void MUCBookmarkManager::removeBookmark(boost::shared_ptr<MUCBookmark> bookmark)
 		if ((*it).get() == bookmark.get()) {
 			bookmarks_.erase(it);
 			onBookmarkRemoved(bookmark);
-			return;
+			break;
 		}
 	}
-	assert(false);
 	flush();
 }
 
diff --git a/Swiften/MUC/MUCBookmarkManager.h b/Swiften/MUC/MUCBookmarkManager.h
index 9fe5b7d..79b6167 100644
--- a/Swiften/MUC/MUCBookmarkManager.h
+++ b/Swiften/MUC/MUCBookmarkManager.h
@@ -23,14 +23,14 @@ namespace Swift {
 			MUCBookmarkManager(IQRouter* iqRouter);
 			void addBookmark(boost::shared_ptr<MUCBookmark> bookmark);
 			void removeBookmark(boost::shared_ptr<MUCBookmark> bookmark);
-			/** Call flush after editing an existing bookmark. */
-			void flush();
-			/** Returns pointers to the bookmarks. These can be edited, and then flush()ed.*/
+			void replaceBookmark(boost::shared_ptr<MUCBookmark> oldBookmark, boost::shared_ptr<MUCBookmark> newBookmark);
 			const std::vector<boost::shared_ptr<MUCBookmark> >& getBookmarks(); 
 			boost::signal<void (boost::shared_ptr<MUCBookmark>)> onBookmarkAdded;
 			boost::signal<void (boost::shared_ptr<MUCBookmark>)> onBookmarkRemoved;
 		private:
+			bool containsEquivalent(std::vector<boost::shared_ptr<MUCBookmark> > list, boost::shared_ptr<MUCBookmark> bookmark);
 			void handleBookmarksReceived(boost::shared_ptr<Storage> payload, const boost::optional<ErrorPayload>& error);
+			void flush();
 			std::vector<boost::shared_ptr<MUCBookmark> > bookmarks_;
 			IQRouter* iqRouter_;
 	};
-- 
cgit v0.10.2-6-g49f6