history.py :  » Development » Rope » rope-0.9.2 » rope » base » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » Rope 
Rope » rope 0.9.2 » rope » base » history.py
from rope.base import exceptions,change,taskhandle


class History(object):
    """A class that holds project history"""

    def __init__(self, project, maxundos=None):
        self.project = project
        self._undo_list = []
        self._redo_list = []
        self._maxundos = maxundos
        self._load_history()
        self.project.data_files.add_write_hook(self.write)
        self.current_change = None

    def _load_history(self):
        if self.save:
            result = self.project.data_files.read_data(
                'history', compress=self.compress, import_=True)
            if result is not None:
                to_change = change.DataToChange(self.project)
                for data in result[0]:
                    self._undo_list.append(to_change(data))
                for data in result[1]:
                    self._redo_list.append(to_change(data))

    def do(self, changes, task_handle=taskhandle.NullTaskHandle()):
        """Perform the change and add it to the `self.undo_list`

        Note that uninteresting changes (changes to ignored files)
        will not be appended to `self.undo_list`.

        """
        try:
            self.current_change = changes
            changes.do(change.create_job_set(task_handle, changes))
        finally:
            self.current_change = None
        if self._is_change_interesting(changes):
            self.undo_list.append(changes)
            self._remove_extra_items()
        del self.redo_list[:]

    def _remove_extra_items(self):
        if len(self.undo_list) > self.max_undos:
            del self.undo_list[0:len(self.undo_list) - self.max_undos]

    def _is_change_interesting(self, changes):
        for resource in changes.get_changed_resources():
            if not self.project.is_ignored(resource):
                return True
        return False

    def undo(self, change=None, drop=False,
             task_handle=taskhandle.NullTaskHandle()):
        """Redo done changes from the history

        When `change` is `None`, the last done change will be undone.
        If change is not `None` it should be an item from
        `self.undo_list`; this change and all changes that depend on
        it will be undone.  In both cases the list of undone changes
        will be returned.

        If `drop` is `True`, the undone change will not be appended to
        the redo list.

        """
        if not self._undo_list:
            raise exceptions.HistoryError('Undo list is empty')
        if change is None:
            change = self.undo_list[-1]
        dependencies = self._find_dependencies(self.undo_list, change)
        self._move_front(self.undo_list, dependencies)
        self._perform_undos(len(dependencies), task_handle)
        result = self.redo_list[-len(dependencies):]
        if drop:
            del self.redo_list[-len(dependencies):]
        return result

    def redo(self, change=None, task_handle=taskhandle.NullTaskHandle()):
        """Redo undone changes from the history

        When `change` is `None`, the last undone change will be
        redone.  If change is not `None` it should be an item from
        `self.redo_list`; this change and all changes that depend on
        it will be redone.  In both cases the list of redone changes
        will be returned.

        """
        if not self.redo_list:
            raise exceptions.HistoryError('Redo list is empty')
        if change is None:
            change = self.redo_list[-1]
        dependencies = self._find_dependencies(self.redo_list, change)
        self._move_front(self.redo_list, dependencies)
        self._perform_redos(len(dependencies), task_handle)
        return self.undo_list[-len(dependencies):]

    def _move_front(self, change_list, changes):
        for change in changes:
            change_list.remove(change)
            change_list.append(change)

    def _find_dependencies(self, change_list, change):
        index = change_list.index(change)
        return _FindChangeDependencies(change_list[index:])()

    def _perform_undos(self, count, task_handle):
        for i in range(count):
            self.current_change = self.undo_list[-1]
            try:
                job_set = change.create_job_set(task_handle,
                                                self.current_change)
                self.current_change.undo(job_set)
            finally:
                self.current_change = None
            self.redo_list.append(self.undo_list.pop())

    def _perform_redos(self, count, task_handle):
        for i in range(count):
            self.current_change = self.redo_list[-1]
            try:
                job_set = change.create_job_set(task_handle,
                                                self.current_change)
                self.current_change.do(job_set)
            finally:
                self.current_change = None
            self.undo_list.append(self.redo_list.pop())

    def contents_before_current_change(self, file):
        if self.current_change is None:
            return None
        result = self._search_for_change_contents([self.current_change], file)
        if result is not None:
            return result
        if file.exists() and not file.is_folder():
            return file.read()
        else:
            return None

    def _search_for_change_contents(self, change_list, file):
        for change_ in reversed(change_list):
            if isinstance(change_, change.ChangeSet):
                result = self._search_for_change_contents(change_.changes,
                                                          file)
                if result is not None:
                    return result
            if isinstance(change_, change.ChangeContents) and \
               change_.resource == file:
                return change_.old_contents

    def write(self):
        if self.save:
            data = []
            to_data = change.ChangeToData()
            self._remove_extra_items()
            data.append([to_data(change_) for change_ in self.undo_list])
            data.append([to_data(change_) for change_ in self.redo_list])
            self.project.data_files.write_data('history', data,
                                               compress=self.compress)

    def get_file_undo_list(self, resource):
        result = []
        for change in self.undo_list:
            if resource in change.get_changed_resources():
                result.append(change)
        return result

    def __str__(self):
        return 'History holds %s changes in memory' % \
               (len(self.undo_list) + len(self.redo_list))

    undo_list = property(lambda self: self._undo_list)
    redo_list = property(lambda self: self._redo_list)

    @property
    def tobe_undone(self):
        """The last done change if available, `None` otherwise"""
        if self.undo_list:
            return self.undo_list[-1]

    @property
    def tobe_redone(self):
        """The last undone change if available, `None` otherwise"""
        if self.redo_list:
            return self.redo_list[-1]

    @property
    def max_undos(self):
        if self._maxundos is None:
            return self.project.prefs.get('max_history_items', 100)
        else:
            return self._maxundos

    @property
    def save(self):
        return self.project.prefs.get('save_history', False)

    @property
    def compress(self):
        return self.project.prefs.get('compress_history', False)

    def clear(self):
        """Forget all undo and redo information"""
        del self.undo_list[:]
        del self.redo_list[:]


class _FindChangeDependencies(object):

    def __init__(self, change_list):
        self.change = change_list[0]
        self.change_list = change_list
        self.changed_resources = set(self.change.get_changed_resources())

    def __call__(self):
        result = [self.change]
        for change in self.change_list[1:]:
            if self._depends_on(change, result):
                result.append(change)
                self.changed_resources.update(change.get_changed_resources())
        return result

    def _depends_on(self, changes, result):
        for resource in changes.get_changed_resources():
            if resource is None:
                continue
            if resource in self.changed_resources:
                return True
            for changed in self.changed_resources:
                if resource.is_folder() and resource.contains(changed):
                    return True
                if changed.is_folder() and changed.contains(resource):
                    return True
        return False
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.