Project

General

Profile

SimpleChat made easy » History » Version 2

Omer Katz, 03/23/2010 01:23 AM

1 2 Omer Katz
h1. SimpleChat made easy - Part 1
2 1 Omer Katz
3 2 Omer Katz
Currently the situation with Wt's Comet is that you have to track the sessions you want to push data to yourself.
4
I have written some classes that help dealing with this issue and simplifies building the simple chat example.
5
We start writing a new application type that is derived from Wt application:
6
7
h2. CometApplication.hpp
8
9
<pre>
10
#ifndef CometApplication_HPP
11
#define CometApplication_HPP
12
13
// <STL>
14
#include <list>
15
#include <string>
16
#include <map>
17
// </STL>
18
19
// <Boost>
20
#include <boost/unordered_map.hpp>
21
// </Boost>
22
23
// <Wt>
24
#include <Wt/WApplication>
25
#include <Wt/WWidget>
26
// </Wt>
27
28
namespace UI
29
{
30
	namespace Widgets
31
	{
32
                // Forward declerations
33
		class CometWidget;
34
35
		template <class>
36
		class CometWidgetFactory;
37
	}
38
39
	namespace Application
40
	{
41
		class CometApplication : public Wt::WApplication
42
		{
43
		public:
44
			CometApplication(const Wt::WEnvironment &env); // Ctor, passes enviorment variables to WApplication
45
			~CometApplication(); // Dtor
46
47
			friend class Widgets::CometWidget; // Befriending with CometWidget so it can access the widget map
48
49
			template <class>
50
			friend class Widgets::CometWidgetFactory; // Same here
51
		private:
52
			typedef std::pair<int, Wt::WWidget *> WidgetEntryType;
53
			typedef boost::unordered_multimap<CometApplication *, WidgetEntryType > WidgetMapType;
54
			typedef boost::unordered_multimap<CometApplication *, WidgetEntryType >::iterator WidgetMapIteratorType;
55
			typedef std::pair<WidgetMapIteratorType, WidgetMapIteratorType> WidgetRangeType;
56
57
			static WidgetMapType widgets;
58
59
			// Pushes a new widget to the current session with group id and the widget itself
60
			inline void registerWidget(unsigned long int id, Wt::WWidget *w)
61
			{
62
				widgets.insert(WidgetMapType::value_type(this, WidgetEntryType(id, w)));
63
			}
64
65
			// Searches for the widget of the group id for the current session and erases it
66
			inline void unregisterWidget(unsigned long int id)
67
			{
68
				WidgetRangeType range = widgets.equal_range(this);
69
70
				for ( WidgetMapIteratorType iter = range.first; iter != range.second; ++iter )
71
				{
72
					if ( iter->second.first == id )
73
					{
74
						widgets.erase(iter);
75
						break;
76
					}
77
				}
78
			}
79
80
			// Searches for a widget in the current session, casts it to the right widget type and returns it
81
			template <class T>
82
			inline T *getWidget(unsigned long int id)
83
			{
84
				WidgetRangeType range = widgets.equal_range(this);
85
86
				for ( WidgetMapIteratorType iter = range.first; iter != range.second; ++iter )
87
					if ( iter->second.first == id )
88
						return dynamic_cast<T *>(iter->second.second);
89
90
				return NULL;
91
			}
92
		};
93
	}
94
}
95
96
#endif
97
</pre>
98
99
h2. CometApplication.cpp
100
101
<pre>
102
#include "CometApplication.hpp"
103
104
namespace UI
105
{
106
	namespace Application
107
	{
108
		CometApplication::CometApplication(const Wt::WEnvironment &env)
109
		: WApplication(env)
110
		{
111
			enableUpdates(); // Enables ajax-push for the current session
112
		}
113
114
		CometApplication::~CometApplication()
115
		{
116
			if ( widgets.find(this) != widgets.end() ) // Erases the current session from the widget map
117
				widgets.erase(this);
118
		}
119
120
		CometApplication::WidgetMapType CometApplication::widgets;
121
	}
122
}
123
</pre>
124
125
h3. Code Review
126
127
I have created an unordered multimap that might look a little strange to you guys but I'm going to elaborate about it in a minute.
128
# The multimap key is the pointer to the current session which is represented by CometApplication, because as you guys already know, a session is an application instance. That way I can access the current session's widgets using *this* or iterate through all sessions.
129
# The value of the multimap is a pair of a group id and a widget. Different widgets in different sessions with the same group id can be accessed this way.
130
131
As you can see the CometApplication instance only refers to *this*, which means only to the current session.
132
I have befriended all other classes because registerWidget, unregisterWidget and getWidget should only be accessed by those classes. This doesn't indicate that my code has a design problem in my opinion. Sometimes you actually have to use class friendship.
133
It also makes sense that the end user will not control anything related to registering/unregistering widgets as you will see.