~universal-applets-extras-team/universal-applets/universal-applets-extras

« back to all changes in this revision

Viewing changes to src/FolderViewClone/FolderViewCloneScreenlet.py

  • Committer: Julien Lavergne
  • Date: 2009-03-12 22:37:56 UTC
  • Revision ID: julien.lavergne@gmail.com-20090312223756-zlv6wj64jeodvq68
FolderViewClone : Add a clone of FolderView plasmoid.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
#  Julien Lavergne (c) 2009 julien.lavergne@gmail.com
 
4
#
 
5
#This program is free software; you can redistribute it and/or
 
6
#modify it under the terms of the GNU General Public License
 
7
#as published by the Free Software Foundation; either version 2
 
8
#of the License, or (at your option) any later version.
 
9
#
 
10
#This program is distributed in the hope that it will be useful,
 
11
#but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
#GNU General Public License for more details.
 
14
#
 
15
#You should have received a copy of the GNU General Public License
 
16
#along with this program; if not, write to the Free Software
 
17
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
18
#
 
19
 
 
20
#TODO
 
21
#Split drawing stuff
 
22
#Implement mousewheel to display hidden files
 
23
 
 
24
import screenlets
 
25
from screenlets.options import StringOption, FontOption, BoolOption, IntOption, ColorOption, DirectoryOption
 
26
from screenlets.utils import xdg_open
 
27
import cairo
 
28
import gtk
 
29
import pango
 
30
 
 
31
import os
 
32
import gobject, glib
 
33
 
 
34
try:
 
35
        import gio
 
36
except:
 
37
        screenlets.show_message(None,'You don\'t have GIO python bindings installed. \nYou need to install python-gobject >= 2.15 .')
 
38
        sys.exit()
 
39
 
 
40
log = screenlets.logger.get_default_logger()
 
41
 
 
42
class FolderViewCloneScreenlet(screenlets.Screenlet):
 
43
        
 
44
        # default meta-info for Screenlets
 
45
        __name__ = 'FolderViewClone'
 
46
        __version__ = '0.2'
 
47
        __author__ = 'Julien Lavergne'
 
48
        __desc__ = 'Display the content of a folder'
 
49
 
 
50
        # internals
 
51
        __timeout = None
 
52
 
 
53
        # editable options and defaults
 
54
        __update_interval = 1 # every second
 
55
 
 
56
        # constructor
 
57
        def __init__(self, **keyword_args):
 
58
                # call super
 
59
                screenlets.Screenlet.__init__(self, width=400, height=200, **keyword_args)
 
60
                self.x = self.width
 
61
                self.y = self.height
 
62
                # set theme
 
63
                self.theme_name = "default"
 
64
 
 
65
                #Init the theme to search for icons and default style
 
66
                self.theme = gtk.icon_theme_get_default()
 
67
 
 
68
                #Default Options
 
69
 
 
70
                self.icon_size_default = 48
 
71
                self.icon_size = self.icon_size_default
 
72
                self.icon_in_row_default = 4
 
73
                self.icon_in_column_default = 2
 
74
 
 
75
                self.icons_in_row = 4
 
76
                self.icons_in_column = 2
 
77
 
 
78
                self.files_list_show = []
 
79
 
 
80
 
 
81
                self.folder_path = os.path.join(os.path.expanduser("~"))
 
82
                self.folder_path_current = self.folder_path
 
83
                self.files_list = self.populate_list(self.folder_path_current)
 
84
                self.monitor = self.monitor_path(self.folder_path_current)
 
85
 
 
86
                self.font_default = "FreeSans"
 
87
                self.banner_size_default = 40
 
88
 
 
89
                self.border_size_default = 2
 
90
                self.border_size_selected = 2
 
91
 
 
92
                self.cursor_position = [-1,-1]
 
93
 
 
94
                self.auto_update = False
 
95
 
 
96
                # add default menu items
 
97
                self.add_menuitem("up_folder", "Up")
 
98
                self.add_default_menuitems()
 
99
 
 
100
                #add custom option
 
101
                self.add_options_group('Folder', 'Settings for the folder ...')
 
102
 
 
103
 
 
104
                self.add_option(IntOption('Folder','icon_size',
 
105
                                                self.icon_size_default, 'Icons Size','',
 
106
                                                callback=self.update, always_trigger_callback=False))
 
107
 
 
108
                self.add_option(IntOption('Folder','icons_in_row',
 
109
                                                self.icon_in_row_default, 'Icons in a row','Number of icons in a row',
 
110
                                                callback=self.update_path, always_trigger_callback=False))
 
111
 
 
112
                self.add_option(IntOption('Folder','icons_in_column',
 
113
                                                self.icon_in_column_default, 'Icons in a column','Number of icons in a column',
 
114
                                                callback=self.update_path, always_trigger_callback=False))
 
115
 
 
116
                self.add_option(IntOption('Folder','banner_size',
 
117
                                                self.banner_size_default, 'Size of the Banner','',
 
118
                                                callback=self.update, always_trigger_callback=False))
 
119
 
 
120
                self.add_option(DirectoryOption('Folder', 'Path',
 
121
                                        self.folder_path, 'Path', 'Default path to the folder',
 
122
                                        callback=self.update_path_from_settings,
 
123
                                        always_trigger_callback=False),realtime=False)
 
124
 
 
125
 
 
126
                self.add_options_group('Look', 'Settings colors and fonts')
 
127
 
 
128
                self.add_option(ColorOption('Look','color_text', 
 
129
                                                (0, 0, 0, 0.6), 'Text color', '',callback=self.update))
 
130
 
 
131
                self.add_option(ColorOption('Look','frame_color', 
 
132
                                                (1,1,1,0.8), 'Background Frame color', 'Frame color',callback=self.update))
 
133
 
 
134
                self.add_option(FontOption('Look','font', 
 
135
                                                self.font_default, 'Text Font', '',callback=self.update))
 
136
 
 
137
                self.add_option(IntOption('Look','border_size',
 
138
                                                self.border_size_default, 'Size of the border','',
 
139
                                                callback=self.update, always_trigger_callback=False))
 
140
 
 
141
 
 
142
                self.add_option(ColorOption('Look','color_text_selected', 
 
143
                                                (0, 0, 0, 0.6), 'Text color selected', 'Color of the text when selected', callback=self.update))
 
144
 
 
145
                self.add_option(ColorOption('Look','frame_color_selected', 
 
146
                                                (1,1,1,0.8), 'Background Frame color', 'Frame color for selected background', callback=self.update))
 
147
 
 
148
                self.add_option(IntOption('Look','border_size_selected',
 
149
                                                self.border_size_selected, 'Size of the border selected','',
 
150
                                                callback=self.update, always_trigger_callback=False))
 
151
 
 
152
                self.update_path()
 
153
 
 
154
        def __setattr__(self, name, value):
 
155
                # call Screenlet.__setattr__ in baseclass (ESSENTIAL!!!!)
 
156
                screenlets.Screenlet.__setattr__(self, name, value)
 
157
 
 
158
 
 
159
        def get_style_color(self):
 
160
                '''     Get default color for background
 
161
                        #TODO Use this
 
162
                '''
 
163
                style = gtk.Style().bg[gtk.STATE_NORMAL]
 
164
                return style
 
165
 
 
166
        def populate_list(self, path):
 
167
                '''     Generate the list of GFile and GFileInfos
 
168
                '''             
 
169
                parent = gio.File(path)
 
170
                list_files = [] #List of tuble of 3
 
171
                self.files_list_show = []
 
172
 
 
173
                for elem in os.listdir(path):
 
174
                        Gfile = gio.File(os.path.join(path,elem))
 
175
                        tuble = [Gfile, Gfile.query_info("standard::*"), []]
 
176
                        if not tuble[1].get_is_hidden():
 
177
                                list_files.append(tuble)
 
178
                        tuble = False
 
179
                        Gfile = False
 
180
                parent = False
 
181
 
 
182
                self.x_position = int(0)
 
183
                self.y_position = int(0)
 
184
 
 
185
                for elem in list_files:
 
186
                        #Update the position of the file
 
187
                        elem[2] = [self.x_position, self.y_position]
 
188
 
 
189
                        if self.x_position == self.icons_in_row:# If we are at the end of the row, 
 
190
                                                                # jump to the next row
 
191
 
 
192
                                self.x_position = int(0)
 
193
                                self.y_position = int(self.y_position) + 1
 
194
 
 
195
                        else: 
 
196
                                self.x_position = int(self.x_position) + 1
 
197
 
 
198
                for elem in list_files:
 
199
                        if elem[2][0] < self.icons_in_row:
 
200
                                if elem[2][1] < self.icons_in_column:
 
201
                                                self.files_list_show.append(elem)
 
202
        
 
203
 
 
204
        def generate_icon_names(self, tuble):
 
205
                '''     Generate a list of icons names from a [GFile, GFileInfo, [x,y]]
 
206
                '''
 
207
                info = tuble[1]
 
208
                Gicon = info.get_icon()
 
209
                self.icon_names = Gicon.get_names()
 
210
                if self.check_for_icon(self.icon_names[0]):
 
211
                        return self.icon_names
 
212
                else:
 
213
                        return ['gtk-execute']
 
214
        
 
215
 
 
216
        def generate_file_name(self, tuble):
 
217
                '''     Generate the name of a file from a (GFile, GFileInfo)
 
218
                '''
 
219
                info = tuble[1]
 
220
                info = info.get_name()
 
221
                return info
 
222
 
 
223
        def monitor_path(self, path):
 
224
                '''     Monitor the path for modified files/directory
 
225
                '''     
 
226
                current_file = gio.File(self.folder_path_current)
 
227
                mon = current_file.monitor_directory()
 
228
                mon.connect("changed", self.monitor_callback)
 
229
                return mon
 
230
 
 
231
        def monitor_callback(self, monitor, Gfile, event, data=None):
 
232
                self.update_path()
 
233
                #self.show_notification("Changes !")
 
234
 
 
235
 
 
236
        def click_callback(self):
 
237
                '''     Callback when click
 
238
                '''
 
239
                
 
240
                for elem in self.files_list_show:
 
241
                        if elem[2] == self.cursor_position:
 
242
                                if os.path.isdir(elem[0].get_path()):
 
243
                                        self.folder_path_current = elem[0].get_path()
 
244
                                        self.update_path()
 
245
                                else: xdg_open(elem[0].get_path())
 
246
 
 
247
        def set_path_to_parent(self):
 
248
                if self.folder_path_current is not bool:
 
249
                        self.folder_path_current = os.path.split(self.folder_path_current)[0]
 
250
                        self.update_path()
 
251
 
 
252
        def menuitem_callback(self, widget, id):
 
253
                screenlets.Screenlet.menuitem_callback(self, widget, id)
 
254
                if id == "up_folder":
 
255
                        self.set_path_to_parent()
 
256
 
 
257
 
 
258
        def on_mouse_down(self, event):
 
259
                """Called when a buttonpress-event occured in Screenlet's window. 
 
260
                Returning True causes the event to be not further propagated."""
 
261
                self.set_current_cursor(event) 
 
262
                self.click_callback()
 
263
 
 
264
                return False
 
265
 
 
266
        def set_current_cursor(self, event):
 
267
                self.cursor_position= [int(event.x / self.scale), int(event.y / self.scale)]
 
268
                if self.cursor_position[1] < self.banner_size:
 
269
                        self.cursor_position = [-1,-1]
 
270
                else:
 
271
                        self.cursor_position = [int(self.cursor_position[0]) / int(self.icon_size * 2), 
 
272
                                int(self.cursor_position[1]) / int(self.banner_size + int(self.icon_size*2))]
 
273
 
 
274
        def update_path_from_settings(self):
 
275
                self.folder_path_current = self.Path
 
276
                self.monitor = self.monitor_path(self.folder_path_current)
 
277
                self.update_path()
 
278
 
 
279
 
 
280
        def update_path(self):
 
281
                ''' Update path from settings
 
282
                '''
 
283
                if self.folder_path_current is not bool:
 
284
                        self.populate_list(self.folder_path_current)
 
285
                        self.monitor = self.monitor_path(self.folder_path_current)              
 
286
                self.update()
 
287
 
 
288
 
 
289
        def update(self):
 
290
                
 
291
                self.redraw_canvas()
 
292
                self.update_shape()
 
293
                return True # keep on running this event
 
294
 
 
295
        def on_mouse_enter (self, event):
 
296
                self.redraw_canvas()
 
297
                pass
 
298
 
 
299
        def on_mouse_leave (self, event):
 
300
                """Called when the mouse leaves the Screenlet's window."""
 
301
                self.cursor_position = [-1,-1]
 
302
                self.redraw_canvas()
 
303
 
 
304
        def on_mouse_move(self, event):
 
305
                """Called when the mouse moves in the Screenlet's window."""
 
306
                before_cursor = self.cursor_position
 
307
                self.set_current_cursor(event)
 
308
                if before_cursor <> self.cursor_position:
 
309
                        self.update()
 
310
 
 
311
        def get_large(self, situation):
 
312
                return situation[2][0] * self.icon_size * 2
 
313
 
 
314
        def get_long(self,situation):
 
315
                return situation[2][1] * self.icon_size * 2 + self.banner_size
 
316
 
 
317
 
 
318
        def on_draw(self, ctx):
 
319
                self.width = self.icon_size * 2 * self.icons_in_row
 
320
                self.height = self.icon_size * 2 * self.icons_in_column + self.banner_size
 
321
 
 
322
                ctx.scale(self.scale, self.scale)
 
323
                
 
324
                #Draw the banner
 
325
                ctx.set_source_rgba(*self.frame_color)
 
326
                self.draw_rectangle_advanced (ctx, 0, 0, self.width-10, self.banner_size,
 
327
                        rounded_angles=(5,5,5,5), fill=True, border_size=2, border_color=(0,0,0,0.5),
 
328
                        shadow_size=0, shadow_color=(0,0,0,0.5))
 
329
 
 
330
                ctx.set_source_rgba(*self.color_text)
 
331
                self.draw_text(ctx, self.folder_path_current,                   # ctx, texte
 
332
                        10,                     # x
 
333
                        5,                      # y
 
334
                        self.font.split(' ')[0],                                # font
 
335
                        self.banner_size * 0.3 , self.width-10 ,                # size, width
 
336
                        alignment=pango.ALIGN_CENTER, ellipsize=pango.ELLIPSIZE_END)
 
337
 
 
338
                #Draw the main widget
 
339
                ctx.set_source_rgba(*self.frame_color)
 
340
                self.draw_rectangle_advanced (ctx, 0, self.banner_size, self.width-10, self.height-self.banner_size-10,
 
341
                        rounded_angles=(5,5,5,5), fill=True, border_size=self.border_size, border_color=(0,0,0,0.5),
 
342
                        shadow_size=0, shadow_color=(0,0,0,0.5))
 
343
                
 
344
                self.large_init = 0
 
345
                self.longue_init = self.banner_size     
 
346
 
 
347
                
 
348
                self.large = self.large_init
 
349
                self.longue = self.longue_init
 
350
 
 
351
                for elem in self.files_list_show:
 
352
                        #Draw the selected rextancle
 
353
                        if elem[2] == self.cursor_position:
 
354
                                ctx.set_source_rgba(*self.frame_color_selected)
 
355
                                self.draw_rectangle_advanced(ctx,                       # ctx
 
356
                                        self.get_large(elem) ,          # x
 
357
                                        self.get_long(elem),            # y
 
358
                                        self.icon_size * 1.8, self.icon_size * 1.8,             # width, height
 
359
                                        rounded_angles=(5,5,5,5), fill=True,
 
360
                                        border_size=self.border_size_selected, border_color=(0,0,0,0.5))
 
361
                        
 
362
                        #Draw the icon
 
363
                        ctx.set_source_rgba(*self.frame_color)
 
364
                        self.draw_icon(ctx,                                             # ctx
 
365
                                self.get_large(elem) + self.icon_size * 0.5 ,   # x
 
366
                                self.get_long(elem) + self.icon_size * 0.2,             # y
 
367
                                self.generate_icon_names(elem)[0],                      # icon name
 
368
                                self.icon_size, self.icon_size)                         # width, height
 
369
 
 
370
                        #Draw the text
 
371
                        ctx.set_source_rgba(*self.color_text)
 
372
                        self.draw_text(ctx, self.generate_file_name(elem),              # ctx, texte
 
373
                                self.get_large(elem),                   # x
 
374
                                self.get_long(elem) + self.icon_size * 1.2,                     # y
 
375
                                self.font.split(' ')[0],                                # font
 
376
                                self.icon_size * 0.18, self.icon_size * 1.8 ,           # size, width
 
377
                                alignment=pango.ALIGN_CENTER, ellipsize=pango.ELLIPSIZE_END)
 
378
 
 
379
        
 
380
 
 
381
        def on_draw_shape(self, ctx):
 
382
                self.on_draw(ctx)
 
383
 
 
384
        
 
385
# If the program is run directly or passed as an argument to the python
 
386
# interpreter then create a Screenlet instance and show it
 
387
if __name__ == "__main__":
 
388
        import screenlets.session
 
389
        screenlets.session.create_session(FolderViewCloneScreenlet)