コード例 #1
0
ファイル: inf-adopted-request.c プロジェクト: pkern/infinote
/**
 * inf_adopted_request_need_concurrency_id:
 * @request: The request to transform.
 * @against: The request to transform against.
 *
 * Returns whether transforming @request against @against requires a
 * concurrency ID. You can still call inf_adopted_request_transform() with
 * a concurrency ID of %INF_ADOPTED_CONCURRENCY_NONE even if this function
 * returns %TRUE if you don't have another possibility to find a
 * concurrency ID in which case user IDs are used to determine which request
 * to transform.
 *
 * Both request need to be of type %INF_ADOPTED_REQUEST_DO, and their state
 * vectors must be the same.
 *
 * Returns: Whether transformation of @request against @against requires a
 * concurrency ID.
 */
gboolean
inf_adopted_request_need_concurrency_id(InfAdoptedRequest* request,
                                        InfAdoptedRequest* against)
{
    InfAdoptedRequestPrivate* request_priv;
    InfAdoptedRequestPrivate* against_priv;

    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(request), FALSE);
    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(against), FALSE);

    request_priv = INF_ADOPTED_REQUEST_PRIVATE(request);
    against_priv = INF_ADOPTED_REQUEST_PRIVATE(against);

    g_return_val_if_fail(request_priv->type == INF_ADOPTED_REQUEST_DO, FALSE);
    g_return_val_if_fail(against_priv->type == INF_ADOPTED_REQUEST_DO, FALSE);
    g_return_val_if_fail(request_priv->user_id != against_priv->user_id, FALSE);

    g_return_val_if_fail(
        inf_adopted_state_vector_compare(
            request_priv->vector,
            against_priv->vector
        ) == 0,
        FALSE
    );

    return inf_adopted_operation_need_concurrency_id(
               request_priv->operation,
               against_priv->operation
           );
}
コード例 #2
0
ファイル: inf-adopted-request.c プロジェクト: pkern/infinote
/**
 * inf_adopted_request_affects_buffer:
 * @request: A #InfAdoptedRequest.
 *
 * Returns whether this request, when applied, changes the content of the
 * buffer. If this is a %INF_ADOPTED_REQUEST_UNDO or %INF_ADOPTED_REQUEST_REDO
 * request, than it always affects the buffer, because only requests that
 * affect the buffer can be undone or redone. If it is a
 * %INF_ADOPTED_REQUEST_DO request, than it returns whether its operation
 * has the %INF_ADOPTED_OPERATION_AFFECTS_BUFFER flag set.
 *
 * Returns: Whether @request affects the session's buffer.
 **/
gboolean
inf_adopted_request_affects_buffer(InfAdoptedRequest* request)
{
    InfAdoptedRequestPrivate* priv;

    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(request), FALSE);
    priv = INF_ADOPTED_REQUEST_PRIVATE(request);

    switch(priv->type)
    {
    case INF_ADOPTED_REQUEST_DO:
        if(inf_adopted_operation_get_flags(priv->operation) &
                INF_ADOPTED_OPERATION_AFFECTS_BUFFER)
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    case INF_ADOPTED_REQUEST_UNDO:
    case INF_ADOPTED_REQUEST_REDO:
        return TRUE;
    default:
        g_assert_not_reached();
        return FALSE;
    }
}
コード例 #3
0
ファイル: inf-adopted-request.c プロジェクト: pkern/infinote
/**
 * inf_adopted_request_mirror:
 * @request: A #InfAdoptedRequest.
 * @by: The number of requests between the original and the mirrored
 * operation.
 *
 * Mirrors @request as described in "Reducing the Problems of Group Undo" by
 * Matthias Ressel and Rul Gunzenhäuser
 * (http://portal.acm.org/citation.cfm?doid=320297.320312).
 *
 * Note that @by is the total amount of requests between the original and
 * mirrored request, and thus equivalent to 2j-1 in the paper's definition.
 *
 * @request must be of type %INF_ADOPTED_REQUEST_DO and its operation must
 * be reversible.
 *
 * Returns: The mirrored request as a new #InfAdoptedRequest.
 **/
InfAdoptedRequest*
inf_adopted_request_mirror(InfAdoptedRequest* request,
                           guint by)
{
    InfAdoptedRequestPrivate* priv;
    InfAdoptedOperation* new_operation;
    InfAdoptedStateVector* new_vector;
    InfAdoptedRequest* new_request;

    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(request), NULL);
    g_return_val_if_fail(by % 2 == 1, NULL);

    priv = INF_ADOPTED_REQUEST_PRIVATE(request);
    g_return_val_if_fail(priv->type == INF_ADOPTED_REQUEST_DO, NULL);
    g_return_val_if_fail(
        inf_adopted_operation_is_reversible(priv->operation),
        NULL
    );

    new_operation = inf_adopted_operation_revert(priv->operation);
    new_vector = inf_adopted_state_vector_copy(priv->vector);
    inf_adopted_state_vector_add(new_vector, priv->user_id, by);

    new_request = inf_adopted_request_new_do(
                      new_vector,
                      priv->user_id,
                      new_operation
                  );

    g_object_unref(new_operation);
    inf_adopted_state_vector_free(new_vector);
    return new_request;
}
コード例 #4
0
ファイル: inf-adopted-request.c プロジェクト: pkern/infinote
/**
 * inf_adopted_request_copy:
 * @request: The #InfAdoptedRequest to copy.
 *
 * Creates a copy of @request with an initial reference count of 1.
 *
 * Return Value: A new #InfAdoptedRequest.
 **/
InfAdoptedRequest*
inf_adopted_request_copy(InfAdoptedRequest* request)
{
    InfAdoptedRequestPrivate* priv;
    GObject* object;

    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(request), NULL);
    priv = INF_ADOPTED_REQUEST_PRIVATE(request);

    if(priv->type == INF_ADOPTED_REQUEST_DO)
    {
        object = g_object_new(
                     INF_ADOPTED_TYPE_REQUEST,
                     "type", priv->type,
                     "vector", priv->vector,
                     "user-id", priv->user_id,
                     "operation", priv->operation,
                     NULL
                 );
    }
    else
    {
        object = g_object_new(
                     INF_ADOPTED_TYPE_REQUEST,
                     "type", priv->type,
                     "vector", priv->vector,
                     "user-id", priv->user_id,
                     NULL
                 );
    }

    return INF_ADOPTED_REQUEST(object);
}
コード例 #5
0
ファイル: inf-adopted-request.c プロジェクト: pkern/infinote
/**
 * inf_adopted_request_get_concurrency_id:
 * @request: The request to transform.
 * @against: The request to transform against.
 *
 * Returns a concurrency ID for transformation of @operation against @against.
 * It always returns %INF_ADOPTED_CONCURRENCY_NONE when
 * inf_adopted_request_need_concurrency_id() returns %TRUE (but that's not
 * necessarily true the other way around), since it is not possible to decide
 * which operation to transform without any additional information.
 *
 * However, the function can be called on the same requests in a previous
 * state. In some cases, a decision can be made based on these previous
 * requests. This can be used as a concurrency ID for a call to
 * inf_adopted_request_transform(). If this does not yield a decision, it is
 * still possible to call inf_adopted_request_transform() with
 * %INF_ADOPTED_CONCURRENCY_NONE as concurrency ID in which case an arbitrary
 * request will be transformed, based on the user IDs of the requests.
 *
 * Both requests must be of type %INF_ADOPTED_REQUEST_DO, and their state
 * vectors must be the same.
 *
 * Returns: A concurrency ID between @operation and @against. Can be
 * %INF_ADOPTED_CONCURRENCY_NONE in case no decision can be made.
 */
InfAdoptedConcurrencyId
inf_adopted_request_get_concurrency_id(InfAdoptedRequest* request,
                                       InfAdoptedRequest* against)
{
    InfAdoptedRequestPrivate* request_priv;
    InfAdoptedRequestPrivate* against_priv;

    g_return_val_if_fail(
        INF_ADOPTED_IS_REQUEST(request),
        INF_ADOPTED_CONCURRENCY_NONE
    );
    g_return_val_if_fail(
        INF_ADOPTED_IS_REQUEST(against),
        INF_ADOPTED_CONCURRENCY_NONE
    );

    request_priv = INF_ADOPTED_REQUEST_PRIVATE(request);
    against_priv = INF_ADOPTED_REQUEST_PRIVATE(against);

    g_return_val_if_fail(
        request_priv->type == INF_ADOPTED_REQUEST_DO,
        INF_ADOPTED_CONCURRENCY_NONE
    );
    g_return_val_if_fail(
        against_priv->type == INF_ADOPTED_REQUEST_DO,
        INF_ADOPTED_CONCURRENCY_NONE
    );
    g_return_val_if_fail(
        request_priv->user_id != against_priv->user_id,
        INF_ADOPTED_CONCURRENCY_NONE
    );

    g_return_val_if_fail(
        inf_adopted_state_vector_compare(
            request_priv->vector,
            against_priv->vector
        ) == 0,
        INF_ADOPTED_CONCURRENCY_NONE
    );

    return inf_adopted_operation_get_concurrency_id(
               request_priv->operation,
               against_priv->operation
           );
}
コード例 #6
0
/**
 * inf_adopted_session_broadcast_request:
 * @session: A #InfAdoptedSession.
 * @request: A #InfAdoptedRequest obtained from @session's algorithm.
 *
 * Sends a request to all subscribed connections. The request should originate
 * from a call to inf_adopted_algorithm_generate_request_noexec(),
 * inf_adopted_algorithm_generate_request(),
 * inf_adopted_algorithm_generate_undo() or
 * inf_adopted_algorithm_generate_redo() with @session's #InfAdoptedAlgorithm.
 **/
void
inf_adopted_session_broadcast_request(InfAdoptedSession* session,
                                      InfAdoptedRequest* request)
{
  g_return_if_fail(INF_ADOPTED_IS_SESSION(session));
  g_return_if_fail(INF_ADOPTED_IS_REQUEST(request));

  inf_adopted_session_broadcast_n_requests(session, request, 1);
}
コード例 #7
0
ファイル: inf-adopted-request.c プロジェクト: pkern/infinote
/**
 * inf_adopted_request_get_request_type:
 * @request: A #InfAdoptedRequest.
 *
 * Returns the request type of @request.
 *
 * Return Value: The type of @request.
 **/
InfAdoptedRequestType
inf_adopted_request_get_request_type(InfAdoptedRequest* request)
{
    g_return_val_if_fail(
        INF_ADOPTED_IS_REQUEST(request),
        INF_ADOPTED_REQUEST_DO
    );

    return INF_ADOPTED_REQUEST_PRIVATE(request)->type;
}
コード例 #8
0
ファイル: inf-adopted-request.c プロジェクト: pkern/infinote
/**
 * inf_adopted_request_get_operation:
 * @request: A #InfAdoptedRequest.
 *
 * Returns the operation carried by the request. This can only be called if
 * the request's type is %INF_ADOPTED_REQUEST_DO.
 *
 * Return Value: The request's operation.
 **/
InfAdoptedOperation*
inf_adopted_request_get_operation(InfAdoptedRequest* request)
{
    InfAdoptedRequestPrivate* priv;

    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(request), NULL);

    priv = INF_ADOPTED_REQUEST_PRIVATE(request);
    g_return_val_if_fail(priv->operation != NULL, NULL);

    return priv->operation;
}
コード例 #9
0
ファイル: inf-adopted-request.c プロジェクト: pkern/infinote
/**
 * inf_adopted_request_fold:
 * @request: A #InfAdoptedRequest.
 * @into: The direction into which to fold.
 * @by: The number of operations between the original and the fold request.
 *
 * Folds @request as described in "Reducing the Problems of Group Undo" by
 * Matthias Ressel and Rul Gunzenhäuser
 * (http://portal.acm.org/citation.cfm?doid=320297.320312).
 *
 * Note that @by is the total amount of requests between the original and
 * the fold request, and thus equivalent to 2j in the paper's definition.
 *
 * @into must not be the same user as the one that issued @request.
 *
 * Returns: The folded request as a new #InfAdoptedRequest.
 **/
InfAdoptedRequest*
inf_adopted_request_fold(InfAdoptedRequest* request,
                         guint into,
                         guint by)
{
    InfAdoptedRequestPrivate* priv;
    InfAdoptedStateVector* new_vector;
    InfAdoptedRequest* new_request;

    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(request), NULL);
    g_return_val_if_fail(into != 0, NULL);
    g_return_val_if_fail(by % 2 == 0, NULL);

    priv = INF_ADOPTED_REQUEST_PRIVATE(request);
    g_return_val_if_fail(priv->user_id != into, NULL);

    new_vector = inf_adopted_state_vector_copy(priv->vector);
    inf_adopted_state_vector_add(new_vector, into, by);

    if(priv->type == INF_ADOPTED_REQUEST_DO)
    {
        new_request = INF_ADOPTED_REQUEST(
                          g_object_new(
                              INF_ADOPTED_TYPE_REQUEST,
                              "type", priv->type,
                              "operation", priv->operation,
                              "vector", new_vector,
                              "user-id", priv->user_id,
                              NULL
                          )
                      );
    }
    else
    {
        new_request = INF_ADOPTED_REQUEST(
                          g_object_new(
                              INF_ADOPTED_TYPE_REQUEST,
                              "type", priv->type,
                              "vector", new_vector,
                              "user-id", priv->user_id
                          )
                      );
    }

    inf_adopted_state_vector_free(new_vector);
    return new_request;
}
コード例 #10
0
ファイル: inf-adopted-request.c プロジェクト: pkern/infinote
/**
 * inf_adopted_request_transform:
 * @request: The request to transform.
 * @against: The request to transform against.
 * @concurrency_id: A concurrency ID for the transformation.
 *
 * Transforms the operation of @request against the operation of @against.
 * Both requests must be of type %INF_ADOPTED_REQUEST_DO, and their state
 * vectors must be the same.
 *
 * @concurrency_id can be %INF_ADOPTED_CONCURRENCY_NONE even if the
 * transformation requires a concurrency ID (see
 * inf_adopted_request_need_concurrency_id()). In that case, it is assumed
 * that it does not matter which operation to transform, and user IDs are
 * used to determine a concurrency ID for the transformation.
 *
 * Returns: A new #InfAdoptedRequest, the result of the transformation.
 **/
InfAdoptedRequest*
inf_adopted_request_transform(InfAdoptedRequest* request,
                              InfAdoptedRequest* against,
                              InfAdoptedConcurrencyId concurrency_id)
{
    InfAdoptedRequestPrivate* request_priv;
    InfAdoptedRequestPrivate* against_priv;
    InfAdoptedOperation* new_operation;
    InfAdoptedStateVector* new_vector;
    InfAdoptedRequest* new_request;

    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(request), NULL);
    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(against), NULL);

    request_priv = INF_ADOPTED_REQUEST_PRIVATE(request);
    against_priv = INF_ADOPTED_REQUEST_PRIVATE(against);

    g_return_val_if_fail(request_priv->type == INF_ADOPTED_REQUEST_DO, NULL);
    g_return_val_if_fail(against_priv->type == INF_ADOPTED_REQUEST_DO, NULL);
    g_return_val_if_fail(request_priv->user_id != against_priv->user_id, NULL);

    g_return_val_if_fail(
        inf_adopted_state_vector_compare(
            request_priv->vector,
            against_priv->vector
        ) == 0, NULL
    );

    if(concurrency_id != INF_ADOPTED_CONCURRENCY_NONE)
    {
        new_operation = inf_adopted_operation_transform(
                            request_priv->operation,
                            against_priv->operation,
                            concurrency_id
                        );
    }
    else if(request_priv->user_id > against_priv->user_id)
    {
        new_operation = inf_adopted_operation_transform(
                            request_priv->operation,
                            against_priv->operation,
                            INF_ADOPTED_CONCURRENCY_OTHER
                        );
    }
    else
    {
        new_operation = inf_adopted_operation_transform(
                            request_priv->operation,
                            against_priv->operation,
                            INF_ADOPTED_CONCURRENCY_SELF
                        );
    }

    new_vector = inf_adopted_state_vector_copy(request_priv->vector);
    inf_adopted_state_vector_add(new_vector, against_priv->user_id, 1);

    new_request = inf_adopted_request_new_do(
                      new_vector,
                      request_priv->user_id,
                      new_operation
                  );

    g_object_unref(new_operation);
    inf_adopted_state_vector_free(new_vector);
    return new_request;
}
コード例 #11
0
ファイル: inf-adopted-request.c プロジェクト: pkern/infinote
/**
 * inf_adopted_request_get_user_id:
 * @request: A #InfAdoptedRequest.
 *
 * Returns the user ID of the user that issued @request.
 *
 * Return Value: The request's user ID.
 **/
guint
inf_adopted_request_get_user_id(InfAdoptedRequest* request)
{
    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(request), 0);
    return INF_ADOPTED_REQUEST_PRIVATE(request)->user_id;
}
コード例 #12
0
ファイル: inf-adopted-request.c プロジェクト: pkern/infinote
/**
 * inf_adopted_request_get_vector:
 * @request: A #InfAdoptedRequest.
 *
 * Returns the vector time the request was made i.e. its operation can be
 * applied to the buffer.
 *
 * Return Value: The state vector of @request. The returned value should
 * not be freed, it is owned by the #InfAdoptedRequest.
 **/
InfAdoptedStateVector*
inf_adopted_request_get_vector(InfAdoptedRequest* request)
{
    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(request), NULL);
    return INF_ADOPTED_REQUEST_PRIVATE(request)->vector;
}