46
45
A particular backend should redefine all the methods marked as such.
50
48
###########################################################################
51
49
### BACKEND INTERFACE #####################################################
52
50
###########################################################################
54
#General description of the backend: these parameters are used
55
#to show a description of the backend to the user when s/he is
56
#considering adding it.
51
# General description of the backend: these parameters are used
52
# to show a description of the backend to the user when s/he is
53
# considering adding it.
57
54
# For an example, see the GTG/backends/backend_localfile.py file
58
#_general_description has this format:
59
#_general_description = {
55
# _general_description has this format:
56
# _general_description = {
60
57
# GenericBackend.BACKEND_NAME: "backend_unique_identifier", \
61
58
# GenericBackend.BACKEND_HUMAN_NAME: _("Human friendly name"), \
62
59
# GenericBackend.BACKEND_AUTHORS: ["First author", \
169
166
###########################################################################
170
167
### CONSTANTS #############################################################
171
168
###########################################################################
172
#BACKEND TYPE DESCRIPTION
169
# BACKEND TYPE DESCRIPTION
173
170
# Each backend must have a "_general_description" attribute, which
174
171
# is a dictionary that holds the values for the following keys.
175
BACKEND_NAME = "name" #the backend gtg internal name (doesn't change in
172
BACKEND_NAME = "name" # the backend gtg internal name (doesn't change in
176
173
# translations, *must be unique*)
177
BACKEND_HUMAN_NAME = "human-friendly-name" #The name shown to the user
178
BACKEND_DESCRIPTION = "description" #A short description of the backend
179
BACKEND_AUTHORS = "authors" #a list of strings
174
BACKEND_HUMAN_NAME = "human-friendly-name" # The name shown to the user
175
BACKEND_DESCRIPTION = "description" # A short description of the backend
176
BACKEND_AUTHORS = "authors" # a list of strings
180
177
BACKEND_TYPE = "type"
181
#BACKEND_TYPE is one of:
178
# BACKEND_TYPE is one of:
182
179
TYPE_READWRITE = "readwrite"
183
180
TYPE_READONLY = "readonly"
184
181
TYPE_IMPORT = "import"
185
182
TYPE_EXPORT = "export"
188
184
#"static_parameters" is a dictionary of dictionaries, each of which
189
185
# are a description of a parameter needed to configure the backend and
190
186
# is identified in the outer dictionary by a key which is the name of the
192
188
# For an example, see the GTG/backends/backend_localfile.py file
193
189
# Each dictionary contains the keys:
194
PARAM_DEFAULT_VALUE = "default_value" # its default value
196
#PARAM_TYPE is one of the following (changing this changes the way
190
PARAM_DEFAULT_VALUE = "default_value" # its default value
192
# PARAM_TYPE is one of the following (changing this changes the way
197
193
# the user can configure the parameter)
198
TYPE_PASSWORD = "password" #the real password is stored in the GNOME
194
TYPE_PASSWORD = "password" # the real password is stored in the GNOME
200
196
# This is just a key to find it there
201
TYPE_STRING = "string" #generic string, nothing fancy is done
202
TYPE_INT = "int" #edit box can contain only integers
203
TYPE_BOOL = "bool" #checkbox is shown
204
TYPE_LIST_OF_STRINGS = "liststring" #list of strings. the "," character is
205
# prohibited in strings
197
TYPE_STRING = "string" # generic string, nothing fancy is done
198
TYPE_INT = "int" # edit box can contain only integers
199
TYPE_BOOL = "bool" # checkbox is shown
200
TYPE_LIST_OF_STRINGS = "liststring" # list of strings. the "," character
201
# is prohibited in strings
207
#These parameters are common to all backends and necessary.
203
# These parameters are common to all backends and necessary.
208
204
# They will be added automatically to your _static_parameters list
209
#NOTE: for now I'm disabling changing the default backend. Once it's all
205
# NOTE: for now I'm disabling changing the default backend. Once it's all
210
206
# set up, we will see about that (invernizzi)
211
207
KEY_DEFAULT_BACKEND = "Default"
212
KEY_ENABLED = "Enabled"
208
KEY_ENABLED = "enabled"
213
209
KEY_HUMAN_NAME = BACKEND_HUMAN_NAME
214
210
KEY_ATTACHED_TAGS = "attached-tags"
215
211
KEY_USER = "user"
217
ALLTASKS_TAG = "gtg-tags-all" #NOTE: this has been moved here to avoid
213
ALLTASKS_TAG = "gtg-tags-all" # NOTE: this has been moved here to avoid
218
214
# circular imports. It's the same as in
219
215
# the CoreConfig class, because it's the
220
216
# same thing conceptually. It doesn't
221
217
# matter it the naming diverges.
223
_static_parameters_obligatory = { \
224
KEY_DEFAULT_BACKEND: { \
225
PARAM_TYPE: TYPE_BOOL, \
226
PARAM_DEFAULT_VALUE: False, \
229
PARAM_TYPE: TYPE_STRING, \
230
PARAM_DEFAULT_VALUE: "", \
233
PARAM_TYPE: TYPE_STRING, \
234
PARAM_DEFAULT_VALUE: "", \
237
PARAM_TYPE: TYPE_STRING, \
238
PARAM_DEFAULT_VALUE: "", \
241
PARAM_TYPE: TYPE_BOOL, \
242
PARAM_DEFAULT_VALUE: False, \
245
_static_parameters_obligatory_for_rw = { \
246
KEY_ATTACHED_TAGS: {\
247
PARAM_TYPE: TYPE_LIST_OF_STRINGS, \
248
PARAM_DEFAULT_VALUE: [ALLTASKS_TAG], \
251
#Handy dictionary used in type conversion (from string to type)
219
_static_parameters_obligatory = {
220
KEY_DEFAULT_BACKEND: {
221
PARAM_TYPE: TYPE_BOOL,
222
PARAM_DEFAULT_VALUE: False,
225
PARAM_TYPE: TYPE_STRING,
226
PARAM_DEFAULT_VALUE: "",
229
PARAM_TYPE: TYPE_STRING,
230
PARAM_DEFAULT_VALUE: "",
233
PARAM_TYPE: TYPE_STRING,
234
PARAM_DEFAULT_VALUE: "",
237
PARAM_TYPE: TYPE_BOOL,
238
PARAM_DEFAULT_VALUE: False,
241
_static_parameters_obligatory_for_rw = {
243
PARAM_TYPE: TYPE_LIST_OF_STRINGS,
244
PARAM_DEFAULT_VALUE: [ALLTASKS_TAG],
247
# Handy dictionary used in type conversion (from string to type)
252
248
_type_converter = {TYPE_STRING: str,
257
253
def _get_static_parameters(cls):
278
274
want to check out the initialize() function.
280
276
if self.KEY_DEFAULT_BACKEND not in parameters:
281
#if it's not specified, then this is the default backend
277
# if it's not specified, then this is the default backend
282
278
#(for retro-compatibility with the GTG 0.2 series)
283
279
parameters[self.KEY_DEFAULT_BACKEND] = True
284
#default backends should get all the tasks
280
# default backends should get all the tasks
285
281
if parameters[self.KEY_DEFAULT_BACKEND] or \
286
(not self.KEY_ATTACHED_TAGS in parameters and \
287
self._general_description[self.BACKEND_TYPE] \
288
== self.TYPE_READWRITE):
282
(not self.KEY_ATTACHED_TAGS in parameters and
283
self._general_description[self.BACKEND_TYPE]
284
== self.TYPE_READWRITE):
289
285
parameters[self.KEY_ATTACHED_TAGS] = [self.ALLTASKS_TAG]
290
286
self._parameters = parameters
291
287
self._signal_manager = BackendSignals()
292
288
self._is_initialized = False
293
#if debugging mode is enabled, tasks should be saved as soon as they're
294
# marked as modified. If in normal mode, we prefer speed over easier
289
# if debugging mode is enabled, tasks should be saved as soon as
290
# they're marked as modified. If in normal mode, we prefer speed over
296
292
if Log.is_debugging_mode():
297
293
self.timer_timestep = 5
299
self.timer_timestep = 1
295
self.timer_timestep = 1
300
296
self.to_set_timer = None
301
297
self.please_quit = False
302
self.cancellation_point = lambda: _cancellation_point(\
303
lambda: self.please_quit)
298
self.cancellation_point = lambda: _cancellation_point(
299
lambda: self.please_quit)
304
300
self.to_set = deque()
305
301
self.to_remove = deque()
585
580
return pickle.load(file)
586
581
except Exception:
587
Log.error("Pickle file for backend '%s' is damaged" % \
582
Log.error("Pickle file for backend '%s' is damaged" %
590
585
# Loading file failed, trying backups
591
for i in range(1, PICKLE_BACKUP_NBR+1):
586
for i in range(1, PICKLE_BACKUP_NBR + 1):
592
587
backup_file = "%s.bak.%d" % (path, i)
593
588
if os.path.exists(backup_file):
594
589
with open(backup_file, 'r') as file:
596
591
data = pickle.load(file)
597
Log.info("Succesfully restored backup #%d for '%s'" % \
598
(i, self.get_name()))
592
Log.info("Succesfully restored backup #%d for '%s'" %
593
(i, self.get_name()))
600
595
except Exception:
601
Log.error("Backup #%d for '%s' is damaged as well" % \
602
(i, self.get_name()))
596
Log.error("Backup #%d for '%s' is damaged as well" %
597
(i, self.get_name()))
604
599
# Data could not be loaded, degrade to default data
605
Log.error("There is no suitable backup for '%s', " \
606
"loading default data" % self.get_name())
600
Log.error("There is no suitable backup for '%s', "
601
"loading default data" % self.get_name())
607
602
return default_value
610
604
def _gtg_task_is_syncable_per_attached_tags(self, task):
612
606
Helper function which checks if the given task satisfies the filtering
622
616
for tag in task.get_tags_name():
623
617
if tag in attached_tags:
627
621
###############################################################################
628
622
### THREADING #################################################################
629
623
###############################################################################
631
624
def __try_launch_setting_thread(self):
633
626
Helper function to launch the setting thread, if it's not running.
635
if self.to_set_timer == None and self.is_enabled():
636
self.to_set_timer = threading.Timer(self.timer_timestep, \
637
self.launch_setting_thread)
628
if self.to_set_timer is None and self.is_enabled():
629
self.to_set_timer = threading.Timer(self.timer_timestep,
630
self.launch_setting_thread)
638
631
self.to_set_timer.start()
640
def launch_setting_thread(self, bypass_quit_request = False):
633
def launch_setting_thread(self, bypass_quit_request=False):
642
635
This function is launched as a separate thread. Its job is to perform
643
the changes that have been issued from GTG core.
636
the changes that have been issued from GTG core.
644
637
In particular, for each task in the self.to_set queue, a task
645
638
has to be modified or to be created (if the tid is new), and for
646
639
each task in the self.to_remove queue, a task has to be deleted