gui.py :  » IDE » PIDA » pida-0.6beta3 » pida » services » language » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » IDE » PIDA 
PIDA » pida 0.6beta3 » pida » services » language » gui.py
# -*- coding: utf-8 -*- 
"""
    pida.services.languages
    ~~~~~~~~~~~~~~~~~~~~~

    Supplies support for languages

    :copyright: 2005-2008 by The PIDA Project
    :license: GPL2 or later
"""

from functools import partial

import gtk
import gobject
import os

from kiwi.ui.objectlist import Column
from kiwi.ui.objectlist import ObjectList,COL_MODEL

from .outlinefilter import FILTERMAP

from pida.core.environment import on_windows,get_pixmap_path
from pida.core.languages import LANGUAGE_PLUGIN_TYPES
from pida.core.log import get_logger

from pida.utils.gthreads import GeneratorTask

# ui
from pida.ui.views import PidaView,PidaGladeView
from pida.ui.objectlist import AttrSortCombo
from pida.ui.prioritywindow import Category,Entry,PriorityEditorView
from pida.core.languages import (PRIO_DEFAULT,PRIO_FOREGROUND
                                 PRIO_FOREGROUND_HIGH, PRIO_LOW)

# locale
from pida.core.locale import Locale
locale = Locale('plugins')
_ = locale.gettext

logger = get_logger('service.language')

class LanguageEntry(Entry):

    @classmethod
    def from_plugin(cls, plugin):
        return cls(uid=plugin.func.uuid(),
                   display=plugin.func.name,
                   plugin=plugin.func.plugin,
                   description=plugin.func.description)

    def uuid(self):
        return self.uid

class LanguageSubCategory(Category):
    def __init__(self, svc, lang, type_):
        self.svc = svc
        self.lang = lang
        self.type_ = type_
        self._customized = None
    
    @property
    def display(self):
        return LANGUAGE_PLUGIN_TYPES[self.type_]['name']

    @property
    def display_info(self):
        if self.type_ == 'completer':
            return _('<i>All plugins before the Disabled entry are used</i>')
        return None
    
    def _get_customized(self):
        if self._customized is None:
            self._customized = len(self.svc.get_priority_list(self.lang, self.type_))
        return self._customized
    
    def _set_customized(self, value):
        self._customized = value
    
    customized = property(_get_customized, _set_customized)

    def get_entries(self, default=False):
        #for type_, info in LANGUAGE_PLUGIN.iteritems():
        for i in self.svc.get_plugins(self.lang, self.type_, default=default):
            yield LanguageEntry.from_plugin(i)

    def has_entries(self):
        # the disable service should always exist,so there should be more 
        # then 1 real entries
        return len(self.svc.get_plugins(self.lang, self.type_)) > 1

    def commit_list(self, lst):
        done = []
        prio = []
        for x in lst:
            if x.uuid() in done:
                continue
            prio.append({"uuid": x.uuid(),
                 "name": x.display,
                 "plugin": x.plugin,
                 "description": x.description})
            done.append(x.uuid())

        self.svc.set_priority_list(self.lang, self.type_, prio, save=False)


class LanguageCategory(Category):
    def __init__(self, svc, lang):
        self.svc = svc
        self.lang = lang

    @property
    def display(self):
        return self.svc.doctypes[self.lang].human


    def get_subcategories(self):
        for type_, info in LANGUAGE_PLUGIN_TYPES.iteritems():
            #self.svc.get_plugins(self.lang, type_)
            yield LanguageSubCategory(self.svc, self.lang, type_)

    def needs_visible(self):
        """
        Returns True if it should be displayed
        """
        for type_, info in LANGUAGE_PLUGIN_TYPES.iteritems():
            #self.svc.get_plugins(self.lang, type_)
            if LanguageSubCategory(self.svc, self.lang, type_).has_entries():
                return True

class LanguageRoot(Category):
    """
    Data root for PriorityEditor
    """
    def __init__(self, svc, prioview):
        self.svc = svc
        self.prioview = prioview

    def get_subcategories(self):
        for internal in self.svc.doctypes.iterkeys():
            entry = LanguageCategory(self.svc, internal)
            if self.prioview.all_languages.get_active():
                yield entry
            elif entry.needs_visible():
                yield entry

class LanguagePriorityView(PriorityEditorView):
    """
    Window which allows the user to configure the priorities of plugins
    """
    key = 'language.prio'

    icon_name = 'gtk-library'
    label_text = _('Language Priorities')

    def create_ui(self):
        self.root = LanguageRoot(self.svc, self)
        self.set_category_root(self.root)

    def can_be_closed(self):
        self.svc.get_action('show_language_prio').set_active(False)

    def on_button_apply__clicked(self, action):
        super(LanguagePriorityView, self).on_button_apply__clicked(action)
        #self.svc.get_action('show_language_prio').set_active(False)
        # update all caches
        self.svc.options.set_extra_value(
            "plugin_priorities",
            self.svc.options.get_extra_value("plugin_priorities"))
        self.svc.emit('refresh')

    def on_button_close__clicked(self, action):
        super(LanguagePriorityView, self).on_button_close__clicked(action)
        self.svc.get_action('show_language_prio').set_active(False)

class ValidatorView(PidaView):

    key = 'language.validator'

    icon_name = 'python-icon'
    label_text = _('Validator')

    def create_ui(self):
        self._last_selected = None
        self.document = None
        self.tasks = {}
        self.restart = False
        self.errors_ol = ObjectList(
            Column('markup', use_markup=True)
        )
        self.errors_ol.set_headers_visible(False)
        self.errors_ol.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.add_main_widget(self.errors_ol)
        self.errors_ol.connect('double-click', self._on_errors_double_clicked)
        self.errors_ol.connect('row-activated', self._on_errors_double_clicked)
        self.errors_ol.connect('selection-changed', 
                               self._on_errors_ol_selection_changed)
        self.errors_ol.show_all()
        self.sort_combo = AttrSortCombo(
            self.errors_ol,
            [
                ('lineno', _('Line Number')),
                ('message', _('Message')),
                ('type_', _('Type')),
            ],
            'lineno',
        )
        self.sort_combo.show()
        self.add_main_widget(self.sort_combo, expand=False)

    def set_validator(self, validator, document):
        # this is quite an act we have to do here because of the many cornercases
        # 1. Jobs once started run through. This is for caching purpuses as a validator
        # is supposed to cache results, somehow.
        # 2. buffers can switch quite often and n background jobs are still 
        # running

        # set the old task job to default priorty again
        old = self.tasks.get(self.document, None)
        if old:
            old.priority = PRIO_LOW

        self.document = document
        self.clear()

        if self.tasks.has_key(document):
            # set the priority of the current validator higher, so it feels 
            # faster on the current view
            if self.svc.boss.window.paned.is_visible_pane(self.pane):
                prio = PRIO_FOREGROUND
            else:
                prio = PRIO_DEFAULT
            self.tasks[document].priorty = prio
            # when restart is set, the set_validator is run again so the 
            # list gets updated from the validator cache. this happens when
            # the buffer switched to another file and back again
            self.restart = True
            self.svc.log.debug(_('Validator task for %s already running'), document)
            return

        self.restart = False

        if validator:

            def wrap_add_node(document, *args):
                # we need this proxy function as a task may be still running in 
                # background and the document already switched
                # this way we still can fill up the cache by letting the task run
                # sometimes args have a lengh of 0 so we have to catch this
                if self.document == document and len(args):
                    self.add_node(args[0])
                    if self._last_selected:
                        if self._last_selected[0] == self.document:
                            if args[0].lineno == self._last_selected[1]:
                                self.errors_ol.select(args[0])

            def on_complete(document, validator):
                del self.tasks[document]
                # refire the task and hope the cache will just display stuff,
                # elsewise the task is run again
                validator.sync()

                if document == self.document and self.restart:
                    self.set_validator(validator, document)

            radd = partial(wrap_add_node, document)
            rcomp = partial(on_complete, document, validator)

            if self.svc.boss.window.paned.is_visible_pane(self.pane):
                prio = PRIO_FOREGROUND
            else:
                prio = PRIO_DEFAULT

            task = GeneratorTask(validator.get_validations_cached, 
                                 radd,
                                 complete_callback=rcomp,
                                 priority=prio)
            self.tasks[document] = task
            task.start()

    def add_node(self, node):
        if node:
            node.lookup_color = self.errors_ol.style.lookup_color
            self.errors_ol.append(node)


    def clear(self):
        self.errors_ol.clear()

    def _on_errors_ol_selection_changed(self, ol, item):
        if not item:
            return
        self._last_selected = (self.document, item.lineno)

    def _on_errors_double_clicked(self, ol, item):
        self.svc.boss.editor.cmd('goto_line', line=item.lineno)

    def can_be_closed(self):
        self.svc.get_action('show_validator').set_active(False)


class BrowserView(PidaGladeView):
    """
    Window with the outliner
    """

    key = 'language.browser'


    gladefile = 'outline_browser'
    locale = locale
    icon_name = 'python-icon'
    label_text = _('Outliner')

    def create_ui(self):
        self.document = None
        self.tasks = {}
        self.restart = False
        self.source_tree.set_columns(
            [
                Column('icon_name', use_stock=True),
                Column('markup', use_markup=True, expand=True),
                Column('type_markup', use_markup=True),
                Column('sort_hack', visible=False),
                Column('line_sort_hack', visible=False),
            ]
        )
        self.source_tree.set_headers_visible(False)
        # faster lookups on the id property
        self.source_tree_ids = {}
        self.sort_box = AttrSortCombo(
            self.source_tree,
            [
                ('sort_hack', _('Alphabetical by type')),
                ('line_sort_hack', _('Line Number')),
                ('name', _('Name')),
            ],
            'sort_hack'
        )
        self.sort_box.show()
        self.sort_vbox.pack_start(self.sort_box, expand=False)
        self.filter_model = self.source_tree.get_model().filter_new()
        #FIXME this causes a total crash on win32
        if not on_windows:
            self.source_tree.get_treeview().set_model(self.filter_model)
        self.filter_model.set_visible_func(self._visible_func)
        self.source_tree.get_treeview().connect('key-press-event',
            self.on_treeview_key_pressed)
        self.source_tree.get_treeview().connect('row-activated',
                                     self.do_treeview__row_activated)

        self._last_expanded = None

    def _visible_func(self, model, iter_):
        node = model[iter_][0]
        # FIXME: None objects shouldn't be here, but why ????
        if not node:
            return False
        ftext = self.filter_name.get_text().lower()
        #riter = model.convert_child_iter_to_iter(iter)
        # name filter
        def if_type(inode):
            # type filter
            if inode.filter_type in self.filter_map:
                if self.filter_map[inode.filter_type]:
                    return True
                else:
                    return False
            else:
                return True


        if ftext:
            # we have to test if any children of the current node may match
            def any_child(parent):
                if not parent:
                    return False
                for i in xrange(model.iter_n_children(parent)):
                    child = model.iter_nth_child(parent, i)
                    cnode = model[child][0]
                    if cnode and cnode.name.lower().find(ftext) != -1 and if_type(cnode):
                        return True
                    if model.iter_has_child(child) and any_child(child):
                        return True
                return False

            if (node.name and node.name.lower().find(ftext) != -1) or \
                (model.iter_has_child(iter_) and any_child(iter_)):
                return if_type(node)
            
            return False
        
        return if_type(node)

    def set_outliner(self, outliner, document):
        # see comments on set_validator

        old = self.tasks.get(self.document, None)
        if old:
            old.priority = PRIO_DEFAULT

        self.document = document
        self.clear()

        if self.tasks.has_key(document):
            # set the priority of the current validator higher, so it feels 
            # faster on the current view
            if self.svc.boss.window.paned.is_visible_pane(self.pane):
                prio = PRIO_FOREGROUND
            else:
                prio = PRIO_DEFAULT
            self.tasks[document].priorty = prio
            # when restart is set, the set_validator is run again so the 
            # list gets updated from the validator cache. this happens when
            # the buffer switched to another file and back again
            self.restart = True
            self.svc.log.debug(_('Outliner task for %s already running'), document)
            return

        self.restart = False

        if outliner:
#            if self.task:
#                self.task.stop()
#            self.task = GeneratorTask(outliner.get_outline_cached, self.add_node)
#            self.task.start()


            def wrap_add_node(document, *args):
                # we need this proxy function as a task may be still running in 
                # background and the document already switched
                # this way we still can fill up the cache by letting the task run
                # sometimes args have a lengh of 0 so we have to catch this
                if self.document == document and len(args):
                    self.add_node(*args)

            def on_complete(document, outliner):
                del self.tasks[document]
                outliner.sync()
                # fire refilter so the list is updated after buffer changed
                self.filter_model.refilter()
                # refire the task and hope the cache will just display stuff,
                # elsewise the task is run again
                if document == self.document and self.restart:
                    self.set_outliner(outliner, document)


            radd = partial(wrap_add_node, document)
            rcomp = partial(on_complete, document, outliner)

            if self.svc.boss.window.paned.is_visible_pane(self.pane):
                prio = PRIO_FOREGROUND
            else:
                prio = PRIO_DEFAULT

            task = GeneratorTask(outliner.get_outline_cached, 
                                 radd,
                                 complete_callback=rcomp,
                                 priority=prio)
            self.tasks[document] = task
            task.start()


    def clear(self):
        self.source_tree.clear()
        self.source_tree_ids = {}

    def get_by_id(self, id_):
        """
        Return the OutlinerItem by it's id property
        """
        def lookup(model, path, iter):
            if model.get_value(iter, 0).id == id_:
                lookup.rv = model.get_value(iter, 0)
                return True

        self.source_tree.get_model().foreach(lookup)
        return getattr(lookup, 'rv', None)


    def add_node(self, node):
        if not node:
            return

        if node.id:
            self.source_tree_ids[node.id] = node

        if node.parent:
            parent = node.parent
        elif node.parent_id:
            # only the parent_id was submitted so we have to look the parent up
            try:
                parent = self.source_tree_ids[node.parent_id]
            except KeyError:
                # try a deep lookup
                parent = self.get_by_id(node.parent_id)
        else:
            parent = None

        try:
            self.source_tree.append(parent, node)
        except Exception, e:
            import traceback
            traceback.print_exc()
            print "exc", e
            print "add", parent, node

    def can_be_closed(self):
        self.svc.get_action('show_outliner').set_active(False)

    def do_treeview__row_activated(self, treeview, path, view_column):
        "After activated (double clicked or pressed enter) on a row"
        # we have to use this hand connected version as the kiwi one
        # used the wrong model and not our filtered one :(
        try:
            row = self.filter_model[path]
        except IndexError:
            print 'path %s was not found in model: %s' % (
                path, map(list, self._model))
            return
        item = row[COL_MODEL]
        if item.filename is not None:
            self.svc.boss.cmd('buffer', 'open_file', file_name=item.filename,
                                                     line=item.linenumber)
            self.svc.boss.editor.cmd('grab_focus')
        elif item.linenumber:
            self.svc.boss.editor.cmd('goto_line', line=item.linenumber)
            self.svc.boss.editor.cmd('grab_focus')
        return True

    def update_filterview(self, outliner):
        if outliner:
            def rmchild(widget):
                self.filter_toolbar.remove(widget)
            self.filter_toolbar.foreach(rmchild)

            self.filter_map = dict(
                [(f, FILTERMAP[f]['default']) for f in outliner.filter_type]
                )
            for f in self.filter_map:
                tool_button = gtk.ToggleToolButton()
                tool_button.set_name(str(f))
                tool_button.set_active(self.filter_map[f])
                #FIXME no tooltip on win32
                if not on_windows:
                    tool_button.set_tooltip_text(FILTERMAP[f]['display'])
                tool_button.connect("toggled", self.on_filter_toggled,outliner)
                im = gtk.Image()
                im.set_from_file(get_pixmap_path(FILTERMAP[f]['icon']))
                tool_button.set_icon_widget(im)
                self.filter_toolbar.insert(tool_button, 0)
        #self.options_vbox.add(self.filter_toolbar)
        self.options_vbox.show_all()

    def on_filter_toggled(self, but, outliner):
        self.filter_map[int(but.get_name())] = not self.filter_map[int(but.get_name())]
        #self.set_outliner(outliner, self.document)
        self.filter_model.refilter()

    def on_filter_name_clear__clicked(self, widget):
        self.filter_name.set_text('')

    def on_filter_name__changed(self, widget):
        if len(widget.get_text()) >= self.svc.opt('outline_expand_vars'):
            for i in self.source_tree:
                self.source_tree.expand(
                    i,
                    open_all=True)
        else:
            for i in self.source_tree:
                self.source_tree.collapse(i)

        self.filter_model.refilter()

    def on_treeview_key_pressed(self, tree, event):
        if event.keyval == gtk.keysyms.space:
            # FIXME: who to do this right ??
            cur = self.source_tree.get_selected()
            if self._last_expanded == cur:
                self._last_expanded = None
                self.source_tree.collapse(
                    cur)
            else:
                self.source_tree.expand(
                    cur, 
                    open_all=False)
                self._last_expanded = cur
            return True

    def on_type_changed(self):
        pass
        
#    def read_options(self):
#        return {}

class DefinitionView(PidaGladeView):
    """
    List of Definitions if language plugin returns more then one result
    """

    key = 'language.definition'

    gladefile = 'definition'
    #icon_name = 'python-icon'
    label_text = _('Definition')


    def create_ui(self):
        self._project = None
        self.list.set_columns(
                [
                    Column('icon_name', title=' ', width=35, use_stock=True,
                            expand=False),
                    Column('signature', data_type=str, title=_('Symbol'),
                           format_func=self.format_signature,
                           expander=True, searchable=True),
                    Column('file_name', data_type=str, title=_('Filename'),
                           format_func=self.format_path,
                           expander=True, searchable=True),
                    Column('line', data_type=int, title=_('Line'))
                ]
        )
    def grab_focus(self):
        self.list.grab_focus()
        if len(self.list):
            self.list.select(self.list[0], scroll=True)
            self.list.get_treeview().grab_focus()

    def format_signature(self, value):
        if value:
            return value[:80]
        return ''

    def format_path(self, path):
        if not self._project:
            return path
        comps = self._project.get_relative_path_for(path)
        if comps:
            return os.path.sep.join(comps)
        return path

    def set_list(self, lst):
        self._project = self.svc.boss.cmd('project', 'get_current_project')
        self.list.clear()
        for i in lst:
            self.list.append(i)

    def on_list__row_activated(self, widget, row):
        self.svc.use_definition(row)

    def on_list__double_click(self, widget, row):
        self.svc.use_definition(row)

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.