basesource.py :  » Project-Management » Task-Coach » TaskCoach-1.0.3 » taskcoachlib » syncml » 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 » Project Management » Task Coach 
Task Coach » TaskCoach 1.0.3 » taskcoachlib » syncml » basesource.py
'''
Task Coach - Your friendly task manager
Copyright (C) 2008 Jerome Laheurte <fraca7@free.fr>

Task Coach 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.

Task Coach 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 this program.  If not, see <http://www.gnu.org/licenses/>.
'''

import wx
from taskcoachlib.syncml.core import *
from taskcoachlib.i18n import _


class BaseSource(SyncSource):
    STATE_NONE         = 0
    STATE_FIRSTPASS    = 1
    STATE_SECONDPASS   = 2
    STATE_NORMAL       = 3

    def __init__(self, callback, objectList, *args, **kwargs):
        super(BaseSource, self).__init__(*args, **kwargs)

        self.callback = callback
        self.objectList = objectList

        self.allObjectsList = [obj for obj in objectList]
        self.newObjectsList = [obj for obj in objectList if obj.isNew()]
        self.changedObjectsList = [obj for obj in objectList if obj.isModified()]
        self.deletedObjectsList = [obj for obj in objectList if obj.isDeleted()]

        self.state = self.STATE_NONE
        self.lastLast = None

    def __getstate__(self):
        return {'state': self.state, 'lastLast': self.lastLast}

    def __setstate__(self, state):
        self.__dict__.update(state)

    def beginSync(self):
        if self.state == self.STATE_NONE:
            if self.syncMode in [TWO_WAY, SLOW]:
                self.lastLast = self.lastAnchor
                self.state = self.STATE_FIRSTPASS
            elif self.syncMode in [REFRESH_FROM_SERVER,
                                 REFRESH_FROM_SERVER_BY_SERVER]:
                if self.objectList:
                    if wx.MessageBox(_('The synchronization for source %s') % self.name + \
                                     _('will be a refresh from server. All local items will\n' \
                                       'be deleted. Do you wish to continue?'),
                                     _('Refresh from server'), wx.YES_NO) != wx.YES:
                        return 514 # Not sure of this
                    self.objectList.clear()
                    self.allObjectsList = []
                    self.newObjectsList = []
                    self.changedObjectsList = []
                    self.deletedObjectsList = []
            elif self.syncMode in [REFRESH_FROM_CLIENT,
                                   REFRESH_FROM_CLIENT_BY_SERVER]:
                if wx.MessageBox(_('The synchronization for source %s') % self.name + \
                                 _('will be a refresh from client. All remote items will\n' \
                                   'be deleted. Do you wish to continue?'),
                                 _('Refresh from server'), wx.YES_NO) != wx.YES:
                    return 514 # Not sure of this

                self.state = self.STATE_NORMAL
        elif self.state == self.STATE_FIRSTPASS:
            lastLast = self.lastAnchor
            self.lastAnchor = self.lastLast
            self.lastLast = lastLast
            self.state = self.STATE_SECONDPASS

    def endSync(self):
        if self.state == self.STATE_SECONDPASS:
            self.lastAnchor = self.lastLast

    def _getObject(self, key):
        """Returns the domain object with local ID 'key', or raise
        KeyError if not found."""

        for obj in self.allObjectsList:
            if obj.id() == key:
                return obj
        raise KeyError, 'No such object: %s' % key

    def _getItem(self, ls):
        """Returns a SyncItem instance representing the first domain
        object in the 'ls' sequence."""

        try:
            obj = ls.pop(0)
        except IndexError:
            return None

        item = SyncItem(obj.id())

        if obj.getStatus() == obj.STATUS_NONE:
            item.state = STATE_NONE
        elif obj.getStatus() == obj.STATUS_NEW:
            item.state = STATE_NEW
        elif obj.getStatus() == obj.STATUS_CHANGED:
            item.state = STATE_UPDATED
        elif obj.getStatus() == obj.STATUS_DELETED:
            item.state = STATE_DELETED

        self.updateItemProperties(item, obj)

        return item

    def updateItemProperties(self, item, obj):
        """Set item properties (data, dataType...) according to the
        domain object 'obj'. You must overload this in subclasses."""

        raise NotImplementedError

    def compareItemProperties(self, local, remote):
        """Compare the two domain objects, and return 0 if they're the
        same. The return value will then be passed to the conflict
        resolution methods if there is a conflict."""

        raise NotImplementedError

    def _parseObject(self, item):
        """Must return a new domain object from a SyncItem instance."""

        raise NotImplementedError

    # These two methods seem to be obsolete.

    def getFirstItemKey(self):
        return None

    def getNextItemKey(self):
        return None

    def getFirstItem(self):
        self.callback.pulse()

        if self.state in [self.STATE_NORMAL, self.STATE_SECONDPASS]:
            self.allObjectsListCopy = self.allObjectsList[:]
            return self._getItem(self.allObjectsListCopy)

    def getNextItem(self):
        self.callback.pulse()

        if self.state in [self.STATE_NORMAL, self.STATE_SECONDPASS]:
            return self._getItem(self.allObjectsListCopy)

    def getFirstNewItem(self):
        self.callback.pulse()

        if self.state in [self.STATE_NORMAL, self.STATE_SECONDPASS]:
            self.newObjectsListCopy = self.newObjectsList[:]
            return self._getItem(self.newObjectsListCopy)

    def getNextNewItem(self):
        self.callback.pulse()

        if self.state in [self.STATE_NORMAL, self.STATE_SECONDPASS]:
            return self._getItem(self.newObjectsListCopy)

    def getFirstUpdatedItem(self):
        self.callback.pulse()

        if self.state in [self.STATE_NORMAL, self.STATE_SECONDPASS]:
            self.changedObjectsListCopy = self.changedObjectsList[:]
            return self._getItem(self.changedObjectsListCopy)

    def getNextUpdatedItem(self):
        self.callback.pulse()

        if self.state in [self.STATE_NORMAL, self.STATE_SECONDPASS]:
            return self._getItem(self.changedObjectsListCopy)

    def getFirstDeletedItem(self):
        self.callback.pulse()

        if self.state in [self.STATE_NORMAL, self.STATE_SECONDPASS]:
            self.deletedObjectsListCopy = self.deletedObjectsList[:]
            return self._getItem(self.deletedObjectsListCopy)

    def getNextDeletedItem(self):
        self.callback.pulse()

        if self.state in [self.STATE_NORMAL, self.STATE_SECONDPASS]:
            return self._getItem(self.deletedObjectsListCopy)

    def addItem(self, item):
        self.callback.onAddItem()

        if self.state in [self.STATE_NORMAL, self.STATE_FIRSTPASS]:
            obj = self._parseObject(item)
            self.objectList.append(obj)
            item.key = obj.id().encode('UTF-8')

            return self.doAddItem(obj)

        return 201

    def doAddItem(self, obj):
        """Called after a domain object has been added; use this to
        set up the object if it needs to."""

        return 201

    def updateItem(self, item):
        self.callback.onUpdateItem()

        if self.state in [self.STATE_NORMAL, self.STATE_FIRSTPASS]:
            obj = self._parseObject(item)

            try:
                local = self._getObject(item.key)
            except KeyError:
                return 404

            if local.isModified():
                result = self.compareItemProperties(local, obj)

                if result:
                    obj = self.doResolveConflict(obj, local, result)
                    local.markDirty() # so that the resolved item is uploaded on second pass
            elif local.isDeleted():
                if self.objectRemovedOnClient(local):
                    self.doUpdateItem(obj, local)
                    local.cleanDirty()
                    return 200

            return self.doUpdateItem(obj, local)

        return 200

    def doUpdateItem(self, obj, local):
        """Must update the 'local' domain object according to 'obj'
        (which is a 'temporary' domain object)"""

        raise NotImplementedError

    def deleteItem(self, item):
        self.callback.onDeleteItem()

        if self.state in [self.STATE_NORMAL, self.STATE_FIRSTPASS]:
            try:
                obj = self._getObject(item.key)
            except KeyError:
                return 211

            if obj.isModified():
                if self.objectRemovedOnServer(obj):
                    obj.markNew() # Will be uploaded on second pass
                else:
                    self.objectList.remove(obj)
            else:
                self.objectList.remove(obj)

        return 200

    def doResolveConflict(self, obj, local, result):
        """Called when an object has been modified both on server and
        client. Must return a domain object to replace both."""

        raise NotImplementedError

    def objectRemovedOnServer(self, obj):
        """Called when an object has been removed on server and
        locally modified. Return True to keep the object alive."""

        raise NotImplementedError

    def objectRemovedOnClient(self, obj):
        """Called when an object has been removed on client and
        remotely modified. Return True to keep the object alive."""

        raise NotImplementedError

    def setItemStatus(self, key, status):
        self.callback.pulse()

        if self.state in [self.STATE_NORMAL, self.STATE_SECONDPASS]:
            obj = self._getObject(key)

            if status in [200, 201, 211, 418]:
                # 200: Generic OK
                # 201: Added.
                # 211: Item not deleted (not found)
                # 418: Already exists.

                if obj.isDeleted():
                    self.objectList.remove(obj)
                else:
                    obj.cleanDirty()

                return 200

            print 'UNHANDLED ITEM STATUS %s %d' % (key, status)

            return 501
        else:
            raise RuntimeError, 'This shouldn\'t happen'
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.