Source code for timelinelib.canvas.data.transactions

# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018  Rickard Lindberg, Roger Lindberg
#
# This file is part of Timeline.
#
# Timeline is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Timeline is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Timeline.  If not, see <http://www.gnu.org/licenses/>.


from timelinelib.general.observer import Observable


[docs]class Transactions(Observable):
[docs] def __init__(self, initial_value, initial_name="", history_size=10): Observable.__init__(self) if history_size < 1: raise ValueError("history_size is to small (must be at least 1)") self._history_size = history_size self._history = [(initial_name, initial_value)] self._current_index = 0 self._current_transaction = None
@property def value(self): if self._current_transaction is not None: return self._current_transaction.value else: return self._history[self._current_index][1] @property def status(self): return ( self._current_index, self._current_transaction is not None, list(self._history) )
[docs] def clear(self): self.ensure_not_in_transaction() self._history = [self._history[self._current_index]] self._current_index = 0 self._notify()
[docs] def move(self, index): self.ensure_not_in_transaction() if index < 0 or index >= len(self._history): raise ValueError("Index does not exist in history") self._current_index = index self._notify()
[docs] def new(self, name): self._current_transaction = Transaction( self, name, self.value, self._current_transaction ) return self._current_transaction
[docs] def commit(self, transaction): self.ensure_is_current(transaction) self._current_transaction = transaction.parent if self._current_transaction is None: self._history = self._history[:self._current_index + 1] self._history.append((transaction.name, transaction.value)) self._history = self._history[-self._history_size:] self._current_index = len(self._history) - 1 self._notify() else: self._current_transaction.value = transaction.value
[docs] def rollback(self, transaction): self.ensure_is_current(transaction) self._current_transaction = transaction.parent
[docs] def ensure_is_current(self, transaction): if transaction is not self._current_transaction: raise TransactionError( "Operation on {0!r} is not allowed " "because it is not the current transaction".format( transaction ) )
[docs] def ensure_not_in_transaction(self): if self._current_transaction is not None: raise TransactionError( "Operation is not allowed " "because transaction {0!r} is active".format( self._current_transaction ) )
[docs]class TransactionError(Exception): pass
[docs]class Transaction:
[docs] def __init__(self, transactions, name, value, parent): self._transactions = transactions self._name = name self._value = value self._parent = parent
[docs] def __repr__(self): return "{0}(name={1!r}, ...)".format( self.__class__.__name__, self._name )
@property def name(self): return self._name @property def value(self): return self._value @value.setter def value(self, value): self._transactions.ensure_is_current(self) self._value = value @property def updater(self): return ValueUpdater(self) @property def parent(self): return self._parent
[docs] def commit(self): self._transactions.commit(self)
[docs] def rollback(self): self._transactions.rollback(self)
def __enter__(self): return self.updater def __exit__(self, exc_type, exc_val, exc_tb): if exc_type is None: self.commit() else: self.rollback()
[docs]class ValueUpdater:
[docs] def __init__(self, transaction): self._transaction = transaction
def __getattr__(self, name): def updater(*args, **kwargs): self._transaction.value = getattr( self._transaction.value, name )(*args, **kwargs) return updater