[ekiga/ds-gtk-application] UI: Added preliminary support for Actions in the main window.
- From: Damien Sandras <dsandras src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ekiga/ds-gtk-application] UI: Added preliminary support for Actions in the main window.
- Date: Tue, 4 Mar 2014 19:32:50 +0000 (UTC)
commit b95db083f6067b0c31f46045971b81182b5fcb7b
Author: Damien Sandras <dsandras beip be>
Date: Mon Mar 3 20:40:50 2014 +0100
UI: Added preliminary support for Actions in the main window.
Mainly in the call history view.
Also converted the actions toolbar into a header bar.
This is still a POC.
.../components/call-history/history-contact.cpp | 8 ++-
.../components/call-history/history-contact.h | 2 +
lib/engine/components/opal/sip-endpoint.cpp | 64 +++++++++++++++++---
lib/engine/components/opal/sip-endpoint.h | 26 +++++++--
.../gui/gtk-frontend/call-history-view-gtk.cpp | 58 ++++++++++++------
.../gui/gtk-frontend/call-history-view-gtk.h | 3 +-
lib/engine/gui/gtk-frontend/main_window.cpp | 52 +++++++++++-----
7 files changed, 164 insertions(+), 49 deletions(-)
---
diff --git a/lib/engine/components/call-history/history-contact.cpp
b/lib/engine/components/call-history/history-contact.cpp
index dea5433..a9d2cf8 100644
--- a/lib/engine/components/call-history/history-contact.cpp
+++ b/lib/engine/components/call-history/history-contact.cpp
@@ -210,8 +210,14 @@ History::Contact::get_call_start () const
return call_start;
}
-const std::string
+const std::string
History::Contact::get_call_duration () const
{
return call_duration;
}
+
+const std::string
+History::Contact::get_uri () const
+{
+ return uri;
+}
diff --git a/lib/engine/components/call-history/history-contact.h
b/lib/engine/components/call-history/history-contact.h
index e436aa8..db8cec3 100644
--- a/lib/engine/components/call-history/history-contact.h
+++ b/lib/engine/components/call-history/history-contact.h
@@ -99,6 +99,8 @@ namespace History
const std::string get_call_duration () const;
+ const std::string get_uri () const;
+
private:
boost::weak_ptr<Ekiga::ContactCore> contact_core;
diff --git a/lib/engine/components/opal/sip-endpoint.cpp b/lib/engine/components/opal/sip-endpoint.cpp
index 9b35600..f2589fb 100644
--- a/lib/engine/components/opal/sip-endpoint.cpp
+++ b/lib/engine/components/opal/sip-endpoint.cpp
@@ -38,6 +38,7 @@
#include <glib/gi18n.h>
#include "config.h"
+#include "contact-action.h"
#include "sip-endpoint.h"
#include "chat-core.h"
@@ -118,6 +119,7 @@ Opal::Sip::EndPoint::EndPoint (Opal::CallManager & _manager,
manager (_manager)
{
boost::shared_ptr<Ekiga::ChatCore> chat_core = core.get<Ekiga::ChatCore> ("chat-core");
+ boost::shared_ptr<Ekiga::ContactCore> contact_core = core.get<Ekiga::ContactCore> ("contact-core");
protocol_name = "sip";
uri_prefix = "sip:";
@@ -145,6 +147,9 @@ Opal::Sip::EndPoint::EndPoint (Opal::CallManager & _manager,
settings = boost::shared_ptr<Ekiga::Settings> (new Ekiga::Settings (SIP_SCHEMA));
settings->changed.connect (boost::bind (&EndPoint::setup, this, _1));
+
+ /* Ready to take actions */
+ register_actions (contact_core);
}
@@ -180,17 +185,41 @@ Opal::Sip::EndPoint::populate_menu (const std::string& fullname,
{
if (0 == GetConnectionCount ())
builder.add_action ("phone-pick-up", _("Call"),
- boost::bind (&Opal::Sip::EndPoint::on_dial, this, uri));
+ boost::bind (&Opal::Sip::EndPoint::on_dial, this, uri));
else
builder.add_action ("mail-forward", _("Transfer"),
- boost::bind (&Opal::Sip::EndPoint::on_transfer, this, uri));
+ boost::bind (&Opal::Sip::EndPoint::on_transfer, this, uri));
builder.add_action ("im-message-new", _("Message"),
- boost::bind (&Opal::Sip::EndPoint::on_message, this, uri, fullname));
+ boost::bind (&Opal::Sip::EndPoint::on_message, this, uri, fullname));
return true;
}
+void
+Opal::Sip::EndPoint::register_actions (boost::shared_ptr<Ekiga::ContactCore> ccore)
+{
+ ccore->add_action (Ekiga::ActionPtr (
+ new Ekiga::ContactAction ("sip-call", _("Call"),
+ boost::bind (&Opal::Sip::EndPoint::on_dial,
+ this, _1, _2),
+ boost::bind (&Opal::Sip::EndPoint::is_valid_uri,
+ this, _2))));
+ ccore->add_action (Ekiga::ActionPtr (
+ new Ekiga::ContactAction ("sip-transfer", _("Transfer"),
+ boost::bind (&Opal::Sip::EndPoint::on_transfer,
+ this, _1, _2),
+ boost::bind (&Opal::Sip::EndPoint::can_transfer,
+ this, _2))));
+ ccore->add_action (Ekiga::ActionPtr (
+ new Ekiga::ContactAction ("sip-message", _("Message"),
+ boost::bind (&Opal::Sip::EndPoint::on_message,
+ this, _1, _2),
+ boost::bind (&Opal::Sip::EndPoint::is_valid_uri,
+ this, _2))));
+}
+
+
bool
Opal::Sip::EndPoint::send_message (const std::string & _uri,
const std::string & _message)
@@ -896,20 +925,25 @@ Opal::Sip::EndPoint::OnDialogInfoReceived (const SIPDialogNotification & info)
}
-void Opal::Sip::EndPoint::on_dial (std::string uri)
+void Opal::Sip::EndPoint::on_dial (Ekiga::ContactPtr contact,
+ const std::string & uri)
{
+ // FIXME: I really think Ekiga::Contacts are TelephonyContacts and, as such,
+ // should have an uri. All methods should act on Contacts, the Ekiga central
+ // point of things.
manager.dial (uri);
}
-void Opal::Sip::EndPoint::on_message (std::string uri,
- std::string name)
+void Opal::Sip::EndPoint::on_message (Ekiga::ContactPtr contact,
+ const std::string & uri)
{
- dialect->start_chat_with (uri, name);
+ dialect->start_chat_with (uri, contact->get_name ());
}
-void Opal::Sip::EndPoint::on_transfer (std::string uri)
+void Opal::Sip::EndPoint::on_transfer (Ekiga::ContactPtr contact,
+ const std::string & uri)
{
/* FIXME : we don't handle several calls here */
for (PSafePtr<OpalConnection> connection(connectionsActive, PSafeReference); connection != NULL;
++connection)
@@ -939,3 +973,17 @@ Opal::Sip::EndPoint::update_aor_map (std::map<std::string, std::string> _account
PWaitAndSignal m(aorMutex);
accounts = _accounts;
}
+
+
+bool
+Opal::Sip::EndPoint::is_valid_uri (const std::string & uri)
+{
+ return (!uri.empty () && (uri.find ("sip:") == 0 || uri.find (':') == string::npos));
+}
+
+
+bool
+Opal::Sip::EndPoint::can_transfer (const std::string & uri)
+{
+ return (GetConnectionCount () > 0 && is_valid_uri (uri));
+}
diff --git a/lib/engine/components/opal/sip-endpoint.h b/lib/engine/components/opal/sip-endpoint.h
index b6b806a..ba3ce0f 100644
--- a/lib/engine/components/opal/sip-endpoint.h
+++ b/lib/engine/components/opal/sip-endpoint.h
@@ -76,7 +76,7 @@ namespace Opal {
/* Set up endpoint: all options or a specific setting */
void setup (std::string setting = "");
-
+
/* Service */
const std::string get_name () const
{ return "opal-sip-endpoint"; }
@@ -90,6 +90,10 @@ namespace Opal {
Ekiga::MenuBuilder& builder);
+ /* Register actions on the ContactCore */
+ void register_actions (boost::shared_ptr<Ekiga::ContactCore> contact_core);
+
+
/* Chat subsystem */
bool send_message (const std::string & uri,
const std::string & message);
@@ -166,13 +170,25 @@ namespace Opal {
SIPURL GetRegisteredPartyName (const SIPURL & host,
const OpalTransport & transport);
+ /* Return true if URI can be handled by the endpoint,
+ * false otherwise.
+ */
+ bool is_valid_uri (const std::string & uri);
+
+ /* Return true if the endpoint is currently handling one or more calls,
+ * and there is an active call to transfer, false otherwise.
+ */
+ bool can_transfer (const std::string & uri);
+
/* Callbacks */
private:
- void on_dial (std::string uri);
- void on_message (std::string uri,
- std::string name);
- void on_transfer (std::string uri);
+ void on_dial (Ekiga::ContactPtr contact,
+ const std::string & uri);
+ void on_message (Ekiga::ContactPtr contact,
+ const std::string & uri);
+ void on_transfer (Ekiga::ContactPtr contact,
+ const std::string & uri);
void push_message_in_main (const std::string uri,
const std::string name,
diff --git a/lib/engine/gui/gtk-frontend/call-history-view-gtk.cpp
b/lib/engine/gui/gtk-frontend/call-history-view-gtk.cpp
index 5f28a48..fe0700c 100644
--- a/lib/engine/gui/gtk-frontend/call-history-view-gtk.cpp
+++ b/lib/engine/gui/gtk-frontend/call-history-view-gtk.cpp
@@ -43,6 +43,15 @@
#include "menu-builder-tools.h"
#include "menu-builder-gtk.h"
#include "gm-cell-renderer-bitext.h"
+#include "live-object-menu.h"
+
+
+struct null_deleter
+{
+ void operator()(void const *) const
+ {
+ }
+};
struct _CallHistoryViewGtkPrivate
@@ -52,6 +61,8 @@ struct _CallHistoryViewGtkPrivate
{}
boost::shared_ptr<History::Book> book;
+ boost::shared_ptr<Ekiga::ActorMenu> menu;
+ boost::shared_ptr<Ekiga::ContactActorMenu> contact_menu;
GtkListStore* store;
GtkTreeView* tree;
boost::signals2::scoped_connection connection;
@@ -155,15 +166,16 @@ on_clicked (GtkWidget *tree,
GdkEventButton *event,
gpointer data)
{
- History::Book *book = NULL;
+ GtkWidget *menu = NULL;
+ GtkBuilder *builder = NULL;
GtkTreeModel *model = NULL;
GtkTreePath *path = NULL;
GtkTreeIter iter;
- Ekiga::Contact *contact = NULL;
+ History::Contact *contact = NULL;
- book = (History::Book*)data;
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree));
+ CallHistoryViewGtk *self = CALL_HISTORY_VIEW_GTK (data);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree));
if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree),
(gint) event->x, (gint) event->y,
@@ -175,23 +187,26 @@ on_clicked (GtkWidget *tree,
COLUMN_CONTACT, &contact,
-1);
-
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
- MenuBuilderGtk builder;
- if (contact != NULL)
- contact->populate_menu (builder);
- if (!builder.empty())
- builder.add_separator ();
- builder.add_action ("gtk-clear", _("Clear List"),
- boost::bind (&History::Book::clear, book));
- gtk_widget_show_all (builder.menu);
- gtk_menu_popup (GTK_MENU (builder.menu), NULL, NULL,
+ builder = gtk_builder_new ();
+
+ self->priv->contact_menu->set_data (Ekiga::ContactPtr (contact, null_deleter ()),
+ contact->get_uri ());
+ std::string menu_content = self->priv->contact_menu->as_xml () + self->priv->menu->as_xml ();
+ gtk_builder_add_from_string (builder,
+ Ekiga::ActorMenu::get_xml_menu ("popup", menu_content, true).c_str (),
+ -1, NULL);
+ menu = gtk_menu_new_from_model (G_MENU_MODEL (gtk_builder_get_object (builder, "popup")));
+ gtk_widget_insert_action_group (menu, "win", G_ACTION_GROUP (g_application_get_default ()));
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
NULL, NULL, event->button, event->time);
- g_object_ref_sink (builder.menu);
+ g_object_ref (menu);
+ g_object_unref (builder);
}
if (event->type == GDK_2BUTTON_PRESS) {
+ std::cout << "FIXME" << std::endl << std::flush;
if (contact != NULL) {
Ekiga::TriggerMenuBuilder builder;
@@ -297,7 +312,8 @@ call_history_view_gtk_class_init (CallHistoryViewGtkClass* klass)
/* public api */
GtkWidget *
-call_history_view_gtk_new (boost::shared_ptr<History::Book> book)
+call_history_view_gtk_new (boost::shared_ptr<History::Book> book,
+ boost::shared_ptr<Ekiga::ContactCore> ccore)
{
CallHistoryViewGtk* self = NULL;
@@ -349,7 +365,7 @@ call_history_view_gtk_new (boost::shared_ptr<History::Book> book)
g_signal_connect (selection, "changed",
G_CALLBACK (on_selection_changed), self);
g_signal_connect (self->priv->tree, "event-after",
- G_CALLBACK (on_clicked), &(*book));
+ G_CALLBACK (on_clicked), self);
/* connect to the signal */
self->priv->connection = book->updated.connect (boost::bind (&on_book_updated, self));
@@ -357,7 +373,13 @@ call_history_view_gtk_new (boost::shared_ptr<History::Book> book)
/* initial populate */
on_book_updated(self);
- return (GtkWidget*)self;
+ /* register book actions */
+ self->priv->menu =
+ boost::shared_ptr<Ekiga::ActorMenu> (new Ekiga::ActorMenu (*book));
+ self->priv->contact_menu =
+ boost::shared_ptr<Ekiga::ContactActorMenu> (new Ekiga::ContactActorMenu (*ccore));
+
+ return GTK_WIDGET (self);
}
void
diff --git a/lib/engine/gui/gtk-frontend/call-history-view-gtk.h
b/lib/engine/gui/gtk-frontend/call-history-view-gtk.h
index b34d552..58ae367 100644
--- a/lib/engine/gui/gtk-frontend/call-history-view-gtk.h
+++ b/lib/engine/gui/gtk-frontend/call-history-view-gtk.h
@@ -50,7 +50,8 @@ typedef struct _CallHistoryViewGtkClass CallHistoryViewGtkClass;
*/
/* creating the widget, connected to an History::Book object */
-GtkWidget *call_history_view_gtk_new (boost::shared_ptr<History::Book> book);
+GtkWidget *call_history_view_gtk_new (boost::shared_ptr<History::Book> book,
+ boost::shared_ptr<Ekiga::ContactCore> ccore);
/* Whatever is selected, we want the view to populate the given menu builder
diff --git a/lib/engine/gui/gtk-frontend/main_window.cpp b/lib/engine/gui/gtk-frontend/main_window.cpp
index feed254..a585d55 100644
--- a/lib/engine/gui/gtk-frontend/main_window.cpp
+++ b/lib/engine/gui/gtk-frontend/main_window.cpp
@@ -826,6 +826,11 @@ ekiga_main_window_init_actions_toolbar (EkigaMainWindow *mw)
GtkWidget *box = NULL;
GtkWidget *button = NULL;
+ GtkIconSize toolbar_size;
+ gint toolbar_size_px = 0;
+ gint menu_size_px = 0;
+ gint margin_px = 0;
+
g_return_if_fail (EKIGA_IS_MAIN_WINDOW (mw));
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (mw)),
@@ -834,23 +839,31 @@ ekiga_main_window_init_actions_toolbar (EkigaMainWindow *mw)
gtk_style_context_set_junction_sides (gtk_widget_get_style_context (GTK_WIDGET (mw)),
GTK_JUNCTION_BOTTOM);
- mw->priv->actions_toolbar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ mw->priv->actions_toolbar = gtk_header_bar_new ();
- button = gtk_toggle_button_new ();
+ /* Compute the image button margin */
+ g_object_get (gtk_settings_get_default (), "gtk-toolbar-icon-size", &toolbar_size, NULL);
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &menu_size_px, NULL);
+ gtk_icon_size_lookup (toolbar_size, &toolbar_size_px, NULL);
+ margin_px = (gint) floor ((toolbar_size_px - menu_size_px) / 2.0);
+
+ /* Start packing buttons */
+ mw->priv->preview_button = gtk_toggle_button_new ();
image = gtk_image_new_from_icon_name ("camera-web-symbolic", GTK_ICON_SIZE_MENU);
- g_object_set (G_OBJECT (image), "margin", 3, NULL);
- gtk_button_set_image (GTK_BUTTON (button), image);
- gtk_widget_set_tooltip_text (GTK_WIDGET (button),
+ g_object_set (G_OBJECT (image), "margin", margin_px, NULL);
+ gtk_button_set_image (GTK_BUTTON (mw->priv->preview_button), image);
+ gtk_widget_set_tooltip_text (GTK_WIDGET (mw->priv->preview_button),
_("Display images from your camera device"));
- gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), "win.enable-preview");
- gtk_box_pack_start (GTK_BOX (mw->priv->actions_toolbar), button, FALSE, FALSE, 0);
- gtk_widget_set_margin_left (button, 6);
- gtk_widget_set_margin_right (button, 6);
+ gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (mw->priv->preview_button),
+ "win.enable-preview");
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (mw->priv->actions_toolbar), mw->priv->preview_button);
+ gtk_widget_set_margin_left (mw->priv->preview_button, 6);
+ gtk_widget_set_margin_right (mw->priv->preview_button, 6);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
button = gtk_toggle_button_new ();
image = gtk_image_new_from_icon_name ("avatar-default-symbolic", GTK_ICON_SIZE_MENU);
- g_object_set (G_OBJECT (image), "margin", 3, NULL);
+ g_object_set (G_OBJECT (image), "margin", margin_px, NULL);
gtk_button_set_image (GTK_BUTTON (button), image);
gtk_widget_set_tooltip_text (GTK_WIDGET (button),
_("View the contacts list"));
@@ -859,7 +872,7 @@ ekiga_main_window_init_actions_toolbar (EkigaMainWindow *mw)
button = gtk_toggle_button_new ();
image = gtk_image_new_from_icon_name ("input-dialpad-symbolic", GTK_ICON_SIZE_MENU);
- g_object_set (G_OBJECT (image), "margin", 3, NULL);
+ g_object_set (G_OBJECT (image), "margin", margin_px, NULL);
gtk_button_set_image (GTK_BUTTON (button), image);
gtk_widget_set_tooltip_text (GTK_WIDGET (button),
_("View the dialpad"));
@@ -868,7 +881,7 @@ ekiga_main_window_init_actions_toolbar (EkigaMainWindow *mw)
button = gtk_toggle_button_new ();
image = gtk_image_new_from_icon_name ("document-open-recent-symbolic", GTK_ICON_SIZE_MENU);
- g_object_set (G_OBJECT (image), "margin", 3, NULL);
+ g_object_set (G_OBJECT (image), "margin", margin_px, NULL);
gtk_button_set_image (GTK_BUTTON (button), image);
gtk_widget_set_tooltip_text (GTK_WIDGET (button),
_("View the call history"));
@@ -880,17 +893,17 @@ ekiga_main_window_init_actions_toolbar (EkigaMainWindow *mw)
gtk_style_context_add_class (gtk_widget_get_style_context (box),
GTK_STYLE_CLASS_LINKED);
- gtk_box_pack_start (GTK_BOX (mw->priv->actions_toolbar), box, FALSE, FALSE, 0);
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (mw->priv->actions_toolbar), box);
gtk_widget_set_margin_left (box, 6);
gtk_widget_set_margin_right (box, 6);
button = gtk_menu_button_new ();
image = gtk_image_new_from_icon_name ("emblem-system-symbolic", GTK_ICON_SIZE_MENU);
- g_object_set (G_OBJECT (image), "margin", 3, NULL);
+ g_object_set (G_OBJECT (image), "margin", margin_px, NULL);
gtk_button_set_image (GTK_BUTTON (button), image);
gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button),
G_MENU_MODEL (gtk_builder_get_object (mw->priv->builder, "menubar")));
- gtk_box_pack_end (GTK_BOX (mw->priv->actions_toolbar), button, FALSE, FALSE, 0);
+ gtk_header_bar_pack_end (GTK_HEADER_BAR (mw->priv->actions_toolbar), button);
gtk_widget_set_margin_left (button, 6);
gtk_widget_set_margin_right (button, 6);
}
@@ -906,6 +919,10 @@ ekiga_main_window_init_menu (EkigaMainWindow *mw)
" </section>"
" <section>"
" <item>"
+ " <attribute name='label' translatable='yes'>_Aontact</attribute>"
+ " <attribute name='action'>win.clear</attribute>"
+ " </item>"
+ " <item>"
" <attribute name='label' translatable='yes'>_Add Contact</attribute>"
" <attribute name='action'>win.add</attribute>"
" </item>"
@@ -1008,7 +1025,8 @@ ekiga_main_window_init_history (EkigaMainWindow *mw)
boost::shared_ptr<History::Book> history_book
= mw->priv->history_source->get_book ();
- mw->priv->call_history_view = call_history_view_gtk_new (history_book);
+ mw->priv->call_history_view = call_history_view_gtk_new (history_book,
+ mw->priv->contact_core);
label = gtk_label_new (_("Call history"));
mw->priv->call_history_page_number =
@@ -1139,6 +1157,8 @@ ekiga_main_window_dispose (GObject* gobject)
g_object_unref (mw->priv->roster_view);
mw->priv->roster_view = NULL;
}
+ g_object_unref (mw->priv->builder);
+ mw->priv->builder = NULL;
G_OBJECT_CLASS (ekiga_main_window_parent_class)->dispose (gobject);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]