scrolledmessage.py :  » Development » Leo » Leo-4.7.1-final » leo » plugins » 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 » Development » Leo 
Leo » Leo 4.7.1 final » leo » plugins » scrolledmessage.py

#@+leo-ver=4-thin
#@+node:leohag.20081204085551.1:@thin scrolledmessage.py
#@@first

#@<< docstring >>
#@+node:leohag.20081203143921.2:<< docstring >>
"""
Scrolled Message Dialog
=======================

Provides a Scrolled Message Dialog service for Qt based guis/plugins.

The plugin can display messages supplied as plain text or formated as html. In addition the plugin can accept messages in rst format and convert them to be displayed as html.

The displayed format can be controlled by the user via check boxes, so rst messages may be viewed either as text or as html. Html messages can also be viwed as raw text, which will be a good debug feature when creating complex dynamically generated html messages.

The user interface is provided by a ScrolledMessage.ui file which is dynamically loaded each time a new dialog is loaded.

The dialog is not modal and many dialogs can exist at one time. Dialogs can be named and output directed to a dialog with a specific name.  

The plugin is invoked like this:

    g.doHook('scrolledMessage', c=c, msg='message', title='title',  ...etc    )

or
    g.app.gui.runScrolledMessageDialog(c=c, ...etc)

all parameters are optional except c.

Parameters
----------
    msg:
        The text to be displayed (html, rst, plain).

        If the text starts with 'rst:' it is assumed to be rst text and
        is converted to html for display, (after the rst: prefix has been removed.

        If the text starts with '<' it is assumed to be html.

        These auto detection features can be overridden by 'flags'.

    label:
        The text to appear in a label above the display. If it is '', the label is hidden.

    title:
        The title to appear on the window or dock.

    flags:
        Says what kind of message eg: 'rst', 'text', 'html'. This overrides auto-detection.

        Flags can be combined, eg 'rst html' causes the message to be interpreted as rst and
        displayed as html.

To Do
-----
    - Add parameters to control position, size, closing, hiding etc.

    - Save or print files from the dialog.

    - Add an option to put the dialog in leo's log notebook.

    - Add \@settings to control default behaviour

    - Provide a menu of plugins that allows their docstring to be displayed.

    - Provide a menu of @rst nodes in the current outline, automatically track changes
      if it is set to display any of these nodes.

"""
#@-node:leohag.20081203143921.2:<< docstring >>
#@nl

#@@language python
#@@tabwidth -4
#@@pagewidth 80

controllers = {}
globalPrinter = None

#@<< imports >>
#@+node:leohag.20081203143921.3:<< imports >>
import inspect 

import leo.core.leoGlobals as g
import leo.core.leoPlugins as leoPlugins

try:
    from PyQt4 import QtCore,QtGui,uic
    Qt = QtCore.Qt
except ImportError:
    Qt = None

#@+others
#@-others
#@-node:leohag.20081203143921.3:<< imports >>
#@nl

#@+others
#@+node:leohag.20081203143921.4:init
def init():

    ok = g.app.gui.guiName().startswith("qt")
    if ok:
        leoPlugins.registerHandler(('open2','new'), onCreate)
        leoPlugins.registerHandler('scrolledMessage', scrolledMessageHandler)
        leoPlugins.registerHandler('scrolledMessage', selectHandler)

        g.plugin_signon(__name__)

    return ok
#@-node:leohag.20081203143921.4:init
#@+node:leohag.20081203143921.5:onCreate
def onCreate (tag,key):

    c = key.get('c')
    if c and c.exists and c not in controllers:
        controllers[c] = ScrolledMessageController(c) 

#@-node:leohag.20081203143921.5:onCreate
#@+node:leohag.20081206052547.20:globalGetPrinter
def getGlobalPrinter():
    global globalPrinter

    if not globalPrinter:
        globalPrinter = QtGui.QPrinter()
    return globalPrinter
#@-node:leohag.20081206052547.20:globalGetPrinter
#@+node:leohag.20081203143921.6:scrolledMessageHandler
def scrolledMessageHandler(tag, keywords):

    c = keywords.get('c')
    if  c in controllers:
        return controllers[c].scrolledMessageHandler(tag, keywords)
#@nonl
#@-node:leohag.20081203143921.6:scrolledMessageHandler
#@+node:leohag.20081207032616.20:selectHandler
def selectHandler(tag, keywords):

    c = keywords.get('c')
    if  c in controllers:
        return controllers[c].selectHandler(tag, keywords)
#@nonl
#@-node:leohag.20081207032616.20:selectHandler
#@+node:leohag.20081207032616.18:safe
def safe(msg):
    return msg.replace('&','&amp;').replace('<', '&lt;').replace('>', '&gt;')
#@nonl
#@-node:leohag.20081207032616.18:safe
#@+node:leohag.20081203143921.9:class ScrolledMessageDialog
class ScrolledMessageDialog(object):

    # 'labels' with no sub menu are the names of actions without the 'action' prefix
    # eg ('Save', None) refers to actionSave

    menuList = [
        ('File', [
            ('Save', None),
            ('', None),
            ('PageSetup', None),
            ('PrintPreview', None),
            ('PrintDialog', None),
        ]),
        ('Outline',[
            ('OutlineShow', None),
            ('RST3', None),
            ('', None),
            ('OutlineThisNode', None),
            ('OutlineExpandFollowsTree', None),
            ('OutlineIncludeBody', None),
        ]),
        ('Help', [
            ('About', None),
        ])
    ]

    #@    @+others
    #@+node:leohag.20081203210510.1:__init__
    def __init__(self, parent, kw ):

        self.parent = parent
        self.c = parent.c
        self.ui = self.getGui()(self)

        self.createMenuBar()

        top = self.c.frame.top
        self.dock = dock = QtGui.QDockWidget("Scrolled Message Dialog", top)
        dock.setAllowedAreas(Qt.AllDockWidgetAreas)
        dock.setWidget(self.ui)
        dock.resize(400, 500)

        top.addDockWidget(Qt.RightDockWidgetArea, dock)

        dock.setFloating(False)

        self.controls = {}
        self.controlFlags = {}

        self.findChkControls()
        self.chkBtnChanged(silent=True)

        self.updateDialog(kw)
        self.ui.show()
    #@-node:leohag.20081203210510.1:__init__
    #@+node:leohag.20081206052547.14:Action Handlers (slots)
    #@+node:leohag.20081206052547.35:File Menu
    #@+node:leohag.20081206052547.19:_print
    def _print(self, printer):
        g.trace( printer)
        self.ui.leo_webView.print_(printer)

    #@-node:leohag.20081206052547.19:_print
    #@+node:leohag.20081206052547.21:PageSetup
    def doActionPageSetup(self, checked):

        dialog = QtGui.QPageSetupDialog(getGlobalPrinter(), self.ui)
        dialog.exec_()


    #@-node:leohag.20081206052547.21:PageSetup
    #@+node:leohag.20081206052547.15:Print
    def doActionPrint(self, checked):
        self._print(getGlobalPrinter())
    #@nonl
    #@-node:leohag.20081206052547.15:Print
    #@+node:leohag.20081206052547.24:PrintDialog
    def doActionPrintDialog(self, checked):
        #g.trace()
        dialog = QtGui.QPrintDialog(getGlobalPrinter(),self.ui)
        if dialog.exec_() == QtGui.QDialog.Accepted:
            self._print(getGlobalPrinter())
    #@nonl
    #@-node:leohag.20081206052547.24:PrintDialog
    #@+node:leohag.20081206052547.23:PrintPreview
    def doActionPrintPreview(self, checked):
        g.trace()
        dialog = QtGui.QPrintPreviewDialog(getGlobalPrinter(),self.ui)
        dialog.connect(dialog, QtCore.SIGNAL('paintRequested(QPrinter*)'), self._print )
        dialog.exec_()
    #@-node:leohag.20081206052547.23:PrintPreview
    #@+node:leohag.20081206052547.16:Save
    def doActionSave(self):
        g.trace()

        result = g.app.gui.runSaveFileDialog()
        g.es(result)
        if result:
            f = open(result, 'wb')
            f.write(self.convertMessage().encode('utf-8'))
            f.close()

    #@-node:leohag.20081206052547.16:Save
    #@-node:leohag.20081206052547.35:File Menu
    #@+node:leohag.20081206052547.27:Outline Menu
    #@+node:leohag.20081206052547.28:Show
    def doActionOutlineShow(self, checked):

        import leo.plugins.leo_to_html as html

        node = self.ui.actionOutlineThisNode.isChecked()
        self._includeBody = self.ui.actionOutlineIncludeBody.isChecked()
        self._expandFollowsTree  = self.ui.actionOutlineExpandFollowsTree.isChecked()

        html = []

        html.append('<ol>')

        if node:
            root = self.c.currentPosition()
            self.doNextLevel(root, html)
        else:
            root = self.c.rootPosition()
            for pp in root.following_siblings():
                self.doNextLevel(pp, html)

        html.append('</ol>')

        #@    << msg = html carcass>>
        #@+node:leohag.20081207032616.16:<< msg = html carcass>>
        msg = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
        <title>
            %s
        </title>
        </head>
        <body>
        %s
        </body></html>
        """
        #@-node:leohag.20081207032616.16:<< msg = html carcass>>
        #@nl
        #@    << label = filename >>
        #@+node:leohag.20081207032616.19:<< label = filename >>
        label = self.c.frame.shortFileName()
        if not label:
            label = 'untitiled'
        #@nonl
        #@-node:leohag.20081207032616.19:<< label = filename >>
        #@nl

        msg = msg % (label, '\n'.join(html))

        g.doHook('scrolledMessage', c=self.c, name=self.name, msg=msg, label=label, flags='html')
    #@+node:leohag.20081207032616.17:doNextLevel
    def doNextLevel(self, p, html):
        """" Recursivley proccess an outline node into an html list."""

        html.append('<li>')
        html.append(safe(p.headString())) 

        if self._includeBody:
            html.append('<div><pre>%s</pre></div>'%safe(p.bodyString()))

        if p.hasChildren() and (p.isExpanded() or not self._expandFollowsTree):

            html.append('<ol>')
            for item in p.children():
                self.doNextLevel(item, html)
            html.append('</ol>')

        html.append('</li>')


    #@-node:leohag.20081207032616.17:doNextLevel
    #@-node:leohag.20081206052547.28:Show
    #@-node:leohag.20081206052547.27:Outline Menu
    #@+node:leohag.20081206052547.36:Help Menu
    #@+node:leohag.20081206052547.17:About
    def doActionAbout(self, checked):
        g.trace()
        pass
    #@nonl
    #@-node:leohag.20081206052547.17:About
    #@-node:leohag.20081206052547.36:Help Menu
    #@+node:leohag.20081207032616.24:RST3
    def doActionRST3(self, checked):

        rst3 = leoPlugins.getPluginModule('rst3')

        if not rst3:
            rst3 = leoPlugins.loadOnePlugin('rst3',verbose=True)
            if rst3:
                g.es('rst3 loaded')
                rst3.onCreate('tag',{'c':self.c})

        if rst3:
            controller = rst3.controllers.get(self.c)
            if controller:
                g.doHook('scrolledMessage', c=self.c, msg='loading..', flags='text')
                p,s = controller.writeNodeToString(ext='.html')
                g.doHook('scrolledMessage', c=self.c, msg=s, flags='html')
    #@-node:leohag.20081207032616.24:RST3
    #@-node:leohag.20081206052547.14:Action Handlers (slots)
    #@+node:leohag.20081206052547.12:Menu Bar
    #@+node:leohag.20081206052547.34:createMenuBar
    def createMenuBar(self):

        self.menubar = mb = QtGui.QMenuBar(self.ui)

        for title, subMenu in self.menuList:
            menu = self.createSubMenu(mb, title, subMenu)
            mb.addMenu(menu)

        self.ui.leo_menubar_frame.layout().insertWidget(0, mb)
        mb.show()

    #@-node:leohag.20081206052547.34:createMenuBar
    #@+node:leohag.20081206052547.13:createSubMenu
    def createSubMenu(self, parent, title, menuList):

        #g.trace(title, menuList)

        menu = QtGui.QMenu(title, parent)
        for subTitle, subList in menuList:

            if subList:
                submenu = self.createSubMenu(menu, subTitle, subList)
                menu.addMenu(submenu)
            elif subTitle:
                #< < find and bind action >>

                action = getattr(self.ui, 'action%s'%subTitle, None)
                if action:
                    method = getattr(self, 'doAction%s'%subTitle, None)
                    if method: 
                        action.connect(action, QtCore.SIGNAL('triggered(bool)'), method)
                    menu.addAction(action)
            else:
                menu.addSeparator()

        return menu
    #@-node:leohag.20081206052547.13:createSubMenu
    #@-node:leohag.20081206052547.12:Menu Bar
    #@+node:leohag.20081203143921.24:getUiPath
    def getUiPath(self):

        return g.os_path_join(g.app.loadDir,'..','plugins', 'ScrolledMessage.ui')
    #@nonl
    #@-node:leohag.20081203143921.24:getUiPath
    #@+node:leohag.20081203143921.22:Create User Interface
    def getGui(self):

        form_class, base_class = uic.loadUiType(self.getUiPath())
        #@    << define class Base_UI>>
        #@+node:leohag.20081203143921.23:<<define class Base_UI>>
        class Base_UI(QtGui.QWidget, form_class):
            """Class to wrap QDesigner ui object and provide glue code to make it work."""

            def __init__(self, parent, *args):
                QtGui.QWidget.__init__(self, *args)
                self.leoParent = parent
                #@        << inject action callbacks >>
                #@+node:leohag.20081206052547.18:<< inject action callbacks >>
                #@+at
                # for name, method in inspect.getmembers(self.leoParent):
                #     if name.startswith('doAction'):
                #         def doAction(self, name=name):
                #             getattr(self.leoParent, name)()
                #         setattr(self.__class__, name, doAction)
                # 
                #@-at
                #@-node:leohag.20081206052547.18:<< inject action callbacks >>
                #@nl
                self.setupUi(self)

            def chkBtnChanged(self):
                self.leoParent.chkBtnChanged()

            def closeEvent(self, event):
                self.leoParent.closeMe(event)
        #@-node:leohag.20081203143921.23:<<define class Base_UI>>
        #@nl
        return Base_UI
    #@-node:leohag.20081203143921.22:Create User Interface
    #@+node:leohag.20081203205020.1:closeMe
    def closeMe(self, visible):
            self.parent.onDialogClosing(self)
            self.dock.destroy()

            print(self.dock)
            print(self.ui)

    #@-node:leohag.20081203205020.1:closeMe
    #@+node:leohag.20081203143921.10:findChkControls
    def findChkControls(self):
        s = 'leo_chk_'; ls = len(s)
        for k, v in self.ui.__dict__.items():
            if k.startswith(s):
                self.controls[k[ls:]] = v

    #@-node:leohag.20081203143921.10:findChkControls
    #@+node:leohag.20081203143921.11:setFlagsFromControls
    def setFlagsFromControls(self):
        for flag, control in self.controls.items():
            self.controlFlags[flag] = bool(control.isChecked())

    #@-node:leohag.20081203143921.11:setFlagsFromControls
    #@+node:leohag.20081203143921.12:setControlsFromFlags
    def setControlsFromFlags(self):
        for flag, value in self.controlFlags.items():
            self.controls[flag].setChecked(bool(value))

    #@-node:leohag.20081203143921.12:setControlsFromFlags
    #@+node:leohag.20081203143921.13:chkBtnClhanged
    def  chkBtnChanged(self,silent=False):
        self.setFlagsFromControls()
        if not silent:
            self.showMessage()

    #@-node:leohag.20081203143921.13:chkBtnClhanged
    #@+node:leohag.20081203143921.14:showMessage
    def showMessage(self, show=True):

        html = self.convertMessage()

        self.ui.leo_webView.setHtml(html)

        if show:
            self.dock.show()
            toggle = self.dock.toggleViewAction()
            toggle.setChecked(True)
    #@-node:leohag.20081203143921.14:showMessage
    #@+node:leohag.20081206052547.37:convertMessage
    def convertMessage(self):

        msg = self.msg
        f = self.controlFlags
        if f['html']:
            if f['rst']:
                msg = self.rstToHtml(msg)
            if f['text']:
                msg = self.textToHtml(msg)
        else:
            msg = self.textToHtml(msg)

        return msg

    #@-node:leohag.20081206052547.37:convertMessage
    #@+node:leohag.20081203143921.15:rstToHtml
    def rstToHtml( self, rst):

        try:
            from docutils import core
        except ImportError:
            g.es('scrolledMessage: Can not import docutils', color='blue')
            return self.textToHtml(rst)

        overrides = {
            'doctitle_xform': False,
            'initial_header_level': 1
        }

        try:
            parts = core.publish_parts(
                source= rst,
                writer_name='html',
                settings_overrides=overrides
            )
        except Exception:
            g.es('scrolledMessage: rst conversion error', color='blue')
            return self.textToHtml(rst)

        return parts['whole']

    #@-node:leohag.20081203143921.15:rstToHtml
    #@+node:leohag.20081203143921.16:textToHtml
    def textToHtml(self, msg):

        return '<pre>%s<pre>'%safe(msg)



    #@-node:leohag.20081203143921.16:textToHtml
    #@+node:leohag.20081203143921.17:updateDialog
    def updateDialog(self, kw):

        # update ivars
        for k in list(kw.keys()):
            setattr(self, k, kw[k])

        if not g.isString(self.msg):
            self.msg = '<h2 style="color:red" >Illegal! Message must be string.</h2>'
            self.flags = 'html'

        # auto detect message type
        if not self.flags.strip():
            self.flags = 'text'
            if self.msg.startswith('rst:'):
                self.flags = 'rst html'
                self.msg = self.msg[4:]
            elif self.msg.startswith('<'):
                self.flags = 'html'

        flags = self.flags.split(' ')
        if 'rst' in flags and 'text' not in flags:
            flags.append('html')

        # update the ui check box controls
        ff = self.controlFlags 

        for flag in list(ff.keys()):
            if flag in flags:
                ff[flag] = True
            else:
                ff[flag] = False

        self.setControlsFromFlags()

        # update label
        w = self.ui.leo_topLabel
        if self.label:
            w.setText(self.label)
            w.show()
        else:
            w.hide()

        #update title
        self.dock.setWindowTitle(self.title)

        self.showMessage()
    #@-node:leohag.20081203143921.17:updateDialog
    #@+node:leohag.20081207032616.23:afterDrawHandler
    def afterDrawHandler():

        pass
        #if self.ui.actionFollowOutline
    #@-node:leohag.20081207032616.23:afterDrawHandler
    #@+node:leohag.20081203143921.18:show
    def show(self):
        self.ui.show()
    #@nonl
    #@-node:leohag.20081203143921.18:show
    #@-others

#@-node:leohag.20081203143921.9:class ScrolledMessageDialog
#@+node:leohag.20081203143921.19:class ScrolledMessageController
class ScrolledMessageController(object):


    kwDefaults = {'msg':'', 'flags':'', 'name':'', 'title':'Leo Message', 'label':''}

    #@    @+others
    #@+node:leohag.20081206052547.1:__init__
    def __init__(self, c):

        self.dialogs = {}
        self.usedNames = set()

        self.c = c
    #@-node:leohag.20081206052547.1:__init__
    #@+node:leohag.20081203143921.20:updateDialog
    def updateDialog(self, kw):

        # print(self.c, self.dialogs)

        if  not kw['name']:
            # name = self.getUniqueName()
            name = 'leo_system'
            kw['name'] = name

        if kw['name'] not in self.dialogs:
            self.createDialog(kw)
        else:
            self.dialogs[kw['name']].updateDialog(kw)

    #@-node:leohag.20081203143921.20:updateDialog
    #@+node:leohag.20081203143921.21:createDialog
    def createDialog(self, kw):

        self.dialogs[kw['name']] = ScrolledMessageDialog(self, kw)
        self.usedNames.add(kw['name'])

    #@-node:leohag.20081203143921.21:createDialog
    #@+node:leohag.20081203143921.25:getUniqueName
    def getUniqueName(self):

        count = 0
        while True:
            count += 1
            name = 'ScrolledMessage_%s'%count
            if name not in self.usedNames:
                return name


    #@-node:leohag.20081203143921.25:getUniqueName
    #@+node:leohag.20081203143921.26:scrolledMessageHandler
    def scrolledMessageHandler(self, tag, keywords):   

        for k, v in self.kwDefaults.items():
            if k not in keywords:
                keywords[k] = v 

        #g.trace(keywords)
        self.updateDialog(keywords)

        return keywords

    #@-node:leohag.20081203143921.26:scrolledMessageHandler
    #@+node:leohag.20081207032616.21:afterRedrawHandler
    def afterRedrawHandler(self, tag, keywords):   

        for name, dialog in dialogs:
            self.afterRedrawHandler()
    #@-node:leohag.20081207032616.21:afterRedrawHandler
    #@+node:leohag.20081203210510.3:onDialogClosing
    def onDialogClosing(self, dialog):

        del self.dialogs[dialog.name]

    #@-node:leohag.20081203210510.3:onDialogClosing
    #@-others

#@-node:leohag.20081203143921.19:class ScrolledMessageController
#@-others
#@-node:leohag.20081204085551.1:@thin scrolledmessage.py
#@-leo
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.