← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/bug-987510 into lp:widelands

 

GunChleoc has proposed merging lp:~widelands-dev/widelands/bug-987510 into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #987510 in widelands: "Filter for Messages"
  https://bugs.launchpad.net/widelands/+bug/987510

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/bug-987510/+merge/236231

Messages can be filtered by category now. Added new buttons for 5 categories and an icon on the bottom right of each message to show its message type. Added keyboard shortcuts and tooltips.
-- 
https://code.launchpad.net/~widelands-dev/widelands/bug-987510/+merge/236231
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-987510 into lp:widelands.
=== modified file 'pics/message_archive.png'
Binary files pics/message_archive.png	2010-01-14 18:22:23 +0000 and pics/message_archive.png	2014-09-27 16:11:00 +0000 differ
=== modified file 'pics/message_archived.png'
Binary files pics/message_archived.png	2010-01-14 18:22:23 +0000 and pics/message_archived.png	2014-09-27 16:11:00 +0000 differ
=== added file 'pics/message_clear_selection.png'
Binary files pics/message_clear_selection.png	1970-01-01 00:00:00 +0000 and pics/message_clear_selection.png	2014-09-27 16:11:00 +0000 differ
=== modified file 'pics/message_restore.png'
Binary files pics/message_restore.png	2010-01-14 18:22:23 +0000 and pics/message_restore.png	2014-09-27 16:11:00 +0000 differ
=== added file 'pics/message_selection_invert.png'
Binary files pics/message_selection_invert.png	1970-01-01 00:00:00 +0000 and pics/message_selection_invert.png	2014-09-27 16:11:00 +0000 differ
=== added file 'pics/messages_warfare.png'
Binary files pics/messages_warfare.png	1970-01-01 00:00:00 +0000 and pics/messages_warfare.png	2014-09-27 16:11:00 +0000 differ
=== modified file 'src/logic/building.cc'
--- src/logic/building.cc	2014-09-18 18:56:20 +0000
+++ src/logic/building.cc	2014-09-27 16:11:00 +0000
@@ -879,7 +879,7 @@
  */
 void Building::send_message
 	(Game & game,
-	 const std::string & msgsender,
+	 const Message::Type msgtype,
 	 const std::string & title,
 	 const std::string & description,
 	 bool link_to_building_lifetime,
@@ -910,7 +910,7 @@
 	rt_description += "</p></rt>";
 
 	Message * msg = new Message
-		(msgsender, game.get_gametime(), title, rt_description,
+		(msgtype, game.get_gametime(), title, rt_description,
 		 get_position(), (link_to_building_lifetime ? m_serial : 0));
 
 	if (throttle_time)

=== modified file 'src/logic/building.h'
--- src/logic/building.h	2014-09-14 11:31:58 +0000
+++ src/logic/building.h	2014-09-27 16:11:00 +0000
@@ -31,6 +31,7 @@
 #include "logic/bill_of_materials.h"
 #include "logic/buildcost.h"
 #include "logic/immovable.h"
+#include "logic/message.h"
 #include "logic/soldier_counts.h"
 #include "logic/wareworker.h"
 #include "logic/widelands.h"
@@ -259,7 +260,7 @@
 
 	void send_message
 		(Game & game,
-		 const std::string & msgsender,
+		 const Message::Type msgtype,
 		 const std::string & title,
 		 const std::string & description,
 		 bool link_to_building_lifetime = true,

=== modified file 'src/logic/cmd_delete_message.h'
=== modified file 'src/logic/cmd_luacoroutine.cc'
--- src/logic/cmd_luacoroutine.cc	2014-09-18 18:56:20 +0000
+++ src/logic/cmd_luacoroutine.cc	2014-09-27 16:11:00 +0000
@@ -50,7 +50,7 @@
 		for (int i = 1; i <= game.map().get_nrplayers(); i++) {
 			Widelands::Message & msg =
 				*new Widelands::Message
-				("Game Logic", game.get_gametime(), "Lua Coroutine Failed", e.what());
+				(Message::Type::gameLogic, game.get_gametime(), "Lua Coroutine Failed", e.what());
 			game.player(i).add_message(game, msg, true);
 		}
 		game.gameController()->setDesiredSpeed(0);

=== modified file 'src/logic/message.h'
--- src/logic/message.h	2014-09-15 10:17:53 +0000
+++ src/logic/message.h	2014-09-27 16:11:00 +0000
@@ -30,9 +30,23 @@
 
 struct Message {
 	enum Status {New, Read, Archived};
+	enum class Type: uint8_t {
+		allMessages,
+		gameLogic,
+		geologists,
+		scenario,
+		seafaring,
+		economy,      // economy
+		siteOccupied, // economy
+		warfare,     // everything starting from here is warfare
+		siteDefeated,
+		siteLost,
+		underAttack
+	};
+
 	/**
 	 * A new message to be displayed to the player
-	 * \param msgsender The message sender
+	 * \param msgtype The type of message (economy, geologists, etc.)
 	 * \param sent_time The (game) time at which the message is sent
 	 * \param t The message title
 	 * \param b The message body
@@ -43,7 +57,7 @@
 	 * \param s The message status. Defaults to Status::New
 	 */
 	Message
-		(const std::string &       msgsender,
+		(Message::Type             msgtype,
 		 uint32_t                  sent_time,
 		 const std::string &       t,
 		 const std::string &       b,
@@ -51,8 +65,8 @@
 		 Widelands::Serial         ser = 0,
 		 Status                    s = New)
 		:
-		m_sender(msgsender),
-		m_title(t),
+		m_type    (msgtype),
+		m_title   (t),
 		m_body    (b),
 		m_sent    (sent_time),
 		m_position(c),
@@ -60,18 +74,32 @@
 		m_status  (s)
 	{}
 
-	const std::string & sender() const     {return m_sender;}
-	uint32_t            sent    () const            {return m_sent;}
-	const std::string & title() const      {return m_title;}
-	const std::string & body () const               {return m_body;}
-	Widelands::Coords   position() const            {return m_position;}
-	Widelands::Serial   serial() const              {return m_serial;}
-	Status              status  () const {return m_status;}
-	Status set_status(Status const s) {return m_status = s;}
+	Message::Type         type    () const   {return m_type;}
+	uint32_t              sent    () const   {return m_sent;}
+	const std::string &   title   () const   {return m_title;}
+	const std::string &   body    () const   {return m_body;}
+	Widelands::Coords     position() const   {return m_position;}
+	Widelands::Serial     serial  () const   {return m_serial;}
+	Status                status  () const   {return m_status;}
+	Status set_status(Status const s)        {return m_status = s;}
+
+	/**
+	 * Returns the main type for the message's sub type
+	 */
+	Message::Type message_type_category() const {
+		if (m_type >=  Widelands::Message::Type::warfare) {
+			return Widelands::Message::Type::warfare;
+
+		} else if (m_type >= Widelands::Message::Type::economy &&
+					  m_type <= Widelands::Message::Type::siteOccupied) {
+			return Widelands::Message::Type::economy;
+		}
+		return m_type;
+	}
 
 private:
-	std::string m_sender;
-	std::string m_title;
+	Message::Type     m_type;
+	std::string       m_title;
 	std::string       m_body;
 	uint32_t          m_sent;
 	Widelands::Coords m_position;

=== modified file 'src/logic/militarysite.cc'
--- src/logic/militarysite.cc	2014-09-10 10:18:46 +0000
+++ src/logic/militarysite.cc	2014-09-27 16:11:00 +0000
@@ -248,7 +248,7 @@
 		if (upcast(Game, game, &egbase)) {
 			send_message
 				(*game,
-				 "site_occupied",
+				 Message::Type::siteOccupied,
 				 descr().descname(),
 				 descr().m_occupied_str,
 				 true);
@@ -845,7 +845,7 @@
 		{
 			send_message
 				(game,
-				 "site_lost",
+				 Message::Type::siteLost,
 				 _("Militarysite lost!"),
 				 descr().m_defeated_enemy_str,
 				 false);
@@ -899,7 +899,7 @@
 		// Of course we should inform the victorious player as well
 		newsite->send_message
 			(game,
-			 "site_defeated",
+			 Message::Type::siteDefeated,
 			 _("Enemy at site defeated!"),
 			 newsite->descr().m_defeated_you_str,
 			 true);
@@ -949,7 +949,7 @@
 	// radius <= 5 near the current location in the last 60 seconds
 	send_message
 		(game,
-		 "under_attack",
+		 Message::Type::underAttack,
 		 _("You are under attack"),
 		 discovered ? descr().m_aggressor_str : descr().m_attack_str,
 		 false,

=== modified file 'src/logic/player.cc'
--- src/logic/player.cc	2014-09-18 18:56:20 +0000
+++ src/logic/player.cc	2014-09-27 16:11:00 +0000
@@ -292,15 +292,15 @@
  * Plays the corresponding sound when a message is received and if sound is
  * enabled.
  */
-void Player::play_message_sound(const std::string & sender) {
-#define MAYBE_PLAY(a, b) if (sender == a) { \
-	g_sound_handler.play_fx(b, 200, PRIO_ALWAYS_PLAY); \
+void Player::play_message_sound(const Message::Type & msgtype) {
+#define MAYBE_PLAY(type, file) if (msgtype == type) { \
+	g_sound_handler.play_fx(file, 200, PRIO_ALWAYS_PLAY); \
 	return; \
 	}
 
 	if (g_options.pull_section("global").get_bool("sound_at_message", true)) {
-		MAYBE_PLAY("site_occupied", "sound/military/site_occupied");
-		MAYBE_PLAY("under_attack", "sound/military/under_attack");
+		MAYBE_PLAY(Message::Type::siteOccupied, "sound/military/site_occupied");
+		MAYBE_PLAY(Message::Type::underAttack, "sound/military/under_attack");
 
 		g_sound_handler.play_fx("sound/message", 200, PRIO_ALWAYS_PLAY);
 	}
@@ -321,7 +321,7 @@
 	// Sound & popup
 	if (InteractivePlayer * const iplayer = game.get_ipl()) {
 		if (&iplayer->player() == this) {
-			play_message_sound(message.sender());
+			play_message_sound(message.type());
 			if (popup)
 				iplayer->popup_message(id, message);
 		}
@@ -339,7 +339,7 @@
 	Coords      const position = m   .position    ();
 	for (std::pair<MessageId, Message *>  tmp_message : messages()) {
 		if
-			(tmp_message.second->sender() == m.sender()      &&
+			(tmp_message.second->type() == m.type()      &&
 			 gametime < tmp_message.second->sent() + timeout &&
 			 map.calc_distance(tmp_message.second->position(), position) <= radius)
 		{

=== modified file 'src/logic/player.h'
--- src/logic/player.h	2014-09-18 18:56:20 +0000
+++ src/logic/player.h	2014-09-27 16:11:00 +0000
@@ -524,7 +524,7 @@
 private:
 	void update_building_statistics(Building &, NoteImmovable::Ownership ownership);
 	void update_team_players();
-	void play_message_sound(const std::string & sender);
+	void play_message_sound(const Message::Type & msgtype);
 	void _enhance_or_dismantle
 		(Building *, BuildingIndex const index_of_new_building);
 

=== modified file 'src/logic/productionsite.cc'
--- src/logic/productionsite.cc	2014-09-10 18:56:42 +0000
+++ src/logic/productionsite.cc	2014-09-27 16:11:00 +0000
@@ -924,7 +924,7 @@
 			assert(!descr().out_of_resource_message().empty());
 			send_message
 				(game,
-					  "produce",
+				 Message::Type::economy,
 				 descr().out_of_resource_title(),
 				 descr().out_of_resource_message(),
 				 true,

=== modified file 'src/logic/ship.cc'
--- src/logic/ship.cc	2014-09-18 18:56:20 +0000
+++ src/logic/ship.cc	2014-09-27 16:11:00 +0000
@@ -459,7 +459,7 @@
 			// Send a message to the player, that a new port space was found
 			std::string msg_head = _("Port Space Found");
 			std::string msg_body = _("An expedition ship found a new port build space.");
-			send_message(game, "exp_port_space", msg_head, msg_body, "port.png");
+			send_message(game, msg_head, msg_body, "port.png");
 		}
 		m_expedition->seen_port_buildspaces.swap(temp_port_buildspaces);
 	}
@@ -568,7 +568,7 @@
 							std::string msg_head = _("Island Circumnavigated");
 							std::string msg_body = _("An expedition ship sailed around its"
 										 " island without any events.");
-							send_message(game, "exp_island", msg_head, msg_body,
+							send_message(game, msg_head, msg_body,
 								"ship_explore_island_cw.png");
 							m_ship_state = EXP_WAITING;
 							return start_task_idle(game, descr().main_animation(), 1500);
@@ -624,7 +624,7 @@
 				std::string msg_head = _("Coast Reached");
 				std::string msg_body =
 					_("An expedition ship reached a coast and is waiting for further commands.");
-				send_message(game, "exp_coast", msg_head, msg_body, "ship_explore_island_cw.png");
+				send_message(game, msg_head, msg_body, "ship_explore_island_cw.png");
 				return;
 			}
 		}
@@ -787,7 +787,7 @@
 	// Send a message to the player, that an expedition is ready to go
 	const std::string msg_head = _("Expedition Ready");
 	const std::string msg_body = _("An expedition ship is waiting for your commands.");
-	send_message(game, "exp_ready", msg_head, msg_body, "start_expedition.png");
+	send_message(game, msg_head, msg_body, "start_expedition.png");
 }
 
 /// Initializes / changes the direction of scouting to @arg direction
@@ -899,9 +899,7 @@
  * \param picture picture name relative to the pics directory
  */
 void Ship::send_message
-	(Game & game, const std::string & msgsender,
-	 const std::string & title, const std::string & description,
-	 const std::string & picture)
+	(Game & game, const std::string & title, const std::string & description, const std::string & picture)
 {
 	std::string rt_description;
 	if (picture.size() > 3) {
@@ -914,7 +912,7 @@
 	rt_description += "</p></rt>";
 
 	Message * msg = new Message
-		(msgsender, game.get_gametime(), title, rt_description, get_position(), m_serial);
+		(Message::Type::seafaring, game.get_gametime(), title, rt_description, get_position(), m_serial);
 
 	get_owner()->add_message(game, *msg);
 }

=== modified file 'src/logic/ship.h'
--- src/logic/ship.h	2014-09-10 08:55:04 +0000
+++ src/logic/ship.h	2014-09-27 16:11:00 +0000
@@ -208,8 +208,7 @@
 	void init_fleet(EditorGameBase &);
 	void set_fleet(Fleet * fleet);
 
-	void send_message
-		(Game &, const std::string &, const std::string &, const std::string &, const std::string &);
+	void send_message(Game &, const std::string &, const std::string &, const std::string &);
 
 	UI::Window * m_window;
 

=== modified file 'src/logic/soldier.cc'
--- src/logic/soldier.cc	2014-09-18 18:56:20 +0000
+++ src/logic/soldier.cc	2014-09-27 16:11:00 +0000
@@ -1570,7 +1570,7 @@
 					owner().add_message
 						(game,
 						 *new Message
-						 	("game engine",
+							(Message::Type::gameLogic,
 							 game.get_gametime(),
 						 	 _("Logic error"),
 						 	 buffer,
@@ -1579,7 +1579,7 @@
 					opponent.owner().add_message
 						(game,
 						 *new Message
-						 	("game engine",
+							(Message::Type::gameLogic,
 							 game.get_gametime(),
 						 	 _("Logic error"),
 						 	 buffer,

=== modified file 'src/logic/warehouse.cc'
--- src/logic/warehouse.cc	2014-09-10 10:18:46 +0000
+++ src/logic/warehouse.cc	2014-09-27 16:11:00 +0000
@@ -451,6 +451,7 @@
 				(ref_cast<Game, EditorGameBase>(egbase), 4000);
 
 		log("Message: adding (wh) (%s) %i \n", to_string(descr().type()).c_str(), player.player_number());
+<<<<<<< TREE
 		char message[2048];
 		snprintf
 			(message, sizeof(message),
@@ -462,7 +463,32 @@
 			 descr().descname(),
 			 message,
 			 true);
+=======
+
+		if (descr().name() == "port") {
+			send_message
+				(ref_cast<Game, Editor_Game_Base>(egbase),
+				 Message::Type::seafaring,
+				 descr().descname(),
+				 _("A new port was added to your economy."),
+				 true);
+		} else if (descr().name() == "headquarters") {
+			send_message
+				(ref_cast<Game, Editor_Game_Base>(egbase),
+				 Message::Type::economy,
+				 descr().descname(),
+				 _("A new headquarters was added to your economy."),
+				 true);
+		} else {
+			send_message
+				(ref_cast<Game, Editor_Game_Base>(egbase),
+				 Message::Type::economy,
+				 descr().descname(),
+				 _("A new warehouse was added to your economy."),
+				 true);
+>>>>>>> MERGE-SOURCE
 		}
+	}
 
 	if (uint32_t const conquer_radius = descr().get_conquers())
 		egbase.conquer_area

=== modified file 'src/logic/worker.cc'
--- src/logic/worker.cc	2014-09-18 18:56:20 +0000
+++ src/logic/worker.cc	2014-09-27 16:11:00 +0000
@@ -946,7 +946,7 @@
 			owner().add_message_with_timeout
 				(game,
 				 *new Message
-				 	("geologist " + rdescr->name(), // e.g. "geologist gold"
+					(Message::Type::geologists,
 					 game.get_gametime(),
 				 	 rdescr->descname(),
 				 	 message,
@@ -1844,7 +1844,7 @@
 		owner().add_message
 			(game,
 			 *new Message
-			 	("game engine",
+				(Message::Type::gameLogic,
 				 game.get_gametime(),
 			 	 _("Worker got lost!"),
 			 	 buffer,

=== modified file 'src/map_io/map_players_messages_packet.cc'
--- src/map_io/map_players_messages_packet.cc	2014-09-18 18:56:20 +0000
+++ src/map_io/map_players_messages_packet.cc	2014-09-27 16:11:00 +0000
@@ -20,6 +20,7 @@
 #include "map_io/map_players_messages_packet.h"
 
 #include "logic/game_data_error.h"
+#include "logic/message.h"
 #include "logic/player.h"
 #include "map_io/coords_profile.h"
 #include "map_io/map_object_loader.h"
@@ -61,14 +62,14 @@
 						 "added it to the queue. This is only allowed during "
 						 "simulation, not at load. The following messge will be "
 						 "removed when the queue is reset:\n"
-						 "\tsender  : %s\n"
+						 "\tstype   : %u\n"
 						 "\ttitle   : %s\n"
 						 "\tsent    : %u\n"
 						 "\tposition: (%i, %i)\n"
 						 "\tstatus  : %u\n"
 						 "\tbody    : %s\n",
 						 p,
-						 begin->second->sender  ().c_str(),
+						 begin->second->type    (),
 						 begin->second->title   ().c_str(),
 						 begin->second->sent    (),
 						 begin->second->position().x, begin->second->position().y,
@@ -120,7 +121,7 @@
 
 					messages.add_message
 						(*new Message
-						 	(s->get_string     ("sender", ""),
+							(static_cast<Message::Type>(s->get_natural("type")),
 						 	 sent,
 						 	 s->get_name       (),
 						 	 s->get_safe_string("body"),
@@ -156,11 +157,10 @@
 			assert(message.sent() <= static_cast<uint32_t>(egbase.get_gametime()));
 
 			Section & s = prof.create_section_duplicate(message.title().c_str());
-			if (message.sender().size())
-				s.set_string("sender",    message.sender  ());
-			s.set_int      ("sent",      message.sent    ());
-			s.set_string   ("body",      message.body    ());
-			if (Coords const c =         message.position())
+			s.set_int    ("type",      static_cast<int32_t>(message.type()));
+			s.set_int    ("sent",      message.sent    ());
+			s.set_string ("body",      message.body    ());
+			if (Coords const c =       message.position())
 				set_coords("position",  c, &s);
 			switch (message.status()) {
 			case Message::New:

=== modified file 'src/scripting/lua_game.cc'
--- src/scripting/lua_game.cc	2014-09-18 18:56:20 +0000
+++ src/scripting/lua_game.cc	2014-09-27 16:11:00 +0000
@@ -29,6 +29,7 @@
 #include "logic/campaign_visibility.h"
 #include "logic/constants.h"
 #include "logic/game_controller.h"
+#include "logic/message.h"
 #include "logic/objective.h"
 #include "logic/path.h"
 #include "logic/player.h"
@@ -277,9 +278,6 @@
 			'archived'. Default: "new"
 		:type status: :class:`string`
 
-		:arg sender: sender name of this string. Default: "ScriptingEngine"
-		:type sender: :class:`string`
-
 		:arg popup: should the message window be opened for this message or not.
 			Default: :const:`false`
 		:type popup: :class:`boolean`
@@ -293,7 +291,6 @@
 	std::string body = luaL_checkstring(L, 3);
 	Coords c = Coords::Null();
 	Message::Status st = Message::New;
-	std::string sender = "ScriptingEngine";
 	bool popup = false;
 
 	if (n == 4) {
@@ -313,11 +310,6 @@
 		}
 		lua_pop(L, 1);
 
-		lua_getfield(L, 4, "sender");
-		if (!lua_isnil(L, -1))
-			sender = luaL_checkstring(L, -1);
-		lua_pop(L, 1);
-
 		lua_getfield(L, 4, "popup");
 		if (!lua_isnil(L, -1))
 			popup = luaL_checkboolean(L, -1);
@@ -331,7 +323,7 @@
 		plr.add_message
 			(game,
 			 *new Message
-			 	(sender,
+				(Message::Type::scenario,
 			 	 game.get_gametime(),
 			 	 title,
 			 	 body,
@@ -1048,6 +1040,7 @@
 	METHOD(LuaMessage, __eq),
 	{nullptr, nullptr},
 };
+<<<<<<< TREE
 const PropertyType<LuaMessage> LuaMessage::Properties[] = {
 	PROP_RO(LuaMessage, sender),
 	PROP_RO(LuaMessage, title),
@@ -1055,6 +1048,14 @@
 	PROP_RO(LuaMessage, sent),
 	PROP_RO(LuaMessage, field),
 	PROP_RW(LuaMessage, status),
+=======
+const PropertyType<L_Message> L_Message::Properties[] = {
+	PROP_RO(L_Message, title),
+	PROP_RO(L_Message, body),
+	PROP_RO(L_Message, sent),
+	PROP_RO(L_Message, field),
+	PROP_RW(L_Message, status),
+>>>>>>> MERGE-SOURCE
 	{nullptr, nullptr, nullptr},
 };
 
@@ -1079,15 +1080,16 @@
  PROPERTIES
  ==========================================================
  */
-/* RST
-	.. attribute:: sender
 
+<<<<<<< TREE
 		(RO) The name of the sender of this message
 */
 int LuaMessage::get_sender(lua_State * L) {
 	lua_pushstring(L, get(L, get_game(L)).sender());
 	return 1;
 }
+=======
+>>>>>>> MERGE-SOURCE
 /* RST
 	.. attribute:: title
 

=== modified file 'src/scripting/lua_game.h'
--- src/scripting/lua_game.h	2014-09-18 18:56:20 +0000
+++ src/scripting/lua_game.h	2014-09-27 16:11:00 +0000
@@ -161,7 +161,6 @@
 	/*
 	 * Properties
 	 */
-	int get_sender(lua_State * L);
 	int get_sent(lua_State * L);
 	int get_title(lua_State * L);
 	int get_body(lua_State * L);

=== modified file 'src/wui/game_message_menu.cc'
--- src/wui/game_message_menu.cc	2014-09-10 14:48:40 +0000
+++ src/wui/game_message_menu.cc	2014-09-27 16:11:00 +0000
@@ -20,6 +20,7 @@
 #include "wui/game_message_menu.h"
 
 #include <boost/bind.hpp>
+#include <boost/format.hpp>
 
 #include "base/deprecated.h"
 #include "base/time_string.h"
@@ -46,11 +47,12 @@
 		(&plr, "messages", &registry, 580, 375, _("Messages: Inbox")),
 	message_body
 		(this,
-		 5, 150, 570, 220,
+		 5, 154, 570, 216,
 		 "", UI::Align_Left, 1),
 	mode(Inbox)
 {
-	list = new UI::Table<uintptr_t>(this, 5, 35, 570, 110);
+
+	list = new UI::Table<uintptr_t>(this, 5, message_body.get_y() - 110, 570, 110);
 	list->selected.connect(boost::bind(&GameMessageMenu::selected, this, _1));
 	list->double_clicked.connect(boost::bind(&GameMessageMenu::double_clicked, this, _1));
 	list->add_column (60, _("Select"), "", UI::Align_HCenter, true);
@@ -58,39 +60,105 @@
 	list->add_column(330, _("Title"));
 	list->add_column(120, _("Time sent"));
 
+	// Buttons for message types
+	m_geologistsbtn =
+			new UI::Button
+				(this, "filter_geologists_messages",
+				 5, 5, 34, 34,
+				 g_gr->images().get("pics/but0.png"),
+				 g_gr->images().get("pics/menu_geologist.png"),
+				 "",
+				 true);
+	m_geologistsbtn->sigclicked.connect
+			(boost::bind(&GameMessageMenu::filter_messages, this, Widelands::Message::Type::geologists));
+
+	m_economybtn =
+			new UI::Button
+				(this, "filter_economy_messages",
+				 2 * 5 + 34, 5, 34, 34,
+				 g_gr->images().get("pics/but0.png"),
+				 g_gr->images().get("pics/menu_build_flag.png"),
+				 "",
+				 true);
+	m_economybtn->sigclicked.connect
+			(boost::bind(&GameMessageMenu::filter_messages, this, Widelands::Message::Type::economy));
+
+	m_seafaringbtn =
+			new UI::Button
+				(this, "filter_seafaring_messages",
+				 3 * 5 + 2 * 34, 5, 34, 34,
+				 g_gr->images().get("pics/but0.png"),
+				 g_gr->images().get("pics/start_expedition.png"),
+				 "",
+				 true);
+	m_seafaringbtn->sigclicked.connect
+			(boost::bind(&GameMessageMenu::filter_messages, this, Widelands::Message::Type::seafaring));
+
+	m_warfarebtn =
+			new UI::Button
+				(this, "filter_warfare_messages",
+				 4 * 5 + 3 * 34, 5, 34, 34,
+				 g_gr->images().get("pics/but0.png"),
+				 g_gr->images().get("pics/messages_warfare.png"),
+				 "",
+				 true);
+	m_warfarebtn->sigclicked.connect
+			(boost::bind(&GameMessageMenu::filter_messages, this, Widelands::Message::Type::warfare));
+
+	m_scenariobtn =
+			new UI::Button
+				(this, "filter_scenario_messages",
+				 5 * 5 + 4 * 34, 5, 34, 34,
+				 g_gr->images().get("pics/but0.png"),
+				 g_gr->images().get("pics/menu_objectives.png"),
+				 "",
+				 true);
+	m_scenariobtn->sigclicked.connect
+			(boost::bind(&GameMessageMenu::filter_messages, this, Widelands::Message::Type::scenario));
+
+	m_message_filter = Widelands::Message::Type::allMessages;
+	set_filter_messages_tooltips();
+	// End: Buttons for message types
+
 	UI::Button * clearselectionbtn =
 		new UI::Button
 			(this, "clear_selection",
-			 5, 5, 140, 25,
-			 g_gr->images().get("pics/but0.png"),
-			 _("Clear"), _("Clear selection"));
+			 5 * 5 + 6 * 34 + 17, 5, 34, 34,
+			 g_gr->images().get("pics/but2.png"),
+			 g_gr->images().get("pics/message_clear_selection.png"),
+			 _("Clear selection"));
 	clearselectionbtn->sigclicked.connect
 		(boost::bind(&GameMessageMenu::do_clear_selection, this));
 
 	UI::Button * invertselectionbtn =
 		new UI::Button
 			(this, "invert_selection",
-			 150, 5, 140, 25,
-			 g_gr->images().get("pics/but0.png"),
-			 _("Invert"), _("Invert selection"));
+			 6 * 5 + 7 * 34 + 17, 5, 34, 34,
+			 g_gr->images().get("pics/but2.png"),
+			 g_gr->images().get("pics/message_selection_invert.png"),
+			 _("Invert selection"));
 	invertselectionbtn->sigclicked.connect
 		(boost::bind(&GameMessageMenu::do_invert_selection, this));
 
 	m_archivebtn =
 		new UI::Button
 			(this, "archive_or_restore_selected_messages",
-			 295, 5, 25, 25,
+			 6 * 5 + 9 * 34 + 34, 5, 34, 34,
 			 g_gr->images().get("pics/but2.png"),
 			 g_gr->images().get("pics/message_archive.png"),
-			 _("Archive selected messages"));
+			 /** TRANSLATORS: %s is a tooltip, Del is the corresponding hotkey */
+			 (boost::format(_("Del: %s"))
+			  /** TRANSLATORS: Tooltip in the messages window */
+			  % _("Archive selected messages")).str());
 	m_archivebtn->sigclicked.connect
 		(boost::bind(&GameMessageMenu::archive_or_restore, this));
 
 	m_togglemodebtn =
 		new UI::Button
 			(this, "toggle_between_inbox_or_archive",
-			 325, 5, 190, 25,
+			 7 * 5 + 10 * 34 + 34, 5, 34, 34,
 			 g_gr->images().get("pics/but2.png"),
+			 g_gr->images().get("pics/message_archived.png"),
 			 _("Show Archive"));
 	m_togglemodebtn->sigclicked.connect
 		(boost::bind(&GameMessageMenu::toggle_mode, this));
@@ -98,13 +166,24 @@
 	m_centerviewbtn =
 		new UI::Button
 			(this, "center_main_mapview_on_location",
-			 550, 5, 25, 25,
+			 580 - 5 - 34, 5, 34, 34,
 			 g_gr->images().get("pics/but2.png"),
 			 g_gr->images().get("pics/menu_goto.png"),
-			 _("center main mapview on location"),
+			 /** TRANSLATORS: %s is a tooltip, G is the corresponding hotkey */
+			 (boost::format(_("G: %s"))
+			  /** TRANSLATORS: Tooltip in the messages window */
+			  % _("Center main mapview on location")).str(),
 			 false);
 	m_centerviewbtn->sigclicked.connect(boost::bind(&GameMessageMenu::center_view, this));
 
+
+	m_display_message_type_label =
+		new UI::Multiline_Textarea
+			(this,
+			 5, 375 - 5 - 34, 5 * 34, 40,
+			 "<rt image=pics/message_new.png></rt>",
+			 UI::Align::Align_BottomLeft, false);
+
 	if (get_usedefaultpos())
 		center_to_parent();
 
@@ -183,6 +262,19 @@
 		}
 	}
 
+	// Filter message type
+	if (m_message_filter != Message::Type::allMessages) {
+		set_display_message_type_label(m_message_filter);
+		for (uint32_t j = list->size(); j; --j) {
+			Message_Id m_id((*list)[j - 1]);
+			if (Message const * const message = mq[m_id]) {
+				if (message->message_type_category() != m_message_filter) {
+					list->remove(j - 1);
+				}
+			}
+		}
+	}
+
 	if (list->size()) {
 		if (!list->has_selection())
 			list->select(0);
@@ -226,6 +318,7 @@
 			}
 			m_centerviewbtn->set_enabled(message->position());
 			message_body.set_text(message->body    ());
+			set_display_message_type_label(message->message_type_category());
 			return;
 		}
 	}
@@ -247,12 +340,31 @@
 {
 	if (down) {
 		switch (code.sym) {
+		// Don't forget to change the tooltips if any of these get reassigned
 		case SDLK_g:
 			if (m_centerviewbtn->enabled())
 				center_view();
 			return true;
-
+		case SDLK_0:
+			filter_messages(Widelands::Message::Type::allMessages);
+			return true;
+		case SDLK_1:
+			filter_messages(Widelands::Message::Type::geologists);
+			return true;
+		case SDLK_2:
+			filter_messages(Widelands::Message::Type::economy);
+			return true;
+		case SDLK_3:
+			filter_messages(Widelands::Message::Type::seafaring);
+			return true;
+		case SDLK_4:
+			filter_messages(Widelands::Message::Type::warfare);
+			return true;
+		case SDLK_5:
+			filter_messages(Widelands::Message::Type::scenario);
+			return true;
 		case SDLK_KP_PERIOD:
+
 			if (code.mod & KMOD_NUM)
 				break;
 			/* no break */
@@ -336,6 +448,136 @@
 }
 
 /**
+ * Show only messages of a certain type
+ * @param msgtype the types of messages to show
+ */
+void GameMessageMenu::filter_messages(Widelands::Message::Type const msgtype) {
+	switch (msgtype) {
+		case Widelands::Message::Type::geologists:
+			toggle_filter_messages_button(*m_geologistsbtn, msgtype);
+			break;
+		case Widelands::Message::Type::economy:
+			toggle_filter_messages_button(*m_economybtn, msgtype);
+			break;
+		case Widelands::Message::Type::seafaring:
+			toggle_filter_messages_button(*m_seafaringbtn, msgtype);
+			break;
+		case Widelands::Message::Type::warfare:
+			toggle_filter_messages_button(*m_warfarebtn, msgtype);
+			break;
+		case Widelands::Message::Type::scenario:
+			toggle_filter_messages_button(*m_scenariobtn, msgtype);
+			break;
+		default:
+			set_filter_messages_tooltips();
+			m_message_filter = Widelands::Message::Type::allMessages;
+			m_geologistsbtn->set_perm_pressed(false);
+			m_economybtn->set_perm_pressed(false);
+			m_seafaringbtn->set_perm_pressed(false);
+			m_warfarebtn->set_perm_pressed(false);
+			m_scenariobtn->set_perm_pressed(false);
+	}
+	think();
+}
+
+/**
+ * Helper for filter_messages
+ */
+void GameMessageMenu::toggle_filter_messages_button(UI::Button & button, Widelands::Message::Type msgtype) {
+	set_filter_messages_tooltips();
+	if (button.get_perm_pressed()) {
+		button.set_perm_pressed(false);
+		m_message_filter = Widelands::Message::Type::allMessages;
+	} else {
+		m_geologistsbtn->set_perm_pressed(false);
+		m_economybtn->set_perm_pressed(false);
+		m_seafaringbtn->set_perm_pressed(false);
+		m_warfarebtn->set_perm_pressed(false);
+		m_scenariobtn->set_perm_pressed(false);
+		button.set_perm_pressed(true);
+		m_message_filter = msgtype;
+		/** TRANSLATORS: %s is a tooltip, 0 is the corresponding hotkey */
+		button.set_tooltip((boost::format(_("0: %s"))
+								  /** TRANSLATORS: Tooltip in the messages window */
+								  % _("Show all messages")).str());
+	}
+}
+
+/**
+ * Helper for filter_messages
+ */
+void GameMessageMenu::set_filter_messages_tooltips() {
+	/** TRANSLATORS: %s is a tooltip, 1 is the corresponding hotkey */
+	m_geologistsbtn->set_tooltip((boost::format(_("1: %s"))
+											/** TRANSLATORS: Tooltip in the messages window */
+											% _("Show geologists' messages only")).str());
+	/** TRANSLATORS: %s is a tooltip, 2 is the corresponding hotkey */
+	m_economybtn->set_tooltip((boost::format(_("2: %s"))
+										/** TRANSLATORS: Tooltip in the messages window */
+										% _("Show economy messages only")).str());
+	/** TRANSLATORS: %s is a tooltip, 3 is the corresponding hotkey */
+	m_seafaringbtn->set_tooltip((boost::format(_("3: %s)"))
+										  /** TRANSLATORS: Tooltip in the messages window */
+										  % _("Show seafaring messages only")).str());
+	/** TRANSLATORS: %s is a tooltip, 4 is the corresponding hotkey */
+	m_warfarebtn->set_tooltip((boost::format(_("4: %s"))
+										/** TRANSLATORS: Tooltip in the messages window */
+										% _("Show warfare messages only")).str());
+	/** TRANSLATORS: %s is a tooltip, 5 is the corresponding hotkey */
+	m_scenariobtn->set_tooltip((boost::format(_("5: %s"))
+										 /** TRANSLATORS: Tooltip in the messages window */
+										 % _("Show scenario messages only")).str());
+}
+
+/**
+ * Update image and tooltip for message category label
+ */
+void GameMessageMenu::set_display_message_type_label(Widelands::Message::Type msgtype) {
+	std::string message_type_tooltip = "";
+	std::string message_type_image = "";
+
+	switch (msgtype) {
+		case Widelands::Message::Type::geologists:
+			/** TRANSLATORS: This is a message's type */
+			message_type_tooltip =  _("Geologists");
+			message_type_image =  "<rt image=pics/menu_geologist.png></rt>";
+			break;
+		case Widelands::Message::Type::economy:
+			/** TRANSLATORS: This is a message's type */
+			message_type_tooltip =  _("Economy");
+			message_type_image =  "<rt image=pics/menu_build_flag.png></rt>";
+			break;
+		case Widelands::Message::Type::seafaring:
+			/** TRANSLATORS: This is a message's type */
+			message_type_tooltip =  _("Seafaring");
+			message_type_image =  "<rt image=pics/start_expedition.png></rt>";
+			break;
+		case Widelands::Message::Type::warfare:
+			/** TRANSLATORS: This is a message's type */
+			message_type_tooltip =  _("Warfare");
+			message_type_image =  "<rt image=pics/messages_warfare.png></rt>";
+			break;
+		case Widelands::Message::Type::scenario:
+			/** TRANSLATORS: This is a message's type */
+			message_type_tooltip =  _("Scenario");
+			message_type_image =  "<rt image=pics/menu_objectives.png></rt>";
+			break;
+		default:
+			/** TRANSLATORS: This is the default message type */
+			message_type_tooltip = _("General");
+			message_type_image =  "<rt image=pics/message_new.png></rt>";
+	}
+
+	m_display_message_type_label->set_tooltip(
+				 /** TRANSLATORS: %s is a message's type */
+				 (boost::format(_("Message type: %s"))
+				  /** TRANSLATORS: Tooltip in the messages window */
+				  % message_type_tooltip).str());
+	m_display_message_type_label->set_text(message_type_image);
+}
+
+
+/**
  * Clear the current selection of messages.
  */
 void GameMessageMenu::do_clear_selection()
@@ -359,15 +601,23 @@
 		mode = Archive;
 		set_title(_("Messages: Archive"));
 		m_archivebtn->set_pic(g_gr->images().get("pics/message_restore.png"));
-		m_archivebtn->set_tooltip(_("Restore selected messages"));
-		m_togglemodebtn->set_title(_("Show Inbox"));
+		/** TRANSLATORS: %s is a tooltip, Del is the corresponding hotkey */
+		m_archivebtn->set_tooltip((boost::format(_("Del: %s"))
+											/** TRANSLATORS: Tooltip in the messages window */
+											% _("Restore selected messages")).str());
+		m_togglemodebtn->set_pic(g_gr->images().get("pics/message_new.png"));
+		m_togglemodebtn->set_tooltip(_("Show Inbox"));
 		break;
 	case Archive:
 		mode = Inbox;
 		set_title(_("Messages: Inbox"));
 		m_archivebtn->set_pic(g_gr->images().get("pics/message_archive.png"));
-		m_archivebtn->set_tooltip(_("Archive selected messages"));
-		m_togglemodebtn->set_title(_("Show Archive"));
+		/** TRANSLATORS: %s is a tooltip, Del is the corresponding hotkey */
+		m_archivebtn->set_tooltip((boost::format(_("Del: %s"))
+											/** TRANSLATORS: Tooltip in the messages window */
+											% _("Archive selected messages")).str());
+		m_togglemodebtn->set_pic(g_gr->images().get("pics/message_archived.png"));
+		m_togglemodebtn->set_tooltip(_("Show Archive"));
 		break;
 	default:
 		assert(false); // there is nothing but Archive and Inbox

=== modified file 'src/wui/game_message_menu.h'
--- src/wui/game_message_menu.h	2014-09-10 14:48:40 +0000
+++ src/wui/game_message_menu.h	2014-09-27 16:11:00 +0000
@@ -22,6 +22,7 @@
 
 #include "base/deprecated.h"
 #include "base/i18n.h"
+#include "logic/message.h"
 #include "logic/message_queue.h"
 #include "ui_basic/button.h"
 #include "ui_basic/multilinetextarea.h"
@@ -49,6 +50,7 @@
 
 private:
 	enum Cols {ColSelect, ColStatus, ColTitle, ColTimeSent};
+	enum class ReadUnread: uint8_t {allMessages, readMessages, newMessages};
 
 	InteractivePlayer & iplayer() const;
 	void selected(uint32_t);
@@ -60,7 +62,15 @@
 	void archive_or_restore();
 	void toggle_mode();
 	void center_view();
+<<<<<<< TREE
 	void update_record(UI::Table<uintptr_t>::EntryRecord & er, const Widelands::Message &);
+=======
+	void filter_messages(Widelands::Message::Type);
+	void toggle_filter_messages_button(UI::Button &, Widelands::Message::Type);
+	void set_filter_messages_tooltips();
+	void set_display_message_type_label(Widelands::Message::Type);
+	void update_record(UI::Table<uintptr_t>::Entry_Record & er, const Widelands::Message &);
+>>>>>>> MERGE-SOURCE
 
 	UI::Table<uintptr_t> * list;
 	UI::MultilineTextarea message_body;
@@ -68,6 +78,14 @@
 	UI::Button * m_togglemodebtn;
 	UI::Button * m_centerviewbtn;
 	Mode mode;
+	// Buttons for message types
+	UI::Button * m_geologistsbtn;
+	UI::Button * m_economybtn;
+	UI::Button * m_seafaringbtn;
+	UI::Button * m_warfarebtn;
+	UI::Button * m_scenariobtn;
+	Widelands::Message::Type m_message_filter;
+	UI::Multiline_Textarea * m_display_message_type_label;
 };
 
 #endif  // end of include guard: WL_WUI_GAME_MESSAGE_MENU_H

=== modified file 'test/maps/lua_persistence.wmf/scripting/test_persistence.lua'
--- test/maps/lua_persistence.wmf/scripting/test_persistence.lua	2014-08-01 15:30:12 +0000
+++ test/maps/lua_persistence.wmf/scripting/test_persistence.lua	2014-09-27 16:11:00 +0000
@@ -49,7 +49,7 @@
    objective.done = true
 
    p:send_message("dummy msg1", "dummy msg 1")
-   msg = p:send_message("hello nice", "World", {sender="blah", field = field })
+   msg = p:send_message("hello nice", "World", {field = field })
    player_slot = map.player_slots[1]
 
    myset = Set:new{
@@ -118,7 +118,6 @@
    assert_table(msg)
    assert_equal("hello nice", msg.title)
    assert_equal("World", msg.body)
-   assert_equal("blah", msg.sender)
    assert_equal(field, msg.field)
 
    assert_table(map)

=== modified file 'test/maps/lua_testsuite.wmf/scripting/messages.lua'
--- test/maps/lua_testsuite.wmf/scripting/messages.lua	2014-09-09 08:24:10 +0000
+++ test/maps/lua_testsuite.wmf/scripting/messages.lua	2014-09-27 16:11:00 +0000
@@ -13,7 +13,6 @@
    local m = player1:send_message("Hallo", "World!")
    assert_equal("Hallo", m.title)
    assert_equal("World!", m.body)
-   assert_equal("ScriptingEngine", m.sender)
    assert_equal(0, m.sent)
    assert_equal(0, m.sent)
    assert_equal(nil, m.field)
@@ -32,10 +31,6 @@
       player1:send_message("Hallo", "World!", {status="nono"})
    end)
 end
-function messages_tests:test_sender()
-   local m = player1:send_message("Hallo", "World!", {sender="i am you"})
-   assert_equal("i am you", m.sender)
-end
 function messages_tests:test_field()
    local f = map:get_field(23,28)
    local m = player1:send_message("Hallo", "World!", {field = f})

=== modified file 'txts/README.lua'
--- txts/README.lua	2014-09-18 16:41:26 +0000
+++ txts/README.lua	2014-09-27 16:11:00 +0000
@@ -78,8 +78,13 @@
    ) .. p(_
 [[In the message window, the following additional shortcuts are available:]]
    ) .. p(
-_ "G: jumps to the location corresponding to the current message" .. "<br>"
-.. _"DELETE: archives the current message"
+_ "1: shows geologists' messages only" .. "<br>"
+.. _ "2: shows economy messages only" .. "<br>"
+.. _ "3: shows seafaring messages only" .. "<br>"
+.. _ "4: shows warfare messages only" .. "<br>"
+.. _ "5: shows scenario messages only" .. "<br>"
+.. _ "G: jumps to the location corresponding to the current message" .. "<br>"
+.. _"DELETE: archives/restores the current message"
    ) .. h2(_
 [[Online Help]]
    ) .. p( _


Follow ups