Exemplo n.º 1
0
/**
 * 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;
}
/**
 * inf_adopted_operation_revert:
 * @operation: A #InfAdoptedOperation.
 *
 * Returns a new #InfAdoptedOperation that undoes the effect of @operation. If
 * @operation and then its reverse operation are applied to a buffer (in that
 * order), the buffer remains unchanged.
 *
 * @operation must be reversible for this function to be called (i.e.
 * inf_adopted_operation_is_reversible() must return TRUE).
 *
 * Return Value: The reverse operation of @operation.
 **/
InfAdoptedOperation*
inf_adopted_operation_revert(InfAdoptedOperation* operation)
{
  InfAdoptedOperationIface* iface;

  g_return_val_if_fail(INF_ADOPTED_IS_OPERATION(operation), NULL);
  g_assert(inf_adopted_operation_is_reversible(operation) == TRUE);

  iface = INF_ADOPTED_OPERATION_GET_IFACE(operation);

  /* When inf_adopted_operation_is_reversible() returns TRUE for an operation
   * it must implement revert. */
  g_assert(iface->revert != NULL);
  return (*iface->revert)(operation);
}
/**
 * inf_adopted_operation_make_reversible:
 * @operation: A #InfAdoptedOperation.
 * @with: Another #InfAdoptedOperation that emerged from @operation by
 * transforming it.
 * @buffer: A #InfBuffer.
 *
 * Some operations may not be reversible, but can be made reversible with
 * some extra information such as another operation that collected
 * enough information while being transformed, and the current buffer.
 *
 * This function can only be called when @operation is not yet reversible
 * and returns a new operation that has the same effect as @operation, but is
 * reversible.
 *
 * For example, an operation that deletes some range of text in a text editor
 * is not reversible if it only stores the position and length of the range,
 * but can be made reversible when it looks up what there is at that position
 * in the buffer.
 *
 * Return Value: A reversible #InfAdoptedOperation, or %NULL if @operation
 * cannot be made reversible with the given transformed operation @with and
 * @buffer.
 **/
InfAdoptedOperation*
inf_adopted_operation_make_reversible(InfAdoptedOperation* operation,
                                      InfAdoptedOperation* with,
                                      InfBuffer* buffer)
{
  InfAdoptedOperationIface* iface;

  g_return_val_if_fail(INF_ADOPTED_IS_OPERATION(operation), NULL);
  g_return_val_if_fail(INF_ADOPTED_IS_OPERATION(with), NULL);
  g_return_val_if_fail(INF_IS_BUFFER(buffer), NULL);

  g_assert(inf_adopted_operation_is_reversible(operation) == FALSE);

  iface = INF_ADOPTED_OPERATION_GET_IFACE(operation);

  if(iface->make_reversible != NULL)
    return (*iface->make_reversible)(operation, with, buffer);
  else
    return NULL;
}