1# -*- coding: UTF-8 -*-
2
3__revision__ = '$Id$'
4
5# Copyright © 2009 Piotr Ożarowski
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published byp
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU Library General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
20
21# You may use and distribute this software under the terms of the
22# GNU General Public License, version 2 or later
23
24import glob
25import logging
26import os.path
27import sys
28
29import db
30
31log = logging.getLogger('Griffith')
32
33# minimum and maximum supported extension API
34COMPAT = (1, 1)
35
36
37class GriffithExtensionBase(object):
38    """Griffith Extension
39
40    :attr config: configuration
41    :attr db: database
42    :attr locations: dictionary with Griffth locations
43    :attr widgets: dictionary with GUI widgets
44    :attr preferences: dictionary used to generate new widgets in preferences window
45        every key points to another dictionary that contains:
46        * name: will be shown to user
47        * type: int, unicode (type) or list, tuple, dict (instance)
48        * min: minimum value (int) or length (unicode)
49        * max: maximum value (int) or length (unicode)
50    :attr app: application reference (use only if really needed)
51    """
52    name = None
53    description = None
54    author = None
55    email = None
56    version = None
57    api = 1 # required Griffith Extension API
58
59    enabled = True # default state (can be changed in preferences later)
60    toolbar_icon = None # None or stock icon name
61    preferences = {}
62
63    toolbar_icon_widget = None # will be constructed from toolbar_icon
64
65    def __new__(class_, *args, **kwargs):
66        if class_.api < COMPAT[0]:
67            raise DeprecationWarning("Extension is using API that is no longer supported: %s (api=%d)" % (class_.name, class_.api))
68        if class_.api > COMPAT[1]:
69            raise NotImplementedError("Extension is using API that is not yet supported: %s (api=%d)" % (class_.name, class_.api))
70        obj = object.__new__(class_)
71        obj.app = app = args[0]
72        obj.widgets = app.widgets
73        obj.config = app.config
74        obj.db = app.db
75        obj.locations = app.locations
76        return obj
77
78    def __repr__(self):
79        return "<GriffithExtension api=%d name=%s version=%s>" % (self.api, self.name, self.version)
80
81    def get_config_value(self, key, default=None):
82        return self.config.get("%s_%s" % (self.id, key), default, section='extensions')
83
84    def set_config_value(self, key, value=None):
85        self.config.set("%s_%s" % (self.id, key), value, section='extensions')
86        self.config.save()
87
88    def _on_toolbar_icon_clicked(self, button_widget):
89        session = self.db.Session()
90        movie = session.query(db.Movie).filter(db.Movie.movie_id == self.app._movie_id).first()
91        if not movie:
92            log.error('No movie selected')
93        else:
94            self.toolbar_icon_clicked(button_widget, movie)
95
96    # methods that can be overwritten:
97
98    def __init__(self, griffith):
99        """Initializes extension"""
100
101    def clear(self): # __del__ cannot be used here (signal reference issue)
102        """Invoked when extension is about to be disabled"""
103        if self.toolbar_icon_widget:
104            self.toolbar_icon_widget.destroy()
105
106    def maintree_clicked(self, selection, movie):
107        """Invoked every time new movie is selected"""
108
109    def toolbar_icon_clicked(self, widget, movie):
110        """Invoked when toolbar icon is clicked"""
111
112    def filter_movies(self, conditions):
113        """Modifies movie selection (via search conditions)"""
114        return conditions
115
116
117by_name = {} # extension modules by name
118
119
120def scan_for_extensions(path):
121    """Adds new extensions from given path"""
122
123    names = dict((os.path.basename(x)[:-3], x) for x in glob.glob("%s/ge_[a-zA-Z]*.py" % path))
124    names.update(dict((os.path.basename(x)[:-4], x) for x in glob.glob("%s/ge_[a-zA-Z]*.pyo" % path)))
125    names.update(dict((os.path.basename(x)[:-4], x) for x in glob.glob("%s/ge_[a-zA-Z]*.pyc" % path)))
126
127    if names:
128        remove_from_syspath = False
129        if path not in sys.path:
130            remove_from_syspath = True
131            sys.path.append(path)
132
133        for ext_name in names:
134            #module = __import__("plugins.extensions.%s" % ext_name, fromlist=[ext_name])
135            module = __import__(ext_name)
136            id_ = ext_name[3:] # skip the "ge_"
137            extension = module.GriffithExtension
138            extension.id = id_
139            extension.__file__ = names[ext_name]
140            by_name[id_] = extension
141
142        if remove_from_syspath:
143            del sys.path[-1]
144
145scan_for_extensions(os.path.dirname(__file__)) # user's directory will be added later (in app)
146