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); }
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); } }
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 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)); } }
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; } }
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()); }
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; } }
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); }
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); }
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 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) ); }
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; } }
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) ); }
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_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); }
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); } }
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; }
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 ); }
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); }
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(¶ms[0].value, G_TYPE_STRING); g_value_init(¶ms[1].value, INF_ADOPTED_TYPE_STATE_VECTOR); g_value_init(¶ms[2].value, G_TYPE_UINT); g_value_set_static_string(¶ms[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(¶ms[1].value, v); g_value_set_uint(¶ms[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(¶ms[2].value); g_value_unset(¶ms[1].value); g_value_unset(¶ms[0].value); }
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); }
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; } }
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(¶ms[0].value, G_TYPE_STRING); g_value_init(¶ms[1].value, INF_ADOPTED_TYPE_STATE_VECTOR); g_value_init(¶ms[2].value, G_TYPE_UINT); g_value_set_static_string(¶ms[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(¶ms[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(¶ms[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 ); } }
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; }
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; }
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 ); }
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); } }