Ejemplo n.º 1
0
void Gobby::UserJoinCommands::UserJoinInfo::
	add_text_user_properties(std::vector<GParameter>& params,
	                         TextSessionView& view)
{
	InfTextSession* session = view.get_session();

	GParameter hue_param = { "hue", { 0 } };
	g_value_init(&hue_param.value, G_TYPE_DOUBLE);
	g_value_set_double(&hue_param.value,
	                   m_commands.m_preferences.user.hue);
	params.push_back(hue_param);

	GParameter vector_param = { "vector", { 0 } };
	g_value_init(&vector_param.value, INF_ADOPTED_TYPE_STATE_VECTOR);

	g_value_take_boxed(&vector_param.value, inf_adopted_state_vector_copy(
		inf_adopted_algorithm_get_current(
			inf_adopted_session_get_algorithm(
				INF_ADOPTED_SESSION(session)))));
	params.push_back(vector_param);

	GParameter caret_param = { "caret-position", { 0 } };
	g_value_init(&caret_param.value, G_TYPE_UINT);

	GtkTextBuffer* buffer = GTK_TEXT_BUFFER(view.get_text_buffer());
	GtkTextMark* mark = gtk_text_buffer_get_insert(buffer);
	GtkTextIter caret_iter;

	gtk_text_buffer_get_iter_at_mark(buffer, &caret_iter, mark);
	g_value_set_uint(&caret_param.value,
	                 gtk_text_iter_get_offset(&caret_iter));
	params.push_back(caret_param);
}
Ejemplo n.º 2
0
void Gobby::EditCommands::on_active_user_changed(InfUser* active_user)
{
	g_assert(m_current_view != NULL);

	if(active_user != NULL)
	{
		InfTextSession* session = m_current_view->get_session();
		InfAdoptedAlgorithm* algorithm =
			inf_adopted_session_get_algorithm(
				INF_ADOPTED_SESSION(session));
		GtkTextBuffer* buffer = GTK_TEXT_BUFFER(
			m_current_view->get_text_buffer());

		m_header.action_edit_undo->set_sensitive(
			inf_adopted_algorithm_can_undo(
				algorithm, INF_ADOPTED_USER(active_user)));
		m_header.action_edit_redo->set_sensitive(
			inf_adopted_algorithm_can_redo(
				algorithm, INF_ADOPTED_USER(active_user)));

		m_header.action_edit_cut->set_sensitive(
			gtk_text_buffer_get_has_selection(buffer));
		m_header.action_edit_paste->set_sensitive(true);
	}
	else
	{
		m_header.action_edit_undo->set_sensitive(false);
		m_header.action_edit_redo->set_sensitive(false);
		m_header.action_edit_cut->set_sensitive(false);
		m_header.action_edit_paste->set_sensitive(false);
	}
}
Ejemplo n.º 3
0
static void
on_join_finished(InfcUserRequest* request,
                 InfUser* user,
                 gpointer user_data)
{
  InfTestGtkBrowserWindow* test;
  InfAdoptedSession* session;
  InfAdoptedAlgorithm* algorithm;
  gboolean undo;
  gboolean redo;

  test = (InfTestGtkBrowserWindow*)user_data;

  inf_text_gtk_buffer_set_active_user(test->buffer, INF_TEXT_USER(user));
  gtk_text_view_set_editable(GTK_TEXT_VIEW(test->textview), TRUE);

  test->user = user;

  session = INF_ADOPTED_SESSION(infc_session_proxy_get_session(test->proxy));
  algorithm = inf_adopted_session_get_algorithm(session);

  undo = inf_adopted_algorithm_can_undo(algorithm, INF_ADOPTED_USER(user));
  redo = inf_adopted_algorithm_can_redo(algorithm, INF_ADOPTED_USER(user));

  gtk_widget_set_sensitive(test->undo_button, undo);
  gtk_widget_set_sensitive(test->redo_button, redo);
}
Ejemplo n.º 4
0
static void
inf_adopted_session_synchronization_complete(InfSession* session,
                                             InfXmlConnection* connection)
{
  InfAdoptedSessionPrivate* priv;
  InfSessionStatus status;

  priv = INF_ADOPTED_SESSION_PRIVATE(session);
  g_object_get(G_OBJECT(session), "status", &status, NULL);

  INF_SESSION_CLASS(parent_class)->synchronization_complete(
    session,
    connection
  );

  if(status == INF_SESSION_SYNCHRONIZING)
  {
    inf_user_table_foreach_user(
      inf_session_get_user_table(session),
      inf_adopted_session_synchronization_complete_foreach_user_func,
      NULL
    );

    /* Create adOPTed algorithm upon successful synchronization */
    g_assert(priv->algorithm == NULL);
    inf_adopted_session_create_algorithm(INF_ADOPTED_SESSION(session));
  }
}
Ejemplo n.º 5
0
static void
inf_adopted_session_set_property(GObject* object,
                                 guint prop_id,
                                 const GValue* value,
                                 GParamSpec* pspec)
{
  InfAdoptedSession* session;
  InfAdoptedSessionPrivate* priv;

  session = INF_ADOPTED_SESSION(object);
  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  switch(prop_id)
  {
  case PROP_IO:
    g_assert(priv->io == NULL); /* construct only */
    priv->io = INF_IO(g_value_dup_object(value));
    break;
  case PROP_MAX_TOTAL_LOG_SIZE:
    priv->max_total_log_size = g_value_get_uint(value);
    break;
  case PROP_ALGORITHM:
    /* read only */
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
    break;
  }
}
Ejemplo n.º 6
0
static void
on_synchronization_complete(InfSession* session,
                            InfXmlConnection* connection,
                            gpointer user_data)
{
  InfTestGtkBrowserWindow* test;
  InfAdoptedAlgorithm* algorithm;

  test = (InfTestGtkBrowserWindow*)user_data;
  session = infc_session_proxy_get_session(test->proxy);
  algorithm = inf_adopted_session_get_algorithm(INF_ADOPTED_SESSION(session));

  g_signal_connect(
    G_OBJECT(algorithm),
    "can-undo-changed",
    G_CALLBACK(on_can_undo_changed),
    test
  );

  g_signal_connect(
    G_OBJECT(algorithm),
    "can-redo-changed",
    G_CALLBACK(on_can_redo_changed),
    test
  );

  request_join(test, g_get_user_name());
}
Ejemplo n.º 7
0
static void
inf_adopted_session_get_property(GObject* object,
                                 guint prop_id,
                                 GValue* value,
                                 GParamSpec* pspec)
{
  InfAdoptedSession* session;
  InfAdoptedSessionPrivate* priv;

  session = INF_ADOPTED_SESSION(object);
  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  switch(prop_id)
  {
  case PROP_IO:
    g_value_set_object(value, G_OBJECT(priv->io));
    break;
  case PROP_MAX_TOTAL_LOG_SIZE:
    g_value_set_uint(value, priv->max_total_log_size);
    break;
  case PROP_ALGORITHM:
    g_value_set_object(value, G_OBJECT(priv->algorithm));
    break;
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
    break;
  }
}
Ejemplo n.º 8
0
void Gobby::EditCommands::on_redo()
{
	g_assert(m_current_view != NULL);

	gulong i_ = g_signal_connect_after(m_current_view->get_text_buffer(), "insert-text", G_CALLBACK(recaret_i), NULL);
	gulong e_ = g_signal_connect_after(m_current_view->get_text_buffer(), "delete-range", G_CALLBACK(recaret_e), NULL);

	inf_adopted_session_redo(
		INF_ADOPTED_SESSION(m_current_view->get_session()),
		INF_ADOPTED_USER(m_current_view->get_active_user()),
		m_current_view->get_undo_grouping().get_redo_size()
	);

	g_signal_handler_disconnect(m_current_view->get_text_buffer(), i_);
	g_signal_handler_disconnect(m_current_view->get_text_buffer(), e_);

	if(check)
	{
		GtkTextIter check_iter;
		gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(m_current_view->get_text_buffer()), &check_iter, check);
		gtk_text_buffer_select_range(GTK_TEXT_BUFFER(m_current_view->get_text_buffer()), &check_iter, &check_iter);
		gtk_text_buffer_delete_mark(GTK_TEXT_BUFFER(m_current_view->get_text_buffer()), check);
		check = NULL;
	}

	m_current_view->scroll_to_cursor_position(0.0);
}
Ejemplo n.º 9
0
static void
inf_adopted_session_noop_timeout_func(gpointer user_data)
{
  InfAdoptedSession* session;
  InfAdoptedSessionPrivate* priv;
  InfAdoptedOperation* op;
  InfAdoptedRequest* request;

  session = INF_ADOPTED_SESSION(user_data);
  priv = INF_ADOPTED_SESSION_PRIVATE(session);
  priv->noop_timeout = NULL;
  g_assert(priv->next_noop_user != NULL);

  op = INF_ADOPTED_OPERATION(inf_adopted_no_operation_new());
  request = inf_adopted_algorithm_generate_request_noexec(
    priv->algorithm,
    priv->next_noop_user->user,
    op
  );
  g_object_unref(op);

  /* This resets noop_time for this user, determines the next user for
   * which to generate a noop request and schedules the new timeout. */
  inf_adopted_session_broadcast_request(session, request);
  g_object_unref(request);
}
Ejemplo n.º 10
0
static void
on_redo_button_clicked(GtkButton* button,
                       gpointer user_data)
{
  InfTestGtkBrowserWindow* test;
  InfAdoptedSession* session;

  test = (InfTestGtkBrowserWindow*)user_data;
  session = INF_ADOPTED_SESSION(infc_session_proxy_get_session(test->proxy));
  inf_adopted_session_redo(session, INF_ADOPTED_USER(test->user));
}
Ejemplo n.º 11
0
static void
inf_adopted_session_constructor_foreach_local_user_func(InfUser* user,
                                                        gpointer user_data)
{
  g_assert(INF_ADOPTED_IS_USER(user));

  inf_adopted_session_local_user_added(
    INF_ADOPTED_SESSION(user_data),
    INF_ADOPTED_USER(user)
  );
}
Ejemplo n.º 12
0
static void
inf_adopted_session_dispose(GObject* object)
{
  InfAdoptedSession* session;
  InfAdoptedSessionPrivate* priv;
  InfUserTable* user_table;

  session = INF_ADOPTED_SESSION(object);
  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  user_table = inf_session_get_user_table(INF_SESSION(session));

  inf_signal_handlers_disconnect_by_func(
    G_OBJECT(user_table),
    G_CALLBACK(inf_adopted_session_add_local_user_cb),
    session
  );

  inf_signal_handlers_disconnect_by_func(
    G_OBJECT(user_table),
    G_CALLBACK(inf_adopted_session_remove_local_user_cb),
    session
  );

  if(priv->noop_timeout != NULL)
  {
    inf_io_remove_timeout(priv->io, priv->noop_timeout);
    priv->noop_timeout = NULL;
  }

  /* This calls the close vfunc if the session is running, in which we
   * free the local users. */
  G_OBJECT_CLASS(parent_class)->dispose(object);

  g_assert(priv->local_users == NULL);

  if(priv->algorithm != NULL)
  {
    inf_signal_handlers_disconnect_by_func(
      G_OBJECT(priv->algorithm),
      G_CALLBACK(inf_adopted_session_execute_request_cb),
      session
    );

    g_object_unref(G_OBJECT(priv->algorithm));
    priv->algorithm = NULL;
  }

  if(priv->io != NULL)
  {
    g_object_unref(G_OBJECT(priv->io));
    priv->io = NULL;
  }
}
Ejemplo n.º 13
0
static void
inf_adopted_session_add_local_user_cb(InfUserTable* user_table,
                                      InfUser* user,
                                      gpointer user_data)
{
  g_assert(INF_ADOPTED_IS_USER(user));

  inf_adopted_session_local_user_added(
    INF_ADOPTED_SESSION(user_data),
    INF_ADOPTED_USER(user)
  );
}
Ejemplo n.º 14
0
static gboolean
inf_adopted_session_process_xml_sync(InfSession* session,
                                     InfXmlConnection* connection,
                                     const xmlNodePtr xml,
                                     GError** error)
{
  InfAdoptedSessionClass* session_class;
  InfAdoptedRequest* request;
  InfAdoptedUser* user;
  InfAdoptedRequestLog* log;

  if(strcmp((const char*)xml->name, "sync-request") == 0)
  {
    session_class = INF_ADOPTED_SESSION_GET_CLASS(session);
    g_assert(session_class->xml_to_request != NULL);

    request = session_class->xml_to_request(
      INF_ADOPTED_SESSION(session),
      xml,
      NULL, /* TODO: Diff to previous request, if any. */
      TRUE,
      error
    );

    if(request == NULL) return FALSE;

    user = INF_ADOPTED_USER(
      inf_user_table_lookup_user_by_id(
        inf_session_get_user_table(session),
        inf_adopted_request_get_user_id(request)
      )
    );

    log = inf_adopted_user_get_request_log(user);
    if(inf_adopted_session_validate_request(log, request, error) == FALSE)
    {
      g_object_unref(request);
      return FALSE;
    }

    inf_adopted_request_log_add_request(log, request);
    g_object_unref(request);

    return TRUE;
  }

  return INF_SESSION_CLASS(parent_class)->process_xml_sync(
    session,
    connection, 
    xml,
    error
  );
}
Ejemplo n.º 15
0
static void
inf_adopted_session_finalize(GObject* object)
{
  InfAdoptedSession* session;
  InfAdoptedSessionPrivate* priv;

  session = INF_ADOPTED_SESSION(object);
  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  /* Should have been freed in close, called by dispose */
  g_assert(priv->local_users == NULL);

  G_OBJECT_CLASS(parent_class)->finalize(object);
}
Ejemplo n.º 16
0
static void
inf_adopted_session_execute_request_cb(InfAdoptedAlgorithm* algorithm,
                                       InfAdoptedUser* user,
                                       InfAdoptedRequest* request,
                                       gboolean apply,
                                       gpointer user_data)
{
  InfAdoptedSession* session;
  InfAdoptedSessionPrivate* priv;
  GSList* item;
  InfAdoptedSessionLocalUser* local;
  guint id;

  session = INF_ADOPTED_SESSION(user_data);
  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  if(inf_adopted_request_affects_buffer(request))
  {
    id = inf_adopted_request_get_user_id(request);

    /* A request has been executed, meaning we are no longer up to date. Send
     * a noop in some time, so that others know what we already processed. */
    for(item = priv->local_users; item != NULL; item = g_slist_next(item))
    {
      local = (InfAdoptedSessionLocalUser*)item->data;
      if(local->noop_time == 0)
        /* Except we issued the request ourselves, of course. */
        if(inf_user_get_id(INF_USER(local->user)) != id)
          inf_adopted_session_start_noop_timer(session, local);
    }
  }

  /* Mark inactive users active if they do something */
  /* Note: This behaviour is implicitly performed by both client and server,
   * and requires no further network traffic. However, users explictely have
   * to be set inactive. */
  if(inf_adopted_request_get_request_type(request) != INF_ADOPTED_REQUEST_DO ||
     !INF_ADOPTED_IS_NO_OPERATION(inf_adopted_request_get_operation(request)))
  {
    /* TODO: We should offer a virtual function to flush all requests for
     * local users, either here or even in InfSession via a vfunc, so that
     * we don't accidentally make local users active by a delayed request. */
    if(inf_user_get_status(INF_USER(user)) == INF_USER_INACTIVE)
      g_object_set(G_OBJECT(user), "status", INF_USER_ACTIVE, NULL);
  }
}
Ejemplo n.º 17
0
static void
inf_adopted_session_init(GTypeInstance* instance,
                         gpointer g_class)
{
  InfAdoptedSession* session;
  InfAdoptedSessionPrivate* priv;

  session = INF_ADOPTED_SESSION(instance);
  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  priv->io = NULL;
  priv->max_total_log_size = 2048;
  priv->algorithm = NULL;
  priv->local_users = NULL;
  priv->noop_timeout = NULL;
  priv->next_noop_user = NULL;
}
Ejemplo n.º 18
0
static void
inf_adopted_session_to_xml_sync(InfSession* session,
                                xmlNodePtr parent)
{
  InfAdoptedSessionPrivate* priv;
  InfAdoptedSessionToXmlSyncForeachData foreach_data;

  priv = INF_ADOPTED_SESSION_PRIVATE(session);
  g_assert(priv->algorithm != NULL);

  INF_SESSION_CLASS(parent_class)->to_xml_sync(session, parent);

  foreach_data.session = INF_ADOPTED_SESSION(session);
  foreach_data.parent_xml = parent;

  inf_user_table_foreach_user(
    inf_session_get_user_table(session),
    inf_adopted_session_to_xml_sync_foreach_user_func,
    &foreach_data
  );
}
Ejemplo n.º 19
0
static void
infinoted_plugin_record_session_added(const InfBrowserIter* iter,
                                      InfSessionProxy* proxy,
                                      gpointer plugin_info,
                                      gpointer session_info)
{
  InfinotedPluginRecord* plugin;
  InfinotedPluginRecordSessionInfo* info;
  InfSession* session;
  gchar* title;
  gchar* pos;
  InfAdoptedSessionRecord* record;

  plugin = (InfinotedPluginRecord*)plugin_info;
  info = (InfinotedPluginRecordSessionInfo*)session_info;

  g_object_get(G_OBJECT(proxy), "session", &session, NULL);
  g_assert(INF_ADOPTED_IS_SESSION(session));

  title = inf_browser_get_path(
    INF_BROWSER(infinoted_plugin_manager_get_directory(plugin->manager)),
    iter
  );

  for(pos = title + 1; *pos != '\0'; ++pos)
    if(*pos == '/')
      *pos = '_';

  info->plugin = plugin;
  info->record = infinoted_plugin_record_start(
    plugin,
    INF_ADOPTED_SESSION(session),
    title + 1
  );

  g_object_set_data(G_OBJECT(session), "infinoted-record", info->record);

  g_object_unref(session);
  g_free(title);
}
Ejemplo n.º 20
0
static void
inf_test_mass_join_join_user(InfTestMassJoiner* joiner)
{
    InfSession* session;
    InfAdoptedStateVector* v;
    GParameter params[3] = {
        { "name", { 0 } },
        { "vector", { 0 } },
        { "caret-position", { 0 } }
    };

    g_value_init(&params[0].value, G_TYPE_STRING);
    g_value_init(&params[1].value, INF_ADOPTED_TYPE_STATE_VECTOR);
    g_value_init(&params[2].value, G_TYPE_UINT);

    g_value_set_static_string(&params[0].value, joiner->username);

    g_object_get(G_OBJECT(joiner->session), "session", &session, NULL);
    v = inf_adopted_algorithm_get_current(
            inf_adopted_session_get_algorithm(INF_ADOPTED_SESSION(session))
        );
    g_object_unref(session);

    g_value_set_boxed(&params[1].value, v);
    g_value_set_uint(&params[2].value, 0u);

    inf_session_proxy_join_user(
        INF_SESSION_PROXY(joiner->session),
        3,
        params,
        inf_test_mass_join_user_join_finished_cb,
        joiner
    );

    g_value_unset(&params[2].value);
    g_value_unset(&params[1].value);
    g_value_unset(&params[0].value);
}
Ejemplo n.º 21
0
static void
inf_adopted_session_remove_local_user_cb(InfUserTable* user_table,
                                         InfUser* user,
                                         gpointer user_data)
{
  InfAdoptedSession* session;
  InfAdoptedSessionPrivate* priv;
  InfAdoptedSessionLocalUser* local;

  session = INF_ADOPTED_SESSION(user_data);
  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  local = inf_adopted_session_lookup_local_user(
    session,
    INF_ADOPTED_USER(user)
  );
  g_assert(local != NULL);

  inf_adopted_session_stop_noop_timer(session, local);
  inf_adopted_state_vector_free(local->last_send_vector);
  priv->local_users = g_slist_remove(priv->local_users, local);
  g_slice_free(InfAdoptedSessionLocalUser, local);
}
Ejemplo n.º 22
0
void Gobby::EditCommands::on_sync_complete()
{
	g_assert(m_current_view != NULL);
	InfTextSession* session = m_current_view->get_session();

	InfAdoptedAlgorithm* algorithm = inf_adopted_session_get_algorithm(
		INF_ADOPTED_SESSION(session));

	m_can_undo_changed_handler = g_signal_connect(
		G_OBJECT(algorithm), "can-undo-changed",
		G_CALLBACK(&on_can_undo_changed_static), this);

	m_can_redo_changed_handler = g_signal_connect(
		G_OBJECT(algorithm), "can-redo-changed",
		G_CALLBACK(&on_can_redo_changed_static), this);

	if(m_synchronization_complete_handler != 0)
	{
		g_signal_handler_disconnect(
			G_OBJECT(session),
			m_synchronization_complete_handler);
		m_synchronization_complete_handler = 0;
	}
}
Ejemplo n.º 23
0
static void
request_join(InfTestGtkBrowserWindow* test,
             const gchar* user_name)
{
  InfcUserRequest* request;
  InfAdoptedStateVector* v;
  GError* error;
  GtkTextBuffer* buffer;
  GtkTextMark* mark;
  GtkTextIter iter;
  GParameter params[3] = {
    { "name", { 0 } },
    { "vector", { 0 } },
    { "caret-position", { 0 } }
  };

  g_value_init(&params[0].value, G_TYPE_STRING);
  g_value_init(&params[1].value, INF_ADOPTED_TYPE_STATE_VECTOR);
  g_value_init(&params[2].value, G_TYPE_UINT);

  g_value_set_static_string(&params[0].value, user_name);

  /* Use current state vector. Infinote should already do this. */
  v = inf_adopted_state_vector_copy(
    inf_adopted_algorithm_get_current(
      inf_adopted_session_get_algorithm(
        INF_ADOPTED_SESSION(infc_session_proxy_get_session(test->proxy))
      )
    )
  );

  g_value_take_boxed(&params[1].value, v);

  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(test->textview));
  mark = gtk_text_buffer_get_insert(buffer);
  gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
  g_value_set_uint(&params[2].value, gtk_text_iter_get_offset(&iter));

  error = NULL;
  request = infc_session_proxy_join_user(test->proxy, params, 3, &error);

  /* TODO: Free GValues? */

  if(request == NULL)
  {
    set_error(test, "Failed to request user join", error->message);
  }
  else
  {
    g_signal_connect_after(
      G_OBJECT(request),
      "failed",
      G_CALLBACK(on_join_failed),
      test
    );

    g_signal_connect_after(
      G_OBJECT(request),
      "finished",
      G_CALLBACK(on_join_finished),
      test
    );
  }
}
Ejemplo n.º 24
0
static GObject*
inf_adopted_session_constructor(GType type,
                                guint n_construct_properties,
                                GObjectConstructParam* construct_properties)
{
  GObject* object;
  InfAdoptedSession* session;
  InfAdoptedSessionPrivate* priv;
  InfSessionStatus status;
  InfUserTable* user_table;

  object = G_OBJECT_CLASS(parent_class)->constructor(
    type,
    n_construct_properties,
    construct_properties
  );

  session = INF_ADOPTED_SESSION(object);
  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  g_assert(priv->io != NULL);
  g_object_get(G_OBJECT(session), "status", &status, NULL);

  user_table = inf_session_get_user_table(INF_SESSION(session));

  g_signal_connect(
    G_OBJECT(user_table),
    "add-local-user",
    G_CALLBACK(inf_adopted_session_add_local_user_cb),
    session
  );

  g_signal_connect(
    G_OBJECT(user_table),
    "remove-local-user",
    G_CALLBACK(inf_adopted_session_remove_local_user_cb),
    session
  );

  switch(status)
  {
  case INF_SESSION_PRESYNC:
  case INF_SESSION_SYNCHRONIZING:
    /* algorithm is created during initial synchronization when parameters
     * like initial vector time, max total log size etc. are known. */
    break;
  case INF_SESSION_RUNNING:
    g_assert(inf_session_get_buffer(INF_SESSION(session)) != NULL);
    inf_adopted_session_create_algorithm(session);

    break;
  case INF_SESSION_CLOSED:
    /* Session should not be initially closed */
  default:
    g_assert_not_reached();
    break;
  }

  /* Add initial local users. Note that this requires the algorithm to exist, 
   * though in synchronizing state no local users can exist. */
  inf_user_table_foreach_local_user(
    user_table,
    inf_adopted_session_constructor_foreach_local_user_func,
    session
  );

  return object;
}
Ejemplo n.º 25
0
static gboolean
perform_test(guint max_total_log_size,
             InfTextChunk* initial,
             GSList* users,
             GSList* requests,
             GError** error)
{
  InfTextBuffer* buffer;
  InfCommunicationManager* manager;
  InfIo* io;
  InfTextSession* session;
  InfAdoptedAlgorithm* algorithm;

  InfUserTable* user_table;
  InfTextUser* user;
  gchar* user_name;

  GSList* item;
  xmlNodePtr request;
  gboolean result;
  GError* local_error;
  
  guint verify_user_id;
  InfAdoptedUser* verify_user;
  guint verify_log_size;
  gint verify_can_undo;
  gint verify_can_redo;

  InfAdoptedRequestLog* log;
  guint log_size;

  buffer = INF_TEXT_BUFFER(inf_text_default_buffer_new("UTF-8"));
  inf_text_buffer_insert_chunk(buffer, 0, initial, NULL);

  manager = inf_communication_manager_new();
  io = INF_IO(inf_standalone_io_new());
  user_table = inf_user_table_new();
  local_error = NULL;

  for(item = users; item != NULL; item = g_slist_next(item))
  {
    user_name = g_strdup_printf("User_%u", GPOINTER_TO_UINT(item->data));

    user = INF_TEXT_USER(
      g_object_new(
        INF_TEXT_TYPE_USER,
        "id", GPOINTER_TO_UINT(item->data),
        "name", user_name,
        "status", INF_USER_ACTIVE,
        "flags", 0,
        NULL
      )
    );

    g_free(user_name);
    inf_user_table_add_user(user_table, INF_USER(user));
    g_object_unref(user);
  }

  session = INF_TEXT_SESSION(
    g_object_new(
      INF_TEXT_TYPE_SESSION,
      "communication-manager", manager,
      "buffer", buffer,
      "io", io,
      "user_table", user_table,
      "max-total-log-size", max_total_log_size,
      NULL
    )
  );
  
  algorithm = inf_adopted_session_get_algorithm(INF_ADOPTED_SESSION(session));

  g_object_unref(io);
  g_object_unref(manager);
  g_object_unref(user_table);
  g_object_unref(buffer);

  for(item = requests; item != NULL; item = item->next)
  {
    request = (xmlNodePtr)item->data;
    
    if(strcmp((const char*)request->name, "request") == 0)
    {
      /* Request */
      result = inf_communication_object_received(
        INF_COMMUNICATION_OBJECT(session),
        NULL,
        request,
        &local_error
      );
      
      if(local_error != NULL)
        goto fail;
    }
    else
    {
      /* TODO: Make an extra function out of this: */
      /* Verify */
      result = inf_xml_util_get_attribute_uint_required(
        request,
        "user",
        &verify_user_id,
        &local_error
      );
      
      if(result == FALSE)
        goto fail;

      verify_user = INF_ADOPTED_USER(
        inf_user_table_lookup_user_by_id(user_table, verify_user_id)
      );

      if(verify_user == NULL)
      {
        g_set_error(
          error,
          inf_test_text_cleanup_error_quark(),
          INF_TEST_TEXT_CLEANUP_USER_UNAVAILABLE,
          "User ID '%u' not available",
          verify_user_id
        );
        
        goto fail;
      }

      result = inf_xml_util_get_attribute_uint(
        request,
        "log-size",
        &verify_log_size,
        &local_error
      );

      if(local_error) goto fail;

      if(result)
      {
        log = inf_adopted_user_get_request_log(INF_ADOPTED_USER(verify_user));
        log_size = inf_adopted_request_log_get_end(log) -
          inf_adopted_request_log_get_begin(log);
        if(verify_log_size != log_size)
        {
          g_set_error(
            error,
            inf_test_text_cleanup_error_quark(),
            INF_TEST_TEXT_CLEANUP_VERIFY_FAILED,
            "Log size does not match; got %u, but expected %u",
            log_size,
            verify_log_size
          );

          goto fail;
        }
      }
      
      result = inf_xml_util_get_attribute_int(
        request,
        "can-undo",
        &verify_can_undo,
        &local_error
      );

      if(local_error) goto fail;

      if(result)
      {
        result = inf_adopted_algorithm_can_undo(algorithm, verify_user);
        if(result != verify_can_undo)
        {
          g_set_error(
            error,
            inf_test_text_cleanup_error_quark(),
            INF_TEST_TEXT_CLEANUP_VERIFY_FAILED,
            "can-undo does not match; got %d, but expected %d",
            (guint)result,
            verify_can_undo
          );

          goto fail;
        }
      }

      result = inf_xml_util_get_attribute_int(
        request,
        "can-redo",
        &verify_can_redo,
        &local_error
      );

      if(local_error) goto fail;

      if(result)
      {
        result = inf_adopted_algorithm_can_redo(algorithm, verify_user);
        if(result != verify_can_redo)
        {
          g_set_error(
            error,
            inf_test_text_cleanup_error_quark(),
            INF_TEST_TEXT_CLEANUP_VERIFY_FAILED,
            "can-redo does not match; got %d, but expected %d",
            (guint)result,
            verify_can_redo
          );

          goto fail;
        }
      }
    }
  }

  g_object_unref(session);
  return TRUE;

fail:
  g_object_unref(session);
  if(local_error) g_propagate_error(error, local_error);
  return FALSE;
}
Ejemplo n.º 26
0
static InfCommunicationScope
inf_adopted_session_process_xml_run(InfSession* session,
                                    InfXmlConnection* connection,
                                    const xmlNodePtr xml,
                                    GError** error)
{
  InfAdoptedSessionPrivate* priv;
  InfAdoptedSessionClass* session_class;
  InfAdoptedRequest* request;
  InfAdoptedUser* user;

  gboolean has_num;
  guint num;
  GError* local_error;
  InfAdoptedRequest* copy_req;
  guint i;

  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  if(strcmp((const char*)xml->name, "request") == 0)
  {
    session_class = INF_ADOPTED_SESSION_GET_CLASS(session);
    g_assert(session_class->xml_to_request != NULL);

    user = inf_adopted_session_user_from_request_xml(
      INF_ADOPTED_SESSION(session),
      xml,
      error
    );

    if(user == NULL)
      return INF_COMMUNICATION_SCOPE_PTP;

    if(inf_user_get_status(INF_USER(user)) == INF_USER_UNAVAILABLE ||
       inf_user_get_connection(INF_USER(user)) != connection)
    {
      g_set_error(
        error,
        inf_user_error_quark(),
        INF_USER_ERROR_NOT_JOINED,
        "%s",
        _("User did not join from this connection")
      );

      return INF_COMMUNICATION_SCOPE_PTP;
    }

    local_error = NULL;
    has_num = inf_xml_util_get_attribute_uint(xml, "num", &num, &local_error);
    if(local_error != NULL)
    {
      g_propagate_error(error, local_error);
      return INF_COMMUNICATION_SCOPE_PTP;
    }
    
    request = session_class->xml_to_request(
      INF_ADOPTED_SESSION(session),
      xml,
      inf_adopted_user_get_vector(user),
      FALSE,
      error
    );

    if(request == NULL)
      return INF_COMMUNICATION_SCOPE_PTP;

    inf_adopted_algorithm_receive_request(priv->algorithm, request);

    /* Apply the request more than once if num is given. This is mostly used
     * for multiple undos and redos, but is in general allowed for any
     * request. */
    if(has_num)
    {
      for(i = 1; i < num; ++i)
      {
        /* TODO: This is a bit of a hack since requests are normally
         * immutable. It avoids an additional vector copy here though. */
        copy_req = inf_adopted_request_copy(request);

        inf_adopted_state_vector_add(
          inf_adopted_request_get_vector(copy_req),
          inf_user_get_id(INF_USER(user)),
          i
        );

        inf_adopted_algorithm_receive_request(priv->algorithm, copy_req);
        g_object_unref(copy_req);
      }
    }

    g_object_unref(request);

    /* Requests can always be forwarded since user is given. */
    return INF_COMMUNICATION_SCOPE_GROUP;
  }

  return INF_SESSION_CLASS(parent_class)->process_xml_run(
    session,
    connection,
    xml,
    error
  );
}
Ejemplo n.º 27
0
void Gobby::EditCommands::on_document_changed(SessionView* view)
{
	if(m_current_view != NULL)
	{
		InfTextSession* session = m_current_view->get_session();
		InfAdoptedAlgorithm* algorithm =
			inf_adopted_session_get_algorithm(
				INF_ADOPTED_SESSION(session));
		GtkTextBuffer* buffer = GTK_TEXT_BUFFER(
			m_current_view->get_text_buffer());

		if(m_synchronization_complete_handler != 0)
		{
			g_signal_handler_disconnect(
				G_OBJECT(session),
				m_synchronization_complete_handler);
		}
		else
		{
			g_signal_handler_disconnect(
				G_OBJECT(algorithm),
				m_can_undo_changed_handler);
			g_signal_handler_disconnect(
				G_OBJECT(algorithm),
				m_can_redo_changed_handler);
		}

		g_signal_handler_disconnect(G_OBJECT(buffer),
		                            m_mark_set_handler);
		g_signal_handler_disconnect(G_OBJECT(buffer),
		                            m_changed_handler);

		m_active_user_changed_connection.disconnect();
	}

	m_current_view = dynamic_cast<TextSessionView*>(view);

	if(m_current_view != NULL)
	{
		InfTextSession* session = m_current_view->get_session();
		InfUser* active_user = m_current_view->get_active_user();
		GtkTextBuffer* buffer =
			GTK_TEXT_BUFFER(m_current_view->get_text_buffer());

		m_active_user_changed_connection =
			m_current_view->signal_active_user_changed().connect(
				sigc::mem_fun(
					*this,
					&EditCommands::
						on_active_user_changed));

		m_mark_set_handler = g_signal_connect_after(
			G_OBJECT(buffer), "mark-set",
			G_CALLBACK(&on_mark_set_static), this);
		// The selection might change without mark-set being emitted
		// when the document changes, for example when all
		// currently selected text is deleted.
		m_changed_handler = g_signal_connect_after(
			G_OBJECT(buffer), "changed",
			G_CALLBACK(&on_changed_static), this);

		if(inf_session_get_status(INF_SESSION(session)) ==
		   INF_SESSION_RUNNING)
		{
			// This connects to can-undo-changed and
			// can-redo-changed of the algorithm. Set
			// m_synchronization_complete_handler to zero so that
			// the function does not try to disconnect from it.
			m_synchronization_complete_handler = 0;
			on_sync_complete();
		}
		else
		{
			// The InfAdoptedSession is created after
			// synchronization, so we wait until that finished.
			m_synchronization_complete_handler =
				g_signal_connect_after(
					G_OBJECT(session),
					"synchronization_complete",
					G_CALLBACK(&on_sync_complete_static),
					this);

			m_can_undo_changed_handler = 0;
			m_can_redo_changed_handler = 0;
		}

		// Set initial sensitivity for active user:
		on_active_user_changed(active_user);
		// Set initial sensitivity for cut/copy/paste:
		on_mark_set();

		// Set initial sensitivity for find/replace/goto:
		m_header.action_edit_find->set_sensitive(true);

		if(m_find_dialog.get())
		{
			on_find_text_changed();
		}
		else
		{
			m_header.action_edit_find_next->set_sensitive(false);
			m_header.action_edit_find_prev->set_sensitive(false);
		}

		m_header.action_edit_find_replace->set_sensitive(true);
		m_header.action_edit_goto_line->set_sensitive(true);
	}
	else
	{
		m_header.action_edit_undo->set_sensitive(false);
		m_header.action_edit_redo->set_sensitive(false);
		m_header.action_edit_cut->set_sensitive(false);
		m_header.action_edit_copy->set_sensitive(false);
		m_header.action_edit_paste->set_sensitive(false);
		m_header.action_edit_find->set_sensitive(false);
		m_header.action_edit_find_next->set_sensitive(false);
		m_header.action_edit_find_prev->set_sensitive(false);
		m_header.action_edit_find_replace->set_sensitive(false);
		m_header.action_edit_goto_line->set_sensitive(false);
	}
}