root/pida/services/filemanager/filemanager.py @ 1173:adcacc565816

Revision 1173:adcacc565816, 29.0 KB (checked in by Tobias Eberle <info@…>, 2 years ago)

contexts: added menu as parameter to show-menu/menu-deactivated events

Line 
1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2007-2008 The PIDA Project
4
5#Permission is hereby granted, free of charge, to any person obtaining a copy
6#of this software and associated documentation files (the "Software"), to deal
7#in the Software without restriction, including without limitation the rights
8#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9#copies of the Software, and to permit persons to whom the Software is
10#furnished to do so, subject to the following conditions:
11
12#The above copyright notice and this permission notice shall be included in
13#all copies or substantial portions of the Software.
14
15#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21#SOFTWARE.
22
23
24from weakref import proxy
25import gtk
26
27from os import listdir, path
28
29import os
30import shutil
31
32import cgi
33
34import re
35
36# PIDA Imports
37from pida.core.service import Service
38from pida.core.features import FeaturesConfig
39from pida.core.commands import CommandsConfig
40from pida.core.events import EventsConfig
41from pida.core.actions import ActionsConfig
42from pida.core.actions import TYPE_NORMAL, TYPE_MENUTOOL, TYPE_DROPDOWNMENUTOOL, TYPE_RADIO, TYPE_TOGGLE
43from pida.core.options import OptionsConfig, OTypeBoolean, OTypeString, OTypeStringList
44from pida.core.environment import get_uidef_path
45
46from pida.utils.gthreads import GeneratorTask, AsyncTask
47
48from pida.ui.views import PidaView
49from pida.ui.objectlist import AttrSortCombo
50from pida.ui.dropdownmenutoolbutton import DropDownMenuToolButton
51from kiwi.ui.objectlist import Column, ColoredColumn, ObjectList
52
53from filehiddencheck import *
54
55
56# locale
57from pida.core.locale import Locale
58locale = Locale('filemanager')
59_ = locale.gettext
60
61
62state_text = dict(
63        hidden=' ',
64        none='?',
65        new='A',
66        modified='M',
67        ignored=' ',
68        normal=' ',
69        error='E',
70        empty='!',
71        conflict='C',
72        removed='D',
73        missing='!',
74        max='+',
75        external='>',
76        )
77
78state_style = dict( # tuples of (color, is_bold, is_italic)
79        hidden=('lightgrey', False, True),
80        ignored=('lightgrey', False, True),
81        #TODO: better handling of normal directories
82        none=('#888888', False, True), 
83        normal=('black', False, False),
84        error=('darkred', True, True),
85        empty=('black', False, True),
86        modified=('darkred', True, False),
87        conflict=('darkred', True, True),
88        removed=('#c06060', True, True),
89        missing=('#00c0c0', True, False),
90        new=('blue', True, False),
91        max=('#c0c000', False, False),
92        external=('#333333', False, True),
93        )
94
95
96class FileEntry(object):
97    """The model for file entries"""
98
99    def __init__(self, name, parent_path, manager):
100        self._manager = manager
101        self.state = 'normal'
102        self.name = name
103        self.lower_name = self.name.lower()
104        self.parent_path = parent_path
105        self.path = os.path.join(parent_path, name)
106        self.extension = os.path.splitext(self.name)[-1]
107        self.extension_sort = self.extension, self.lower_name
108        self.is_dir = os.path.isdir(self.path)
109        self.is_dir_sort = not self.is_dir, self.lower_name
110        self.visible = False
111
112    @property
113    def markup(self):
114        return self.format(cgi.escape(self.name))
115
116    @property
117    def icon_stock_id(self):
118        if path.isdir(self.path):
119            return 'stock_folder'
120        else:
121            #TODO: get a real mimetype icon
122            return 'text-x-generic'
123
124    @property
125    def state_markup(self):
126        text = state_text.get(self.state, ' ')
127        wrap = '<span weight="ultrabold"><tt>%s</tt></span>'
128        return wrap%self.format(text)
129
130
131    def format(self, text):
132        color, b, i = state_style.get(self.state, ('black', False, False))
133        if b:
134            text = '<b>%s</b>' % text
135        if i:
136            text = '<i>%s</i>' % text
137        return '<span color="%s">%s</span>' % (color, text)
138
139
140class FilemanagerView(PidaView):
141
142    _columns = [
143        Column("icon_stock_id", use_stock=True),
144        Column("state_markup", use_markup=True),
145        Column("markup", use_markup=True),
146        Column("lower_name", visible=False, searchable=True),
147        ]
148
149    label_text = _('Files')
150    icon_name = 'file-manager'
151
152    def create_ui(self):
153        self._vbox = gtk.VBox()
154        self._vbox.show()
155        self.create_toolbar()
156        self._file_hidden_check_actions = {}
157        self._create_file_hidden_check_toolbar()
158        self.create_file_list()
159        self._clipboard_file = None
160        self._fix_paste_sensitivity()
161        self.add_main_widget(self._vbox)
162
163    def create_file_list(self):
164        self.file_list = ObjectList()
165        self.file_list.set_headers_visible(False)
166        self.file_list.set_columns(self._columns);
167        self.file_list.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
168        #XXX: real file
169        self.file_list.get_treeview().connect('button-press-event',
170            self.on_file_button_press_event)
171        self.file_list.connect('selection-changed', self.on_selection_changed)
172        self.file_list.connect('row-activated', self.on_file_activated)
173        self.file_list.connect('right-click', self.on_file_right_click)
174        self.entries = {}
175        self.update_to_path(self.svc.path)
176        self.file_list.show()
177        self._vbox.pack_start(self.file_list)
178        self._sort_combo = AttrSortCombo(self.file_list,
179            [
180                ('is_dir_sort', _('Directories First')),
181                ('lower_name', _('File Name')),
182                ('name', _('Case Sensitive File Name')),
183                ('path', _('File Path')),
184                ('extension_sort', _('Extension')),
185                ('state', _('Version Control Status')),
186            ],
187            'is_dir_sort')
188        self._sort_combo.show()
189        self._vbox.pack_start(self._sort_combo, expand=False)
190        self.on_selection_changed(self.file_list, None)
191
192    def create_toolbar(self):
193        self._uim = gtk.UIManager()
194        self._uim.insert_action_group(self.svc.get_action_group(), 0)
195        self._uim.add_ui_from_file(get_uidef_path('filemanager-toolbar.xml'))
196        self._uim.ensure_update()
197        self._toolbar = self._uim.get_toplevels('toolbar')[0]
198        self._toolbar.set_style(gtk.TOOLBAR_ICONS)
199        self._toolbar.set_icon_size(gtk.ICON_SIZE_MENU)
200        self._vbox.pack_start(self._toolbar, expand=False)
201        self._toolbar.show_all()
202
203    def add_or_update_file(self, name, basepath, state):
204        if basepath != self.path:
205            return
206        entry = self.entries.setdefault(name, FileEntry(name, basepath, self))
207        entry.state = state
208
209        self.show_or_hide(entry)
210
211    def show_or_hide(self, entry):
212        from operator import and_
213        def check(checker):
214            check = checker(self.svc.boss)
215            if (check.identifier in self._file_hidden_check_actions) and \
216               (self._file_hidden_check_actions[check.identifier].get_active()):
217                return check(name=entry.name, path=entry.parent_path,
218                    state=entry.state, )
219            else:
220                return True
221
222        if self.svc.opt('show_hidden'):
223            show = True
224        else:
225            show = all(check(x)
226                        for x in self.svc.features['file_hidden_check'])
227
228        if show:
229            if entry.visible:
230                self.file_list.update(entry)
231            else:
232                self.file_list.append(entry)
233                entry.visible = True
234        else:
235            if entry.visible:
236                self.file_list.remove(entry)
237                entry.visible = False
238
239    def update_to_path(self, new_path=None):
240        if new_path is None:
241            new_path = self.path
242        else:
243            self.path = new_path
244
245        self.file_list.clear()
246        self.entries.clear()
247
248        def work(basepath):
249            dir_content = listdir(basepath)
250            # add all files from vcs and remove the corresponding items
251            # from dir_content
252            for item in self.svc.boss.cmd('versioncontrol', 'list_file_states',
253              path=self.path):
254                if (item[1] == self.path):
255                    try:
256                        dir_content.remove(item[0])
257                    except:
258                        pass
259                    yield item
260            # handle remaining files
261            for filename in dir_content:
262                if (path.isdir(path.join(basepath, filename))):
263                    state = 'normal'
264                else:
265                    state = 'unknown'
266                yield filename, basepath, state
267
268        GeneratorTask(work, self.add_or_update_file).start(self.path)
269
270        self.create_ancest_tree()
271
272    # This is painful, and will always break
273    # So use the following method instead
274    def update_single_file(self, name, basepath):
275        def _update_file(oname, obasepath, state):
276            if oname == name and basepath == obasepath:
277                if name not in self.entries:
278                    self.entries[oname] = FileEntry(oname, obasepath, self)
279                self.entries[oname].state = state
280                self.show_or_hide(self.entries[oname])
281        for lister in self.svc.features['file_lister']:
282            GeneratorTask(lister, _update_file).start(self.path)
283
284    def update_single_file(self, name, basepath):
285        if basepath != self.path:
286            return
287        if name not in self.entries:
288            self.entries[name] = FileEntry(name, basepath, self)
289            self.show_or_hide(self.entries[name])
290
291    def update_removed_file(self, filename):
292        entry = self.entries.pop(filename, None)
293        if entry is not None and entry.visible:
294            self.file_list.remove(entry)
295
296    def on_file_button_press_event(self, file_list, event):
297        # unselect all rows if user clicked on the empty space below the last
298        # row
299        if (file_list.get_path_at_pos(int(event.x), int(event.y)) is None):
300            file_list.get_selection().unselect_all()
301            if (event.button == 3):
302                # right click on base directory
303                item = FileEntry(os.path.basename(self.path),
304                    os.path.dirname(self.path), self)
305                self.on_file_right_click(file_list, item, event)
306            return True
307        else:
308            return False
309
310    def on_file_activated(self, rowitem, fileentry):
311        if os.path.exists(fileentry.path):
312            if fileentry.is_dir:
313                self.svc.browse(fileentry.path)
314            else:
315                self.svc.boss.cmd('buffer', 'open_file', file_name=fileentry.path)
316        else:
317            self.update_removed_file(fileentry.name)
318
319    def on_file_right_click(self, ol, item, event=None):
320        if item.is_dir:
321            self.svc.boss.cmd('contexts', 'popup_menu', context='dir-menu',
322                          dir_name=item.path, event=event, filemanager=True) 
323        else:
324            self.svc.boss.cmd('contexts', 'popup_menu', context='file-menu',
325                          file_name=item.path, event=event, filemanager=True)
326
327    def on_selection_changed(self, ol, item):
328        for act_name in ['toolbar_copy', 'toolbar_delete']:
329            self.svc.get_action(act_name).set_sensitive(item is not None)
330
331    def rename_file(self, old, new, entry):
332        print 'renaming', old, 'to' ,new
333
334    def create_ancest_tree(self):
335        task = AsyncTask(self._get_ancestors, self._show_ancestors)
336        task.start(self.path)
337
338    def _on_act_up_ancestor(self, action, directory):
339        self.svc.browse(directory)
340
341    def _show_ancestors(self, ancs):
342        toolitem = self.svc.get_action('toolbar_up').get_proxies()[0]
343        menu = gtk.Menu()
344        for anc in ancs:
345            action = gtk.Action(anc, anc, anc, 'directory')
346            action.connect('activate', self._on_act_up_ancestor, anc)
347            menuitem = action.create_menu_item()
348            menu.add(menuitem)
349        menu.show_all()
350        toolitem.set_menu(menu)
351
352    def _get_ancestors(self, directory):
353        ancs = [directory]
354        while directory != '/':
355            parent = os.path.dirname(directory)
356            ancs.append(parent)
357            directory = parent
358        return ancs
359
360    def _on_act_file_hidden_check(self, action, check):
361        if (check.scope == SCOPE_GLOBAL):
362            # global
363            active_checker = self.svc.opt('file_hidden_check')
364            if (action.get_active()):
365                active_checker.append(check.identifier)
366            else:
367                active_checker.remove(check.identifier)
368            self.svc.set_opt('file_hidden_check', active_checker)
369        else:
370            # project
371            if (self.svc.current_project is not None):
372                section = self.svc.current_project.get_section('file_hidden_check')
373                if (section is None):
374                    section = {}
375                section[check.identifier] = action.get_active()
376                self.svc.current_project.save_section('file_hidden_check',
377                  section)
378        self.update_to_path()
379   
380    def __file_hidden_check_scope_project_set_active(self, action):
381        """sets active state of a file hidden check action with
382           scope = project
383           relies on action name = identifier of checker"""
384        if (self.svc.current_project is not None):
385            section = self.svc.current_project.get_section('file_hidden_check')
386            action.set_active(
387              (section is not None) and
388              (action.get_name() in section) and
389              (section[action.get_name()] == 'True'))
390        else:
391            action.set_active(False)
392       
393   
394    def refresh_file_hidden_check(self):
395        """refreshes active status of actions of project scope checker"""
396        for checker in self.svc.features['file_hidden_check']:
397            check = checker(self.svc.boss)
398            if (check.scope == SCOPE_PROJECT):
399                action = self._file_hidden_check_actions[check.identifier]
400                self.__file_hidden_check_scope_project_set_active(action)
401   
402    def _create_file_hidden_check_toolbar(self):
403        self._file_hidden_check_actions = {}
404        menu = gtk.Menu()
405        separator = gtk.SeparatorMenuItem()
406        project_scope_count = 0
407        menu.append(separator)
408        for checker in self.svc.features['file_hidden_check']:
409            check = checker(self.svc.boss)
410            action = gtk.ToggleAction(check.identifier, check.label,
411              check.label, None)
412            # active?
413            if (check.scope == SCOPE_GLOBAL):
414                action.set_active(
415                    check.identifier in self.svc.opt('file_hidden_check'))
416            else:
417                self.__file_hidden_check_scope_project_set_active(action)
418
419            action.connect('activate', self._on_act_file_hidden_check, check)
420            self._file_hidden_check_actions[check.identifier] = action
421            menuitem = action.create_menu_item()
422            if (check.scope == SCOPE_GLOBAL):
423                menu.prepend(menuitem)
424            else:
425                menu.append(menuitem)
426                project_scope_count += 1
427        menu.show_all()
428        if (project_scope_count == 0):
429            separator.hide()
430        toolitem = None
431        for proxy in self.svc.get_action('toolbar_hidden_menu').get_proxies():
432            if (isinstance(proxy, DropDownMenuToolButton)):
433                toolitem = proxy
434                break
435        if (toolitem is not None):
436            toolitem.set_menu(menu)
437
438    def get_selected_filename(self):
439        fileentry = self.file_list.get_selected()
440        if fileentry is not None:
441            return fileentry.path
442
443    def copy_clipboard(self):
444        current = self.get_selected_filename()
445        if os.path.exists(current):
446            self._clipboard_file = current
447        else:
448            self._clipboard_file = None
449        self._fix_paste_sensitivity()
450
451    def _fix_paste_sensitivity(self):
452        self.svc.get_action('toolbar_paste').set_sensitive(self._clipboard_file
453                                                           is not None)
454
455    def paste_clipboard(self):
456        task = AsyncTask(self._paste_clipboard, lambda: None)
457        task.start()
458
459    def _paste_clipboard(self):
460        newname = os.path.join(self.path, os.path.basename(self._clipboard_file))
461        if newname == self._clipboard_file:
462            self.svc.error_dlg(_('Cannot copy files to themselves.'))
463            return
464        if not os.path.exists(self._clipboard_file):
465            self.svc.error_dlg(_('Source file has vanished.'))
466        if os.path.exists(newname):
467            self.svc.error_dlg(_('Destination already exists.'))
468            return
469        if os.path.isdir(self._clipboard_file):
470            shutil.copytree(self._clipboard_file, newname)
471        else:
472            shutil.copy2(self._clipboard_file, newname)
473
474    def remove_path(self, path):
475        task = AsyncTask(self._remove_path, lambda: None)
476        task.start(path)
477
478    def _remove_path(self, path):
479        if os.path.isdir(path):
480            shutil.rmtree(path)
481        else:
482            os.remove(path)
483        if path == self._clipboard_file:
484            self._clipboard_file = None
485            self._fix_paste_sensitivity()
486
487class DotFilesFileHiddenCheck(FileHiddenCheck):
488    _identifier = "DotFiles"
489    _label = "Hide Dot-Files"
490    _scope = SCOPE_GLOBAL
491   
492    def __call__(self, name, path, state):
493        return name[0] != '.'
494
495class RegExFileHiddenCheck(FileHiddenCheck):
496    _identifier = "RegEx"
497    _label = "Hide by User defined Regular Expression"
498    _scope = SCOPE_GLOBAL
499   
500    def __call__(self, name, path, state):
501        _re = self.boss.get_service('filemanager').opt('hide_regex')
502        if not re:
503            return True
504        else:
505            return re.match(_re, name) is None
506
507class FilemanagerEvents(EventsConfig):
508
509    def create(self):
510        self.publish(
511                'browsed_path_changed',
512                'file_renamed')
513       
514        self.subscribe('file_renamed', self.svc.rename_file)
515
516    def subscribe_all_foreign(self):
517        self.subscribe_foreign('project', 'project_switched',
518                                     self.svc.on_project_switched)
519        self.subscribe_foreign('plugins', 'plugin_started',
520            self.on_plugin_started)
521        self.subscribe_foreign('plugins', 'plugin_stopped',
522            self.on_plugin_stopped);
523        self.subscribe_foreign('contexts', 'show-menu',
524            self.on_contexts__show_menu)
525        self.subscribe_foreign('contexts', 'menu-deactivated',
526            self.on_contexts__menu_deactivated)
527
528    def on_plugin_started(self, plugin):
529        if (plugin.features.has_foreign('filemanager', 'file_hidden_check')):
530            self.svc.refresh_file_hidden_check_menu()
531   
532    def on_plugin_stopped(self, plugin):
533        self.svc.refresh_file_hidden_check_menu()
534
535    def on_contexts__show_menu(self, menu, context, **kw):       
536        if (kw.has_key('filemanager')):
537            if (context == 'file-menu'):
538                self.svc.get_action('delete-file').set_visible(True)
539            else:
540                self.svc.get_action('delete-dir').set_visible(
541                    kw['dir_name'] != self.svc.get_view().path)
542        else:
543            self.svc.get_action('delete-file').set_visible(False)
544            self.svc.get_action('delete-dir').set_visible(False)
545
546    def on_contexts__menu_deactivated(self, menu, context, **kw):
547        if (kw.has_key('filemanager')):
548            if (context == 'file-menu'):
549                self.svc.get_action('delete-file').set_visible(False)
550            else:
551                self.svc.get_action('delete-dir').set_visible(False)
552
553
554class FilemanagerCommandsConfig(CommandsConfig):
555    def browse(self, new_path):
556        self.svc.browse(new_path)
557
558    def get_browsed_path(self):
559        return self.svc.path
560
561    def get_view(self):
562        return self.svc.get_view()
563
564    def present_view(self):
565        return self.svc.boss.cmd('window', 'present_view',
566            view=self.svc.get_view())
567
568    def update_file(self, filename, dirname):
569        if dirname == self.svc.get_view().path:
570            self.svc.get_view().update_single_file(filename, dirname)
571
572    def update_removed_file(self, filename, dirname):
573        if dirname == self.svc.get_view().path:
574            self.svc.get_view().update_removed_file(filename)
575
576    def refresh(self):
577        self.svc.get_view().update_to_path()
578
579
580class FilemanagerFeatureConfig(FeaturesConfig):
581
582    def create(self):
583        self.publish('file_manager')
584        self.publish('file_hidden_check')
585        self.subscribe('file_hidden_check', DotFilesFileHiddenCheck)
586        self.subscribe('file_hidden_check', RegExFileHiddenCheck)
587
588    def subscribe_all_foreign(self):
589        self.subscribe_foreign('contexts', 'file-menu',
590            (self.svc.get_action_group(), 'filemanager-file-menu.xml'))
591        self.subscribe_foreign('contexts', 'dir-menu',
592            (self.svc.get_action_group(), 'filemanager-dir-menu.xml'))
593
594
595
596class FileManagerOptionsConfig(OptionsConfig):
597    def create_options(self):
598        self.create_option(
599                'show_hidden',
600                _('Show hidden files'),
601                OTypeBoolean,
602                True,
603                _('Shows hidden files'))
604        self.create_option(
605                'file_hidden_check',
606                _('Used file hidden checker'),
607                OTypeStringList,
608                [],
609                _('The used file hidden checker'))
610       
611        self.create_option(
612                'last_browsed_remember',
613                _('Remember last Path'),
614                OTypeBoolean,
615                True,
616                _('Remembers the last browsed path'))
617       
618        self.create_option(
619                'last_browsed',
620                _('Last browsed Path'),
621                OTypeString,
622                path.expanduser('~'),
623                _('The last browsed path'))
624       
625        self.create_option(
626                'hide_regex',
627                _('Hide regex'),
628                OTypeString,
629                '^\.|.*~|.*\.py[co]$',
630                _('Hides files that match the regex'))
631
632class FileManagerActionsConfig(ActionsConfig):
633
634    def create_actions(self):
635        self.create_action(
636            'delete-file',
637            TYPE_NORMAL,
638            _('Delete File'),
639            _('Delete selected file'),
640            gtk.STOCK_DELETE,
641            self.on_delete
642        )
643       
644        self.create_action(
645            'browse-for-file',
646            TYPE_NORMAL,
647            _('Browse the file directory'),
648            _('Browse the parent directory of this file'),
649            'file-manager',
650            self.on_browse_for_file,
651        )
652       
653        self.create_action(
654            'delete-dir',
655            TYPE_NORMAL,
656            _('Delete Directory'),
657            _('Delete selected directory'),
658            gtk.STOCK_DELETE,
659            self.on_delete
660        )
661
662        self.create_action(
663            'browse-for-dir',
664            TYPE_NORMAL,
665            _('Browse the directory'),
666            _('Browse the directory'),
667            'file-manager',
668            self.on_browse_for_dir,
669        )
670
671        self.create_action(
672            'show_filebrowser',
673            TYPE_NORMAL,
674            _('Show file browser'),
675            _('Show the file browser view'),
676            'file-manager',
677            self.on_show_filebrowser,
678            '<Shift><Control>f'
679        )
680
681        self.create_action(
682            'toolbar_up',
683            TYPE_MENUTOOL,
684            _('Go Up'),
685            _('Go to the parent directory'),
686            gtk.STOCK_GO_UP,
687            self.on_toolbar_up,
688            '<Shift><Control>Up',
689        )
690
691        self.create_action(
692            'toolbar_terminal',
693            TYPE_NORMAL,
694            _('Open Terminal'),
695            _('Open a terminal in this directory'),
696            'terminal',
697            self.on_toolbar_terminal,
698        )
699
700        self.create_action(
701            'toolbar_refresh',
702            TYPE_NORMAL,
703            _('Refresh Directory'),
704            _('Refresh the current directory'),
705            gtk.STOCK_REFRESH,
706            self.on_toolbar_refresh,
707        )
708
709        self.create_action(
710            'toolbar_projectroot',
711            TYPE_NORMAL,
712            _('Project Root'),
713            _('Browse the root of the current project'),
714            'user-home',
715            self.on_toolbar_projectroot,
716        )
717
718        self.create_action(
719            'toolbar_copy',
720            TYPE_NORMAL,
721            _('Copy File'),
722            _('Copy selected file to the clipboard'),
723            gtk.STOCK_COPY,
724            self.on_toolbar_copy,
725        )
726
727        self.create_action(
728            'toolbar_paste',
729            TYPE_NORMAL,
730            _('Paste File'),
731            _('Paste selected file from the clipboard'),
732            gtk.STOCK_PASTE,
733            self.on_toolbar_paste,
734        )
735
736        self.create_action(
737            'toolbar_delete',
738            TYPE_NORMAL,
739            _('Delete File'),
740            _('Delete the selected file'),
741            gtk.STOCK_DELETE,
742            self.on_delete,
743        )
744        self.create_action(
745            'toolbar_toggle_hidden',
746            TYPE_TOGGLE,
747            _('Show Hidden Files'),
748            _('Show hidden files'),
749            gtk.STOCK_SELECT_ALL,
750            self.on_toggle_hidden,
751        )
752        self.create_action(
753            'toolbar_hidden_menu',
754            TYPE_DROPDOWNMENUTOOL,
755            '',
756            _('Setup which kind of files should be hidden'),
757            None,
758            None,
759        )
760
761
762    def on_browse_for_file(self, action):
763        new_path = path.dirname(action.contexts_kw['file_name'])
764        self.svc.cmd('browse', new_path=new_path)
765        self.svc.cmd('present_view')
766
767    def on_browse_for_dir(self, action):
768        new_path = action.contexts_kw['dir_name']
769        self.svc.cmd('browse', new_path=new_path)
770        self.svc.cmd('present_view')
771
772    def on_show_filebrowser(self, action):
773        self.svc.cmd('present_view')
774
775    def on_toolbar_up(self, action):
776        self.svc.go_up()
777
778    def on_toolbar_terminal(self, action):
779        self.svc.boss.cmd('commander','execute_shell', cwd=self.svc.path)
780
781    def _on_menu_down(self, menu, action):
782        action.set_active(False)
783        print "down"
784   
785    def on_toggle_hidden(self, action):
786        self.svc.set_opt('show_hidden', action.get_active())
787        self.on_toolbar_refresh(action)
788
789    def on_toolbar_refresh(self, action):
790        self.svc.get_view().update_to_path()
791
792    def on_toolbar_projectroot(self, action):
793        self.svc.browse(self.svc.current_project.source_directory)
794
795    def on_toolbar_copy(self, action):
796        self.svc.get_view().copy_clipboard()
797
798    def on_toolbar_paste(self, action):
799        self.svc.get_view().paste_clipboard()
800
801    def on_delete(self, action):
802        current = self.svc.get_view().get_selected_filename()
803        if current is not None:
804            if self.svc.yesno_dlg(
805                _('Are you sure you want to delete the selected file: %s?'
806                % current)
807            ):
808                self.svc.get_view().remove_path(current)
809
810                if not self.svc.boss.get_service('filewatcher').started:
811                    self.svc.get_view().update_to_path()
812
813
814
815# Service class
816class Filemanager(Service):
817    """the Filemanager service"""
818
819    options_config = FileManagerOptionsConfig
820    features_config = FilemanagerFeatureConfig
821    events_config = FilemanagerEvents
822    commands_config = FilemanagerCommandsConfig
823    actions_config = FileManagerActionsConfig
824
825    def pre_start(self):
826        self.path = self.opt('last_browsed')
827
828    def start(self):
829        self.file_view = FilemanagerView(self)
830        self.emit('browsed_path_changed', path=self.path)
831        self.on_project_switched(None)
832
833        self.get_action('toolbar_toggle_hidden').set_active(
834                self.opt('show_hidden'))
835
836    def get_view(self):
837        return self.file_view
838   
839    def browse(self, new_path):
840        new_path = path.abspath(new_path)
841        if new_path == self.path:
842            return
843        else:
844            self.path = new_path
845            self.set_opt('last_browsed', new_path)
846            self.file_view.update_to_path(new_path)
847        self.emit('browsed_path_changed', path=new_path)
848
849
850    def go_up(self):
851        dir = path.dirname(self.path)
852        if not dir:
853            dir = "/" #XXX: unportable, what about non-unix
854        self.browse(dir)
855
856    def rename_file(self, old, new, basepath):
857        pass
858
859    def refresh_file_hidden_check_menu(self):
860        self.get_view()._create_file_hidden_check_toolbar()
861   
862    def on_project_switched(self, project):
863        self.current_project = project
864        self.get_action('toolbar_projectroot').set_sensitive(project is not None)
865        self.get_view().refresh_file_hidden_check()
866
867
868
869# Required Service attribute for service loading
870Service = Filemanager
871
872
873
874# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
Note: See TracBrowser for help on using the browser.