waypoint.py :  » IDE » PIDA » pida-0.6beta3 » pida-plugins » waypoint » 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 plugins » waypoint » waypoint.py
# -*- coding: utf-8 -*-
"""
    :copyright: 2005-2008 by The PIDA Project
    :license: GPL 2 or later (see README/COPYING/LICENSE)
"""

# gtk
import gtk, gobject
import time

# PIDA Imports

# core
from pida.core.service import Service
from pida.core.events import EventsConfig
from pida.core.features import FeaturesConfig
from pida.core.commands import CommandsConfig
from pida.core.actions import ActionsConfig,TYPE_NORMAL,TYPE_MENUTOOL
from pida.core.options import OptionsConfig
from pida.core.pdbus import DbusConfig,EXPORT
from pida.core.document import Document

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


LEXPORT = EXPORT(suffix='buffer')

class WayPoint(object):
    """
    Represents a single point of the waypoint history
    """
    def __init__(self, document, line, time_=None):
        self.document = document
        self.line = line
        self.time = time_ or time.time()

    def __repr__(self):
        return '<WayPoint %s %s @ %s>' %(self.document, self.line, self.time)
    

class WayStack(list):
    """
    Object to stores the waypoint's
    """
    def __init__(self, threshold = 30, max_length = 30, timespan=8,
                       docswitch=False):
        """
        Makes a new instance of WayStack.
        
        :param threshold - lines that must be changed befor beeing a new point
        :max_length - max numbers of point in path
        """
        self.threshold  = threshold
        self.timespan = timespan
        self.max_length = max_length
        self.docswitch = docswitch
        self.current_point = None
        self._considered = []
        self._last_document = None
        self._last_line = None

    def notify_change(self, document, line, force=False, time_=None):
        """
        Adds the document waypoint to the 
        """
        # jumping in the history should not change it
        #for point in self:
        #    if point.document == document and point.line == line:
        #        return
        
        is_good = None

        wpoint = WayPoint(document, line, time_=time_)
        ctime = wpoint.time
        self._considered.insert(0, wpoint)
        # cap considered stack
        del self._considered[20:]

        first = time.time()

        if force:
            self._addpoint(wpoint)
            return

        for check in self._considered[1:]:
            if document == check.document:
                if check.line < line + self.threshold  and \
                   check.line > line - self.threshold and \
                   check.time + self.timespan  <= ctime:
                    fuzz = self.get_fuzzy(wpoint)
                    if fuzz:
                        # we update the line of the fuzzy match so
                        # have the point near bye when jumping back
                        fuzz.line = line
                    else:
                        self._addpoint(wpoint)
                        del self._considered[:]
            elif self.docswitch and document != check.document:
                # if the document changes, we don't need checking anymore
                self._addpoint(wpoint)
                del self._considered[:]
            else:
                break

    def _addpoint(self, point):
        #if self.current_point:
        #    cpoint = self.index(self.current_point)
        #    if cpoint:
        #        # delete all entries befor the current_point
        #        del self[0:cpoint]
        self.insert(0, point)
        self.current_point = point
        del self[self.max_length:]
        #self._last_line = line
        #self._last_document = document

        #self._last_document = document
        #self._last_line = line

    def __contains__(self, element):
        if not isinstance(element, WayPoint):
            return list.__contains__(element)
        for i in self:
            if element.line == i.line and element.document == i.document:
                return True
        return False


    def has_fuzzy(self, element):
        """
        Tests if a element of roughly the props is in the stack
        """
        if not isinstance(element, WayPoint):
            return list.__contains__(element)
        for i in self:
            if element.document == i.document and \
               (i.line - self.threshold) < element.line and \
               (i.line + self.threshold) > element.line:
                return True
        return False

    def get_fuzzy(self, document, line=0):
        """
        Returns the first fuzzy matched element from the Stack
        """
        if isinstance(document, WayPoint):
            line = document.line
            document = document.document
        
        best = None
        for i in self:
            if document == i.document and \
               (i.line - self.threshold) < line and \
               (i.line + self.threshold) > line:
                # we can simply return the exact match
                if i.line == line:
                    return i
                if not best or abs(best.line - line) > abs(i.line - line):
                    best = i
        return best


    def clear(self):
        """
        Clear the WayStack list
        """
        del self[:]
        self.current_point = None
        self._last_document = None
        self._last_line = None

    def jump(self, steps):
        """
        Jumps n steps forward or backward in history and returns the WayPoint.
        
        If steps would break the Borders of the Path, min or max point is 
        returned.
        """
        if not len(self):
            return
        try:
            nindex = min(max(self.index(self.current_point)+steps, 0), len(self)-1)
        except (IndexError, ValueError):
            # the current waypoint was deleted for example
            nindex = 0
        self.current_point = self[nindex]
        self._last_line = self.current_point.line
        self._last_document = self.current_point.document
        return self.current_point

    def remove_waypoint(self, document, line):
        best = self.get_fuzzy(document, line)
        if best and line == best.line:
            self.remove(best)
            if self.current_point == best:
                self.current_point = len(self) and self[0] or None

    def remove_waypoints_of_document(self, document):
        rmlst = []

        for i in self:
            if i.document == document:
                rmlst.append(i)
        for i in rmlst:
            self.remove(i)

        if self.current_point in rmlst:
            self.current_point = None



class WaypointEventsConfig(EventsConfig):
    def subscribe_all_foreign(self):
        self.subscribe_foreign('buffer', 'document-changed',
                    self.on_document_changed)
        self.subscribe_foreign('buffer', 'document-closed',
                    self.on_document_closed)
        self.subscribe_foreign('buffer', 'document-goto',
                    self.on_document_goto)

    def on_document_changed(self, document):
        self.svc.notify_change(document,
                               self.svc.boss.editor.get_current_line())

    def on_document_goto(self, document, line):
        self.svc.notify_change(document, line)

    def on_document_closed(self, document):
        if self.svc.opt('rm_on_close'):
            self.svc.remove_waypoints_of_document(document)

class WaypointFeaturesConfig(FeaturesConfig):

    def subscribe_all_foreign(self):
        pass


class WaypointOptionsConfig(OptionsConfig):

    def create_options(self):
        self.create_option(
            'timespan',
            _('Timespan'),
            int,
            8,
            _('After how man seconds a groups of lines (in the threshold) '
              'is considered a waypoint'),
            self.on_update
        )

        self.create_option(
            'threshold',
            _('Threshold'),
            int,
            30,
            _('After how many lines set a new waypoint'),
            self.on_update
        )

        self.create_option(
            'docswitch',
            _('Waypoint on document change'),
            bool,
            False,
            _('Should a new waypoint be generated if the document switches'),
            self.on_update
        )

        self.create_option(
            'max_entries',
            _('Max Entries'),
            int,
            30,
            _('Who many entries to have'),
            self.on_update
        )

        self.create_option(
            'rm_on_close',
            _('Remove on close'),
            bool,
            True,
            _('Remove entries when a document is closed')
        )

    def on_update(self, *args):
        self.svc.update_stack()


class WaypointCommandsConfig(CommandsConfig):

    def notifiy_change(self, document=None, line=None):
        if document is not None and line is not None:
            self.svc.notifiy_change(document, line)


class BufferDbusConfig(DbusConfig):
    
    @LEXPORT(in_signature='ii')
    def notifiy_change(self, document_id, line):
        doc = self.boss.cmd('buffer', 'get_document_by_id', 
                            document_id=document_id)
        if doc and line:
            self.svc.notifiy_change(doc, line)

class WaypointActionsConfig(ActionsConfig):

    def create_actions(self):
        self.create_action(
            'clear_waypoints',
            TYPE_NORMAL,
            _('Clear Waypoints'),
            _('Clear your waypoint list'),
            gtk.STOCK_CLEAR,
            self.on_clear_waypoints,
        )
        self.create_action(
            'WaypointMenu',
            TYPE_MENUTOOL,
            _('Waypoint_s'),
            _('Show Waypoint List'),
            '',
            self.on_menu,
        )

        self.create_action(
            'force_waypoint',
            TYPE_NORMAL,
            _('Add Waypoint'),
            _('Forces a new Waypoint'),
            '',
            self.on_force_waypoint,
            ''
        )

        self.create_action(
            'remove_waypoint',
            TYPE_NORMAL,
            _('Remove Waypoint'),
            _('Remove current waypoint'),
            '',
            self.on_remove_waypoint,
            ''
        )

        self.create_action(
            'jump_waypoint_back',
            TYPE_NORMAL,
            _('Jump Waypoint Back'),
            _('Jump next waypoint back'),
            '',
            self.on_jump_back,
            '<Shift><Control>Up'
        )

        self.create_action(
            'jump_waypoint_forward',
            TYPE_NORMAL,
            _('Jump Waypoint Forward'),
            _('Jump next waypoint forward'),
            '',
            self.on_jump_next,
            '<Shift><Control>Down'
        )

    def on_jump_back(self, action):
        self.svc.jump(1)

    def on_jump_next(self, action):
        self.svc.jump(-1)

    def on_clear_waypoints(self, action):
        #self.svc.execute_current_document()
        self.svc._stack.clear()

    def on_force_waypoint(self, action):
        self.svc.notify_change(None, None, force=True)

    def on_remove_waypoint(self, action):
        document = self.svc.boss.cmd('buffer', 'get_current')
        line = self.svc.boss.editor.get_current_line()
        if document and line:
            self.svc.remove_waypoint(document, line)

    def on_menu(self, action):
        self.svc.create_waypoint_menu()


class Waypoint(Service):

    features_config = WaypointFeaturesConfig
    actions_config = WaypointActionsConfig
    options_config = WaypointOptionsConfig
    events_config = WaypointEventsConfig
    commands_config = WaypointCommandsConfig

    def pre_start(self):
        self._stack = WayStack(self.opt('threshold'), self.opt('max_entries'),
                               self.opt('timespan'), self.opt('docswitch'))

    def update_stack(self):
        """
        Update the stack to reflect new preferences
        """
        self._stack.threshold = self.opt('threshold')
        self._stack.max_length = self.opt('max_entries')
        self._stack.timespan = self.opt('timespan')
        self._stack.docswitch = self.opt('docswitch')

    def remove_waypoint(self, document, line, fuzzy=False):
        self._stack.remove_waypoint(document, line)

    def remove_waypoints_of_document(self, document):
        self._stack.remove_waypoints_of_document(document)


    def notify_change(self, document, line, force=False):
        """Notify of a document, and line number change"""

        if document is None:
            document = self.boss.cmd('buffer', 'get_current')
            line = self.boss.editor.get_current_line()
            if not document or not line:
                return

        if not isinstance(document, Document):
            import traceback
            print "Not a document"
            traceback.print_stack()
            return
        if not line:
            line = 1
        self._stack.notify_change(document, line, force=force)

    def jump(self, steps):
        """
        jump n positions in the stack
        """
        npoint = self._stack.jump(steps)
        self.boss.cmd('buffer', 'open_file', 
                          document=npoint.document, line=npoint.line)

    def _update_waypoints(self):
        self.notify_change(None, None)
        return True

    def start(self):
        self._window_list_id = self.boss.window.create_merge_id()
        self._action_group = gtk.ActionGroup('window_list')
        self.boss.window._uim._uim.insert_action_group(self._action_group, -1)
        self._timeout = gobject.timeout_add(2000, self._update_waypoints)

    def stop(self):
        self.boss.window._uim._uim.remove_action_group(self._action_group)
        if self._timeout:
            gobject.source_remove(self._timeout)

    def _on_waypoint(self, action, waypoint):
        self.boss.get_service('buffer').view_document(
                                document=waypoint.document,
                                line=waypoint.line)

    def create_waypoint_menu(self):
        # update the window menu list
        # clean up the old list
        self.boss.window.remove_uidef(self._window_list_id)
        for action in self._action_group.list_actions():
            self._action_group.remove_action(action)

        i = 0
        # add panels to list. they are sorted after the paned positions and
        # therefor good
        for wpoint in self._stack:
            action_name = "go_waypoint_%s" %i
            title = u"%s   %s" %(unicode(wpoint.document), wpoint.line)
            act = gtk.Action(action_name,
                title,
                '',
                '')
            act.connect('activate', self._on_waypoint, wpoint)
            self._action_group.add_action(act)
            self.boss.window._uim._uim.add_ui(
                self._window_list_id,
                "ui/menubar/AddMenu/WaypointMenu/waypoint_list", 
                title, 
                action_name, 
                gtk.UI_MANAGER_MENUITEM, 
                False)            #mi = act.create_menu_item()
            i += 1
        return None

# Required Service attribute for service loading
Service = Waypoint



# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.