Package Gnumed :: Package timelinelib :: Package canvas :: Package data :: Module transactions |
[frames] | no frames]

# Source Code for Module Gnumed.timelinelib.canvas.data.transactions

      1  # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018  Rickard Lindberg, Roger Lindberg
      2  #
      3  # This file is part of Timeline.
      4  #
      5  # Timeline is free software: you can redistribute it and/or modify
      6  # it under the terms of the GNU General Public License as published by
      7  # the Free Software Foundation, either version 3 of the License, or
      8  # (at your option) any later version.
      9  #
     10  # Timeline is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  # GNU General Public License for more details.
     14  #
     15  # You should have received a copy of the GNU General Public License
     16  # along with Timeline.  If not, see <http://www.gnu.org/licenses/>.
     17
     18
     19  from timelinelib.general.observer import Observable
     20
     21
     22 -class Transactions(Observable):
     23
     24 -    def __init__(self, initial_value, initial_name="", history_size=10):
     25          Observable.__init__(self)
     26          if history_size < 1:
     27              raise ValueError("history_size is to small (must be at least 1)")
     28          self._history_size = history_size
     29          self._history = [(initial_name, initial_value)]
     30          self._current_index = 0
     31          self._current_transaction = None
     32
     33      @property
     34 -    def value(self):
     35          if self._current_transaction is not None:
     36              return self._current_transaction.value
     37          else:
     38              return self._history[self._current_index][1]
     39
     40      @property
     41 -    def status(self):
     42          return (
     43              self._current_index,
     44              self._current_transaction is not None,
     45              list(self._history)
     46          )
     47
     48 -    def clear(self):
     49          self.ensure_not_in_transaction()
     50          self._history = [self._history[self._current_index]]
     51          self._current_index = 0
     52          self._notify()
     53
     54 -    def move(self, index):
     55          self.ensure_not_in_transaction()
     56          if index < 0 or index >= len(self._history):
     57              raise ValueError("Index does not exist in history")
     58          self._current_index = index
     59          self._notify()
     60
     61 -    def new(self, name):
     62          self._current_transaction = Transaction(
     63              self,
     64              name,
     65              self.value,
     66              self._current_transaction
     67          )
     68          return self._current_transaction
     69
     70 -    def commit(self, transaction):
     71          self.ensure_is_current(transaction)
     72          self._current_transaction = transaction.parent
     73          if self._current_transaction is None:
     74              self._history = self._history[:self._current_index + 1]
     75              self._history.append((transaction.name, transaction.value))
     76              self._history = self._history[-self._history_size:]
     77              self._current_index = len(self._history) - 1
     78              self._notify()
     79          else:
     80              self._current_transaction.value = transaction.value
     81
     82 -    def rollback(self, transaction):
     83          self.ensure_is_current(transaction)
     84          self._current_transaction = transaction.parent
     85
     86 -    def ensure_is_current(self, transaction):
     87          if transaction is not self._current_transaction:
     88              raise TransactionError(
     89                  "Operation on {0!r} is not allowed "
     90                  "because it is not the current transaction".format(
     91                      transaction
     92                  )
     93              )
     94
     95 -    def ensure_not_in_transaction(self):
     96          if self._current_transaction is not None:
     97              raise TransactionError(
     98                  "Operation is not allowed "
     99                  "because transaction {0!r} is active".format(
    100                      self._current_transaction
    101                  )
    102              )
    103
    104
    105 -class TransactionError(Exception):
    106      pass
    107
    108
    109 -class Transaction(object):
    110
    111 -    def __init__(self, transactions, name, value, parent):
    112          self._transactions = transactions
    113          self._name = name
    114          self._value = value
    115          self._parent = parent
    116
    117 -    def __repr__(self):
    118          return "{0}(name={1!r}, ...)".format(
    119              self.__class__.__name__,
    120              self._name
    121          )
    122
    123      @property
    124 -    def name(self):
    125          return self._name
    126
    127      @property
    128 -    def value(self):
    129          return self._value
    130
    131      @value.setter
    132 -    def value(self, value):
    133          self._transactions.ensure_is_current(self)
    134          self._value = value
    135
    136      @property
    137 -    def updater(self):
    138          return ValueUpdater(self)
    139
    140      @property
    141 -    def parent(self):
    142          return self._parent
    143
    144 -    def commit(self):
    145          self._transactions.commit(self)
    146
    147 -    def rollback(self):
    148          self._transactions.rollback(self)
    149
    150 -    def __enter__(self):
    151          return self.updater
    152
    153 -    def __exit__(self, exc_type, exc_val, exc_tb):
    154          if exc_type is None:
    155              self.commit()
    156          else:
    157              self.rollback()
    158
    159
    160 -class ValueUpdater(object):
    161
    162 -    def __init__(self, transaction):
    163          self._transaction = transaction
    164
    165 -    def __getattr__(self, name):
    166          def updater(*args, **kwargs):
    167              self._transaction.value = getattr(
    168                  self._transaction.value,
    169                  name
    170              )(*args, **kwargs)
    171          return updater
    172