示例#1
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);
	}
}
示例#2
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);
}
static InfAdoptedUser*
inf_adopted_session_user_from_request_xml(InfAdoptedSession* session,
                                          xmlNodePtr xml,
                                          GError** error)
{
  InfUserTable* user_table;
  InfUser* user;
  guint user_id;

  user_table = inf_session_get_user_table(INF_SESSION(session));

  if(!inf_xml_util_get_attribute_uint_required(xml, "user", &user_id, error))
    return FALSE;

  /* User ID 0 means no user */
  if(user_id == 0) return NULL;

  user = inf_user_table_lookup_user_by_id(user_table, user_id);

  if(user == NULL)
  {
    g_set_error(
      error,
      inf_adopted_session_error_quark,
      INF_ADOPTED_SESSION_ERROR_NO_SUCH_USER,
      _("No such user with user ID '%u'"),
      user_id
    );

    return NULL;
  }

  g_assert(INF_ADOPTED_IS_USER(user));
  return INF_ADOPTED_USER(user);
}
示例#4
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);
}
示例#5
0
void Gobby::EditCommands::on_can_redo_changed(InfAdoptedUser* user,
                                              bool can_redo)
{
	g_assert(m_current_view != NULL);
	if(INF_ADOPTED_USER(m_current_view->get_active_user()) == user)
		m_header.action_edit_redo->set_sensitive(can_redo);
}
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)
  );
}
示例#7
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));
}
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
  );
}
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)
  );
}
/* Breadcasts a request N times - makes only sense for undo and redo requests,
 * so that's the only thing we offer API for. */
static void
inf_adopted_session_broadcast_n_requests(InfAdoptedSession* session,
                                         InfAdoptedRequest* request,
                                         guint n)
{
  InfAdoptedSessionPrivate* priv;
  InfAdoptedSessionClass* session_class;
  InfUserTable* user_table;
  guint user_id;
  InfUser* user;
  InfAdoptedSessionLocalUser* local;
  xmlNodePtr xml;

  priv = INF_ADOPTED_SESSION_PRIVATE(session);
  session_class = INF_ADOPTED_SESSION_GET_CLASS(session);
  g_assert(session_class->request_to_xml != NULL);

  user_table = inf_session_get_user_table(INF_SESSION(session));
  user_id = inf_adopted_request_get_user_id(request);
  user = inf_user_table_lookup_user_by_id(user_table, user_id);
  g_assert(user != NULL);

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

  xml = xmlNewNode(NULL, (const xmlChar*)"request");

  session_class->request_to_xml(
    session,
    xml,
    request,
    local->last_send_vector,
    FALSE
  );

  if(n > 1) inf_xml_util_set_attribute_uint(xml, "num", n);
  inf_session_send_to_subscriptions(INF_SESSION(session), xml);

  inf_adopted_state_vector_free(local->last_send_vector);
  local->last_send_vector = inf_adopted_state_vector_copy(
    inf_adopted_request_get_vector(request)
  );

  /* Add this request to last send vector if it increases vector time
   * (-> affects buffer). */
  if(inf_adopted_request_affects_buffer(request) == TRUE)
    inf_adopted_state_vector_add(local->last_send_vector, user_id, n);

  inf_adopted_session_stop_noop_timer(session, local);
}
static void
inf_adopted_session_synchronization_complete_foreach_user_func(InfUser* user,
                                                               gpointer data)
{
  InfAdoptedRequestLog* log;
  log = inf_adopted_user_get_request_log(INF_ADOPTED_USER(user));

  /* Set begin index of empty request logs. Algorithm relies on
   * inf_adopted_request_log_get_begin() to return the index of the request
   * that will first be added to the request log. */
  if(inf_adopted_request_log_is_empty(log))
  {
    inf_adopted_request_log_set_begin(
      log,
      inf_adopted_state_vector_get(
        inf_adopted_user_get_vector(INF_ADOPTED_USER(user)),
        inf_user_get_id(user)
      )
    );
  }
}
示例#12
0
Gobby::TextUndoGrouping::TextUndoGrouping(InfAdoptedAlgorithm* algorithm,
                                          InfTextUser* user,
                                          GtkTextBuffer* buffer):
	m_buffer(buffer), m_grouping(inf_text_undo_grouping_new())
{
	g_object_ref(m_buffer);

	inf_adopted_undo_grouping_set_algorithm(
		INF_ADOPTED_UNDO_GROUPING(m_grouping),
		algorithm,
		INF_ADOPTED_USER(user));

	m_begin_user_action_handle = g_signal_connect(
		G_OBJECT(m_buffer), "begin-user-action",
		G_CALLBACK(on_begin_user_action_static), this);
	m_end_user_action_handle = g_signal_connect(
		G_OBJECT(m_buffer), "end-user-action",
		G_CALLBACK(on_end_user_action_static), this);
}
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);
}
static void
inf_adopted_session_to_xml_sync_foreach_user_func(InfUser* user,
                                                  gpointer user_data)
{
  InfAdoptedRequestLog* log;
  InfAdoptedSessionToXmlSyncForeachData* data;
  InfAdoptedSessionClass* session_class;
  guint i;
  guint end;
  xmlNodePtr xml;
  InfAdoptedRequest* request;

  g_assert(INF_ADOPTED_IS_USER(user));

  data = (InfAdoptedSessionToXmlSyncForeachData*)user_data;
  log = inf_adopted_user_get_request_log(INF_ADOPTED_USER(user));
  end = inf_adopted_request_log_get_end(log);
  session_class = INF_ADOPTED_SESSION_GET_CLASS(data->session);
  g_assert(session_class->request_to_xml != NULL);

  for(i = inf_adopted_request_log_get_begin(log); i < end; ++ i)
  {
    request = inf_adopted_request_log_get_request(log, i);

    xml = xmlNewChild(
      data->parent_xml,
      NULL,
      (const xmlChar*)"sync-request",
      NULL
    );

    /* TODO: Diff to previous request? */
    session_class->request_to_xml(data->session, xml, request, NULL, TRUE);
    xmlAddChild(data->parent_xml, xml);
  }
}
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;
}