Deshacer es una técnica de interacción que se implementa en muchos programas informáticos. Borra el último cambio realizado en el documento, volviéndolo a un estado anterior. En algunos programas más avanzados, como los de procesamiento gráfico , deshacer anulará el último comando realizado en el archivo que se está editando. Con la posibilidad de deshacer, los usuarios pueden explorar y trabajar sin temor a cometer errores, ya que se pueden deshacer fácilmente.
Las expectativas para deshacer son fáciles de entender: tener una funcionalidad predecible e incluir todos los comandos "deshacer". [1] Por lo general, la función de deshacer está disponible hasta que el usuario deshaga todas las operaciones ejecutadas. Pero hay algunas acciones que no se almacenan en la lista de deshacer y, por lo tanto, no se pueden deshacer. Por ejemplo, guardar un archivo no se puede deshacer, pero se pone en cola en la lista para mostrar que se ejecutó. Otra acción que normalmente no se almacena y, por lo tanto, no se puede deshacer, es el desplazamiento o la selección . [2]
El opuesto de deshacer es rehacer . El comando rehacer revierte la operación de deshacer o hace avanzar el búfer a un estado más reciente.
Los componentes comunes de la funcionalidad de deshacer son los comandos ejecutados por el usuario, los búferes de historial que almacenan las acciones completadas, el administrador de deshacer/rehacer para controlar el búfer de historial y la interfaz de usuario para interactuar con el usuario. [3]
En la mayoría de las aplicaciones gráficas para la mayoría de los sistemas operativos principales (como Microsoft Windows , Linux y BSD ), el atajo de teclado para el comando deshacer es Ctrl+Z o Alt+Retroceso, y el atajo para rehacer es Ctrl+Y o Ctrl + Shift +Z. En la mayoría de las aplicaciones de macOS, el atajo para el comando deshacer es Comando -Z, y el atajo para rehacer es Comando - Shift -Z. En todas las plataformas, también se puede acceder a las funciones deshacer/rehacer a través del menú Editar .
La capacidad de deshacer una operación en una computadora fue inventada independientemente varias veces, en respuesta a la forma en que las personas usaban las computadoras. [4]
Se informa que el Sistema de recuperación y edición de archivos , desarrollado a partir de 1968 en la Universidad Brown , es el primer sistema basado en computadora que tuvo una función de "deshacer". [5] [6]
Warren Teitelman desarrolló un Asistente de Programación como parte de BBN-LISP con una función Deshacer, en 1971. [7]
El editor de texto Xerox PARC Bravo tenía un comando Deshacer en 1974. [8] Un informe de investigación de 1976 de Lance A. Miller y John C. Thomas de IBM , Behavioral Issues in the Use of Interactive Systems , [9] señaló que "sería bastante útil permitir a los usuarios 'recuperar' al menos el comando inmediatamente anterior (emitiendo algún comando especial 'deshacer')". [10] Los programadores del centro de investigación Xerox PARC asignaron el atajo de teclado Ctrl-Z al comando deshacer, que se convirtió en una característica crucial de los editores de texto y procesadores de texto en la era de las computadoras personales . [11] En 1980, Larry Tesler de Xerox PARC comenzó a trabajar en Apple Computer . Allí, él y Bill Atkinson abogaron por la presencia de un comando deshacer como un elemento estándar en Apple Lisa . Atkinson pudo convencer a los desarrolladores individuales del software de aplicación de Lisa para que incluyeran un solo nivel de deshacer y rehacer, pero no tuvo éxito en su intento de incluir múltiples niveles. [ cita requerida ] Cuando Apple presentó el sucesor de Lisa, Macintosh , estipuló que todas las aplicaciones estándar debían incluir un "Deshacer" como primer comando en el menú "Editar", [12] que ha seguido siendo el estándar en macOS y Windows hasta el día de hoy.
Los comandos de deshacer de varios niveles se introdujeron en la década de 1980, lo que permitía a los usuarios deshacer una serie de acciones, no solo la más reciente. [11] EMACS y otros editores de pantalla de tiempo compartido lo tenían antes del software de computadora personal. CygnusEd fue el primer editor de texto de Amiga con una función de deshacer/rehacer ilimitada. AtariWriter , una aplicación de procesamiento de textos presentada en 1982, incluía la función de deshacer. NewWord, otro programa de procesamiento de textos lanzado por NewStar en 1984, tenía un comando de anulación de borrado. [11] VisiWord de IBM también tenía un comando de anulación de borrado.
Los modelos de deshacer se pueden clasificar como lineales o no lineales. El modelo de deshacer no lineal se puede subclasificar en modelo de script, modelo us&r, modelo triádico y deshacer selectivo. [1]
Algunas propiedades comunes de los modelos son:
La operación de deshacer lineal se implementa con una pila (estructura de datos LIFO [last in first out]) que almacena un historial de todos los comandos ejecutados. Cuando se ejecuta un nuevo comando, se agrega a la parte superior de la pila. Por lo tanto, solo se puede deshacer y eliminar del historial el último comando ejecutado. La operación de deshacer se puede repetir siempre que el historial no esté vacío. [1]
El modelo lineal restringido es una ampliación del modelo de deshacer lineal. Satisface la propiedad de ejecución estable descrita anteriormente para deshacer lineal, porque este modelo no conserva la propiedad si se ejecuta un comando mientras la lista de historial incluye otros comandos. El modelo lineal restringido borra la lista de historial antes de agregar un nuevo comando. Pero también hay otras restricciones disponibles. Por ejemplo, se puede restringir el tamaño de la lista de historial o, cuando se alcanza un tamaño definido, se elimina de la lista el primer comando ejecutado. [1]
La principal diferencia entre la función de deshacer lineal y la función de deshacer no lineal es la posibilidad de que el usuario deshaga los comandos ejecutados en un orden arbitrario. Tiene la posibilidad de deshacer no el comando más reciente, sino elegir un comando de la lista. [3] Para el modelo no lineal existen subclases que implementan este modelo.
El modelo de script maneja las acciones del usuario como si se tratara de la edición de un script de comandos. La lista histórica de los comandos ejecutados se interpreta "como un script, el efecto de una acción de deshacer se define como el mismo que si la acción deshecha nunca se hubiera producido en primer lugar". [1] Como resultado de una acción de deshacer, el estado tiene que ser el mismo que si el comando deshecho nunca se hubiera ejecutado. Una desventaja de este modelo es que el usuario tiene que conocer la conexión entre el comando deshecho y el estado actual para evitar efectos secundarios. Uno de ellos puede ser, por ejemplo, la duplicación. Otros problemas son que si "los comandos posteriores se rehacen en un estado diferente al que se ejecutaron originalmente en las interfaces de manipulación directa, esta reinterpretación de la acción original del usuario no siempre es obvia o está bien definida". [1]
La particularidad de este modelo es que tiene la opción de omitir un comando. Esto significa que se puede omitir la repetición de un comando. El comando que se omite se marca como omitido pero no se elimina. Cuando se ejecutan nuevos comandos, se conserva la lista del historial, por lo que el orden de los comandos ejecutados se puede reproducir con ello. El orden se puede describir mediante un árbol de historial que es un gráfico dirigido, "porque es posible continuar rehaciendo comandos desde otra rama creando un enlace en el gráfico". [1] Aunque el conjunto de comandos es simple y fácil de entender, la estructura compleja con ramas que se omiten y enlazan es difícil de comprender y recordar, cuando el usuario quiere deshacer más de un paso. [1]
Este modelo de deshacer no lineal tiene, además de deshacer y rehacer, la posibilidad de rotar. Tiene la misma estructura de datos que los modelos mencionados anteriormente, con una lista de historial y una lista de rehacer separada que incluye las operaciones de rehacer. La operación de rotación coloca el último comando de la lista de rehacer delante de ella. Por un lado, esto significa que el siguiente comando que se va a rehacer se puede seleccionar colocándolo delante. Por otro lado, la rotación se puede utilizar "para seleccionar el lugar en la lista de rehacer donde la siguiente operación de deshacer colocará el comando". [1] Por lo tanto, la lista de rehacer no está ordenada. "Para deshacer un comando aislado, el usuario tiene que deshacer una serie de pasos, rotar la lista de rehacer y luego rehacer una serie de pasos". [1] Para rehacer, la lista tiene que rotarse hasta que el comando deseado esté encima.
Jakubec et al. afirman que la función de deshacer selectiva es una característica que puede ofrecer un modelo, pero no existe una definición clara para esta función. [3] Los autores seleccionaron funciones que debería tener un modelo cuando admita la función de deshacer selectiva. Debería ser posible "deshacer cualquier acción ejecutada en el búfer de historial. Las acciones independientes de la acción que se está deshaciendo deberían dejarse intactas". [3] De la misma manera, la función de rehacer debe ser posible para cualquier comando deshecho. La tercera función de la función de deshacer selectiva es que "ningún comando puede descartarse automáticamente del búfer de historial sin una solicitud directa del usuario". [3] Para la función de deshacer selectiva se aplica que deshacer y rehacer es ejecutable fuera de cualquier contexto. Hay tres problemas principales. El primero es que los comandos deshechos pueden estar fuera del contexto original. A través de esto, puede haber referencias muertas que deben manejarse. El segundo problema es que los comandos modificados pueden deshacerse y, por lo tanto, debe resolverse qué estado se presentará después de deshacer. El tercer problema son los problemas de descarte de comandos. La función de deshacer selectiva no tiene puntero en las listas, por lo que esto significa que ningún comando debe descartarse de la pila. [3]
La operación de deshacer selectiva directa es una extensión de la operación de deshacer lineal restringida con un árbol de historial. La operación crea una copia del comando seleccionado, lo ejecuta y lo agrega a la lista de historial. Se definen dos operaciones no lineales, deshacer selectivamente y rehacer selectivamente, por lo que es más simétrica. [1]
Cuando varios usuarios pueden editar el mismo documento simultáneamente, se necesita una función de deshacer para varios usuarios. La función de deshacer para varios usuarios global revierte la última acción realizada en el documento, independientemente de quién haya realizado la edición. La función de deshacer para varios usuarios local solo revierte las acciones realizadas por el usuario local, lo que requiere una implementación de deshacer no lineal.
Mientras que la función de deshacer se puede utilizar para retroceder a través de varias ediciones, el comando de rehacer avanza a través del historial de acciones. Al realizar una nueva edición, normalmente se borra la lista de rehacer. Si se utiliza un modelo de rehacer ramificado, la nueva edición ramifica el historial de acciones.
La cantidad de acciones anteriores que se pueden deshacer varía según el programa, la versión y las capacidades del hardware o software. Por ejemplo, el tamaño predeterminado de la pila de deshacer/rehacer en Adobe Photoshop es 20, pero el usuario puede cambiarlo. Como otro ejemplo, las versiones anteriores [ ¿cuándo? ] de Microsoft Paint solo permitían deshacer hasta tres ediciones; la versión introducida en Windows 7 aumentó este límite a 50.
Las funciones de deshacer de una sola edición y simplistas a veces eliminan la función de "rehacer" al tratar el comando de deshacer en sí mismo como una acción que se puede deshacer. Esto se conoce como el modelo de deshacer con inversión, porque el usuario puede cambiar entre dos estados del programa utilizando el comando de deshacer. [13] Este era el modelo estándar antes de la adopción generalizada del deshacer de varios niveles a principios de los años 1990.
La función de deshacer se puede implementar mediante diferentes patrones. Los patrones más comunes son el patrón de comando y el patrón de recuerdo .
El patrón de comando es un patrón de diseño de software que encapsula la información de la operación en objetos de comando. Esto significa que cada acción se almacena en un objeto. La clase de comando abstracto implementa una operación de ejecución abstracta, por lo que cada objeto de comando tiene una operación de ejecución. Para deshacer también debe haber una operación no ejecutada, que deshaga el efecto del comando ejecutado, que se almacena en una lista de historial. Deshacer y rehacer se implementan de modo que la lista se recorra hacia adelante y hacia atrás cuando se llama al comando de ejecución o desejecución. [14]
En el caso de la operación de deshacer simple, solo se almacena el comando ejecutado. A diferencia de la operación de deshacer de varios niveles, en la que no solo se guarda la lista histórica con los comandos, sino que también se puede determinar el número de niveles de deshacer a partir de la longitud máxima de la lista. [14]
Con el patrón memento se almacena el estado interno de un objeto. El objeto en el que se guarda el estado se llama memento y se organiza a través del originador de memento. Este devuelve un memento, inicializado con información del estado actual, cuando se ejecuta undo, de modo que se pueda verificar el estado. El memento solo es visible para el originador.
En el patrón de mementos, el mecanismo de deshacer se llama cuidador. Es responsable de la custodia de los mementos, pero nunca cambia el contenido de estos. Para deshacer, el cuidador solicita un memento del creador y luego aplica la acción de deshacer. [14]
La mayor parte del mecanismo de deshacer se puede implementar sin depender de aplicaciones o clases de comandos específicas. Esto incluye "la gestión de la lista de historial, el deslizador de historial, las entradas de menú para deshacer y rehacer y la actualización de las entradas de menú según el nombre del siguiente comando disponible". [1]
Cada clase de comando tiene un método do que se llama cuando se ejecuta un comando. El método undo implementa la operación inversa del método do. Para implementar la operación inversa, existen varias estrategias diferentes.
el desarrollo más popular entre los usuarios novatos de FRESS no fue su capacidad para acomodar múltiples pantallas y usuarios, sino la función de "deshacer", la característica de la que van Dam está más orgulloso (van Dam 2011). FRESS fue pionero en la función de deshacer de un solo nivel tanto para el procesamiento de textos como para el hipertexto. Cada edición de un archivo se guardaba en una versión oculta de la estructura de datos, lo que permitía tanto un "guardado automático" como una función de deshacer. El personal y los estudiantes de Brown comprendieron inmediatamente la importancia y la utilidad de esta función (van Dam 1999).