0034237285cf0ee6034128d29c70c50371b0730a
[canola-rtm] / canola-rtm / rtm / model.py
1 # Canola2 Remember The Milk Plugin
2 # Authors: Andrey Popelo <andrey@popelo.com>
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 #
17 # Additional permission under GNU GPL version 3 section 7
18 #
19 # If you modify this Program, or any covered work, by linking or combining it
20 # with Canola2 and its core components (or a modified version of any of those),
21 # containing parts covered by the terms of Instituto Nokia de Tecnologia End
22 # User Software Agreement, the licensors of this Program grant you additional
23 # permission to convey the resulting work.
24
25 import logging
26 import urllib2
27 import socket
28
29 from terra.core.manager import Manager
30 from terra.core.task import Task
31 from terra.core.model import ModelFolder, Model
32 from terra.core.threaded_func import ThreadedFunction
33
34 from client import Client
35
36
37 manager = Manager()
38 PluginDefaultIcon = manager.get_class("Icon/Plugin")
39
40 log = logging.getLogger("plugins.canola-rtm.model")
41
42
43 class Icon(PluginDefaultIcon):
44     terra_type = "Icon/Folder/Task/Apps/RTM"
45     icon = "icon/main_item/rtm"
46     plugin = "rtm"
47
48 # TODO more documentation
49 class RTMTaskModel(Model):
50     """Base class for Remember The Milk task models.
51
52     """
53     terra_type = "Model/RTMTask"
54
55     def __init__(self, name, parent=None):
56         Model.__init__(self, name, parent)
57         self.duedate = ""
58         self.priority = ""
59
60 class ServiceModelFolder(ModelFolder):
61     terra_type = "Model/Folder/Task/Apps/RTM/Service"
62
63     threaded_search = True
64     empty_msg = "No tasks found"
65
66     def __init__(self, name, parent):
67         ModelFolder.__init__(self, name, parent)
68         self.callback_notify = None
69         # TODO change token
70         self.client = Client('1e6e489de9374b43ba280ab9741d290c', 'c7197d30f722247d', '1f4c8846175f4bafcf70f7742f4670e41b0ab046')
71
72     def do_load(self):
73         self.search()
74
75     def search(self, end_callback=None):
76         del self.children[:]
77
78         if not self.threaded_search:
79             for item in self.do_search():
80                 self.children.append(item)
81             return
82
83         def refresh():
84             return self.do_search()
85
86         def refresh_finished(exception, retval):
87             if not self.is_loading:
88                 log.info("model is not loading")
89                 return
90
91             if exception is not None:
92                 if type(exception) is socket.gaierror or \
93                         type(exception) is urllib2.URLError:
94                     emsg = "Unable to connect to server.<br>" + \
95                         "Check your connection and try again."
96                 else:
97                     emsg = "An unknown error has occured."
98
99                 log.error(exception)
100
101                 if self.callback_notify:
102                     self.callback_notify(CanolaError(emsg))
103
104             if retval is None:
105                 self.inform_loaded()
106                 return
107
108             for item in retval:
109                 self.children.append(item)
110
111             if end_callback:
112                 end_callback()
113
114             self.inform_loaded()
115
116         self.is_loading = True
117         ThreadedFunction(refresh_finished, refresh).start()
118
119     def do_search(self):
120         raise NotImplementedError("must be implemented by subclasses")
121
122 ##############################################################################
123 # Remember The Milk Remote Service Models
124 ##############################################################################
125
126 class TodayModelFolder(ServiceModelFolder):
127     """This model implements the Today option."""
128     terra_type = "Model/Folder/Task/Apps/RTM/Service/Today"
129
130     def __init__(self, name, parent):
131         ServiceModelFolder.__init__(self, name, parent)
132
133     def do_search(self):
134         lst = []
135         self.client.tasks.getList(filter='dueBefore:tomorrow')
136         # TODO remove stubs
137         lst = [ RTMTaskModel("Task #1 (stub)"),
138                 RTMTaskModel("Task #2 (stub)"),
139                 RTMTaskModel("Task #3 (stub)") ]
140
141         return lst
142
143
144 ##############################################################################
145 # Main Remember The Milk Model
146 ##############################################################################
147
148 class MainModelFolder(ModelFolder, Task):
149     """Main Remember The Milk Model.
150
151     This is the main remember the milk model. It initializes all other models.
152     """
153     terra_type = "Model/Folder/Task/Apps/RTM"
154     terra_task_type = "Task/Folder/Task/Apps/RTM"
155
156     def __init__(self, parent):
157         Task.__init__(self)
158         ModelFolder.__init__(self, "Remember the milk", parent)
159
160     def do_load(self):
161         """Initialize base remember the milk models, like Today, Smart
162         lists, Search and others.
163         """
164         TodayModelFolder("Today", self);
165