ed_statbar.py :  » GUI » wxPython » wxPython-src-2.8.11.0 » wxPython » wx » tools » Editra » src » 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 » GUI » wxPython 
wxPython » wxPython src 2.8.11.0 » wxPython » wx » tools » Editra » src » ed_statbar.py
###############################################################################
# Name: ed_statbar.py                                                         #
# Purpose: Custom statusbar with builtin progress indicator                   #
# Author: Cody Precord <cprecord@editra.org>                                  #
# Copyright: (c) 2008 Cody Precord <staff@editra.org>                         #
# License: wxWindows License                                                  #
###############################################################################

"""
Custom StatusBar for Editra that contains a progress bar that responds to
messages from ed_msg to display progress of different actions.

@summary: Editra's StatusBar class

"""

__author__ = "Cody Precord <cprecord@editra.org>"
__svnid__ = "$Id: ed_statbar.py 62723 2009-11-26 18:43:20Z CJP $"
__revision__ = "$Revision: 62723 $"

#--------------------------------------------------------------------------#
# Imports
import wx
import wx.stc

# Editra Libraries
import ed_glob
import util
import ed_msg
from syntax.synglob import GetDescriptionFromId
from eclib import ProgressStatusBar,EncodingDialog
from extern.decorlib import anythread

#--------------------------------------------------------------------------#
 
_ = wx.GetTranslation

#--------------------------------------------------------------------------#

class EdStatBar(ProgressStatusBar):
    """Custom status bar that handles dynamic field width adjustment and
    automatic expiration of status messages.

    """
    ID_CLEANUP_TIMER = wx.NewId()
    def __init__(self, parent):
        super(EdStatBar, self).__init__(parent, style=wx.ST_SIZEGRIP)

        # Attributes
        self._pid = parent.GetId() # Save parents id for filtering msgs
        self._widths = list()
        self._cleanup_timer = wx.Timer(self, EdStatBar.ID_CLEANUP_TIMER)
        self._eolmenu = wx.Menu()
        self._log = wx.GetApp().GetLog()

        # Setup
        self.SetFieldsCount(6) # Info, vi stuff, line/progress
        self.SetStatusWidths([-1, 90, 40, 40, 40, 155])
        self._eolmenu.Append(ed_glob.ID_EOL_MAC, u"CR",
                             _("Change line endings to %s") % u"CR")
        self._eolmenu.Append(ed_glob.ID_EOL_WIN, u"CRLF",
                             _("Change line endings to %s") % u"CRLF")
        self._eolmenu.Append(ed_glob.ID_EOL_UNIX, u"LF",
                             _("Change line endings to %s") % u"LF")

        # Event Handlers
        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
        self.Bind(wx.EVT_TIMER, self.OnExpireMessage,
                  id=EdStatBar.ID_CLEANUP_TIMER)

        # Messages
        ed_msg.Subscribe(self.OnProgress, ed_msg.EDMSG_PROGRESS_SHOW)
        ed_msg.Subscribe(self.OnProgress, ed_msg.EDMSG_PROGRESS_STATE)
        ed_msg.Subscribe(self.OnUpdateText, ed_msg.EDMSG_UI_SB_TXT)
        ed_msg.Subscribe(self.OnUpdateDoc, ed_msg.EDMSG_UI_NB_CHANGED)
        ed_msg.Subscribe(self.OnUpdateDoc, ed_msg.EDMSG_FILE_SAVED)
        ed_msg.Subscribe(self.OnUpdateDoc, ed_msg.EDMSG_FILE_OPENED)
        ed_msg.Subscribe(self.OnUpdateDoc, ed_msg.EDMSG_UI_STC_LEXER)

    def __del__(self):
        """Unsubscribe from messages"""
        ed_msg.Unsubscribe(self.OnProgress)
        ed_msg.Unsubscribe(self.OnUpdateText)
        ed_msg.Unsubscribe(self.OnUpdateDoc)
        super(EdStatBar, self).__del__()

    def __SetStatusText(self, txt, field):
        """Safe method to use for setting status text with CallAfter.
        @param txt: string
        @param field: int

        """
        try:
            super(EdStatBar, self).SetStatusText(txt, field)
            self.AdjustFieldWidths()

            if field == ed_glob.SB_INFO and txt != u'':
                # Start the expiration countdown
                if self._cleanup_timer.IsRunning():
                    self._cleanup_timer.Stop()
                self._cleanup_timer.Start(10000, True)
        except wx.PyDeadObjectError, wx.PyAssertionError:
            # Getting some odd assertion errors on wxMac so just trap
            # and ignore them for now
            # glyphCount == (text.length()+1)" failed at graphics.cpp(2048)
            # in GetPartialTextExtents()
            pass
        except TypeError, err:
            self._log("[edstatbar][err] Bad status message: %s" % str(txt))
            self._log("[edstatbar][err] %s" % err)

    def AdjustFieldWidths(self):
        """Adjust each field width of status bar basing on the field text
        @return: None

        """
        widths = [-1]
        # Calculate required widths
        # NOTE: Order of fields is important
        for field in [ed_glob.SB_BUFF,
                      ed_glob.SB_LEXER,
                      ed_glob.SB_ENCODING,
                      ed_glob.SB_EOL,
                      ed_glob.SB_ROWCOL]:
            width = self.GetTextExtent(self.GetStatusText(field))[0] + 20
            if width == 20:
                width = 0
            widths.append(width)

        # Adjust widths
        if widths[-1] < 155:
            widths[-1] = 155

        # Only update if there are changes
        if widths != self._widths:
            self._widths = widths
            self.SetStatusWidths(self._widths)

    def GetMainWindow(self):
        """Method required for L{ed_msg.mwcontext}"""
        return self.GetParent()

    def OnExpireMessage(self, evt):
        """Handle Expiring the status message when the oneshot timer
        tells us it has expired.

        """
        if evt.GetId() == EdStatBar.ID_CLEANUP_TIMER:
            wx.CallAfter(self.__SetStatusText, u'', ed_glob.SB_INFO)
        else:
            evt.Skip()

    def OnLeftDClick(self, evt):
        """Handlers mouse left double click on status bar
        @param evt: Event fired that called this handler
        @type evt: 
        @note: Assumes parent is MainWindow instance

        """
        pt = evt.GetPosition()
        if self.GetFieldRect(ed_glob.SB_ROWCOL).Contains(pt):
            mw = self.GetParent()
            mpane = mw.GetEditPane()
            mpane.ShowCommandControl(ed_glob.ID_GOTO_LINE)
        else:
            evt.Skip()

    def OnLeftUp(self, evt):
        """Handle left clicks on the status bar
        @param evt: wx.MouseEvent

        """
        pt = evt.GetPosition()
        if self.GetFieldRect(ed_glob.SB_EOL).Contains(pt):
            rect = self.GetFieldRect(ed_glob.SB_EOL)
            self.PopupMenu(self._eolmenu, (rect.x, rect.y))
        elif self.GetFieldRect(ed_glob.SB_ENCODING).Contains(pt):
            nb = self.GetTopLevelParent().GetNotebook()
            buff = nb.GetCurrentCtrl()
            dlg = EncodingDialog(nb,
                                 msg=_("Change the encoding of the current document."),
                                 title=_("Change Encoding"),
                                 default=buff.GetEncoding())
            bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_DOCPROP),
                                           wx.ART_OTHER)
            if bmp.IsOk():
                dlg.SetBitmap(bmp)
            dlg.CenterOnParent()

            # TODO: should add EdFile callbacks for modification events instead
            #       of using explicit statusbar refresh.
            if dlg.ShowModal() == wx.ID_OK:
                buff.SetEncoding(dlg.GetEncoding())
                self.UpdateFields()
            dlg.Destroy()
        else:
            evt.Skip()

    def OnProgress(self, msg):
        """Set the progress bar's state
        @param msg: Message Object

        """
        mdata = msg.GetData()
        # Don't do anything if the message is not for this frame
        if self._pid != mdata[0]:
            return

        mtype = msg.GetType()
        if mtype == ed_msg.EDMSG_PROGRESS_STATE:
            # May be called from non gui thread so don't do anything with
            # the gui here.
            self.SetProgress(mdata[1])
            self.range = mdata[2]
            if sum(mdata[1:]) == 0:
                self.Stop()
        elif mtype == ed_msg.EDMSG_PROGRESS_SHOW:
            if mdata[1]:
                self.Start(75)
            else:
                # TODO: findout where stray stop event is coming from...
                self.Stop()

    @ed_msg.mwcontext
    def OnUpdateDoc(self, msg):
        """Update document related fields
        @param msg: Message Object

        """
        self.UpdateFields()
        if msg.GetType() == ed_msg.EDMSG_UI_NB_CHANGED:
            wx.CallAfter(self.__SetStatusText, u'', ed_glob.SB_INFO)

    @anythread
    def DoUpdateText(self, msg):
        """Thread safe update of status text. Proxy for OnUpdateText because
        pubsub seems to have issues with passing decorator methods for
        listeners.
        @param msg: Message Object

        """
        # Only process if this status bar is in the active window and shown
        parent = self.GetTopLevelParent()
        if (parent.IsActive() or wx.GetApp().GetTopWindow() == parent):
            field, txt = msg.GetData()
            self.UpdateFields()
            wx.CallAfter(self.__SetStatusText, txt, field)

    def OnUpdateText(self, msg):
        """Update the status bar text based on the received message
        @param msg: Message Object

        """
        self.DoUpdateText(msg)

    def PushStatusText(self, txt, field):
        """Set the status text
        @param txt: Text to put in bar
        @param field: int

        """
        wx.CallAfter(self.__SetStatusText, txt, field)

    def SetStatusText(self, txt, field):
        """Set the status text
        @param txt: Text to put in bar
        @param field: int

        """
        wx.CallAfter(self.__SetStatusText, txt, field)

    def UpdateFields(self):
        """Update document fields based on the currently selected
        document in the editor.
        @postcondition: encoding and lexer fields are updated
        @todo: update when readonly hooks are implemented

        """
        nb = self.GetParent().GetNotebook()
        if nb is None:
            return

        try:
            cbuff = nb.GetCurrentCtrl()
            doc = cbuff.GetDocument()
            wx.CallAfter(self.__SetStatusText, doc.GetEncoding(),
                         ed_glob.SB_ENCODING)
            wx.CallAfter(self.__SetStatusText,
                         GetDescriptionFromId(cbuff.GetLangId()),
                         ed_glob.SB_LEXER)

            eol = { wx.stc.STC_EOL_CR : u"CR",
                    wx.stc.STC_EOL_LF : u"LF",
                    wx.stc.STC_EOL_CRLF : u"CRLF" }
            wx.CallAfter(self.__SetStatusText,
                         eol[cbuff.GetEOLMode()],
                         ed_glob.SB_EOL)

        except wx.PyDeadObjectError:
            # May be called asyncronasly after the control is already dead
            return
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.