Friday, June 19, 2009

Rapid application development with Jython and JFace (part VI - First application reviewed)

New things to learn in this part: Tree, SashForm, DirectoryDialog, TreeViewer, ITreeContentProvider, LabelProvider, ISelectionChangedListener.

Tree control

Tree control is used to display a hierarchy of items and issues notification when an item in the hierarchy is selected. We'll use this control in our application to display hierarchy of directories and files. User will be able to select image file and then we'll display selected image.

SashFrom

Divides client are into independent areas. We'll use it to divide application screen into two peaces: tree of files and image view area.

DirectoryDialog

Directory selection dialog.

TreeViewer, ITreeContentProvider, LabelProvider, ISelectionChangedListener

These classes help to customize and simplify control of tree control. TreeViewer – sits on top of tree control and provides easy control of it, less of manual control is needed. ITreeContentProvider – provides items that should be displayed in tree control. LabelProvider – controls how items should apier in tree control. ISelectionChangedListener – tels what actions should be taken on item selection in tree control.

Explanation of source code

Create SashFrom as top window and divide client area of it into two peaces: treePanel (displays tree control) and imagePanel (displays selected image). Tree will get 30% of application window and image will get 70% of application window.

mainForm = SashForm(parent, SWT.HORIZONTAL | SWT.NULL)
treePanel = Composite(mainForm, SWT.NONE)
imagePanel = Composite(mainForm, SWT.NONE)
mainForm.setWeights([30, 70])
In treePanel we should put tree control.
self.treeViewer = TreeViewer(treePanel, SWT.BORDER | SWT.VIRTUAL)
We'll add ITreeContentProvider, LabelProvider, IselectionChangedListener to it.
self.treeViewer.setContentProvider(FileTreeContentProvider())
self.treeViewer.setLabelProvider(FileTreeLabelProvider())
self.treeViewer.addSelectionChangedListener(FileTreeSelectionChangedListener(self))
We'll add canvas to imagePanel.
self.canvas = Canvas(imagePanel, SWT.BORDER | SWT.NO_BACKGROUND|SWT.NO_REDRAW_RESIZE|SWT.V_SCROLL|SWT.H_SCROLL)

Class FileTreeContentProvider implements ITreeContentProvider

We search directory for directories and files and add those to tree.

Class FileTreeLabelProvider extends LabelProvider

We display short name of directory or file in tree control. If item is directory we are displaying directory image. If item is file we are displaying picture image.

Class FileTreeSelectionChangedListener implements ISelectionChangedListener

Then user selects item which is file we will display it in canvas.

Full Code

"""
Not so dumb image displaying application JPictureMaster II (Jython & JFace example)
Part VI - First application reviewed
GUID of this code snippet: 979fa00c-3001-4c24-b04d-f41d06f1d6d2
[ extends code snippet: eef8f89a-d1d6-4211-9063-ba4c736eb620 ]
Author: Darius Kucinskas (c) 2008-2009
Email: d[dot]kucinskas[eta]gmail[dot]com
Blog: http://blog-of-darius.blogspot.com/
License: GPL
"""

from org.eclipse.swt import *
from org.eclipse.swt.SWT import *
from org.eclipse.swt.widgets import *
from org.eclipse.swt.layout import *
from org.eclipse.jface.window import *
from org.eclipse.jface.action import *
from org.eclipse.jface.resource import *
from org.eclipse.swt.graphics import *
from org.eclipse.swt.custom import SashForm
from org.eclipse.jface.viewers import TreeViewer
from org.eclipse.jface.viewers import ITreeContentProvider
from org.eclipse.jface.viewers import LabelProvider
from org.eclipse.jface.viewers import ISelectionChangedListener
from java.lang import Math
from java.io import File
import jarray

# Skip this for now
# Draw glider emblem (I use it as icon for this example)
def drawIcon(display):
    image = Image(display, 16, 16)
    gc = GC(image)

    gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT))
    gc.fillRectangle(0, 0, 16, 16)

    gc.setBackground(Color(display, 193, 39, 45))
    gc.fillRectangle( 1, 11, 4, 4)
    gc.fillRectangle( 6, 11, 4, 4)
    gc.fillRectangle(11, 11, 4, 4)
    gc.fillRectangle(11,  6, 4, 4)
    gc.fillRectangle( 6,  1, 4, 4)

    gc.setBackground(Color(display, 253, 185, 19))
    gc.fillRectangle( 1,  1, 4, 4)
    gc.fillRectangle( 1,  6, 4, 4)
    gc.fillRectangle(11,  1, 4, 4)

    gc.setBackground(Color(display, 0, 106, 68))
    gc.fillRectangle( 6,  6, 4, 4)

    gc.dispose()
    return image

class HBarListener(Listener):
    """ Listener for horizontal scroll events """

    def __init__(self, app):
        self.app = app

    def handleEvent(self, e):        
        selection = self.app.canvas.getHorizontalBar().getSelection()
        x = -selection - self.app.origin.x
        rect = self.app.image.getBounds()
        self.app.canvas.scroll(x, 0, 0, 0, rect.width, rect.height, False)
        self.app.origin.x = -selection

class VBarListener(HBarListener):
    """ Listener for vertical scroll events """

    def handleEvent(self, e):        
        selection = self.app.canvas.getVerticalBar().getSelection()
        y = -selection - self.app.origin.y
        rect = self.app.image.getBounds()
        self.app.canvas.scroll(0, y, 0, 0, rect.width, rect.height, False)
        self.app.origin.y = -selection

class CanvasPaintListener(HBarListener):
    """ Listener for paint events """

    def handleEvent(self, e):
        gc = e.gc
        gc.drawImage(self.app.image, self.app.origin.x, self.app.origin.y)
        rect = self.app.image.getBounds()
        client = self.app.canvas.getClientArea()
        marginW = client.width - rect.width
        if (marginW > 0):
            gc.fillRectangle(rect.width, 0, marginW, client.height)

        marginH = client.height - rect.height
        if (marginH > 0):
            gc.fillRectangle(0, rect.height, client.width, marginH)

class CanvasResizeListener(HBarListener):
    """ Listener for resize events """

    def handleEvent(self, e):
        self.app.newOrResizeImage()
        self.app.canvas.redraw()

class ExitAction(Action):
    """ This is simple quit application action.

    All action classes should inherit from Action (org.eclipse.jface.action.Action) class.
    """

    def __init__(self, app):
        """ constructor of ExitAction

        arguments:
        app - in order to do anything useful I am passing 
        object of my application.    
        """

        self.app = app
        self.text = "E&xit@Ctrl+Q"
        self.toolTipText = "Exit the application"
        self.imageDescriptor = App.getImageRegistry().getDescriptor("file.exit")

    def run(self):
        """ run() method of action. Every action class should have one.

        This time it closes application.
        """

        if self.app != None:
            self.app.close()

class OpenDirectoryAction(Action):
    """ Simple open image action """

    def __init__(self, app):
        self.app = app
        self.text = "O&pen@Ctrl+O"
        self.toolTipText = "Open directiory and scan it for images"
        self.imageDescriptor = App.getImageRegistry().getDescriptor("file.open")

    def run(self):
        # this code shows DirectoryDialog usage
        dlg = DirectoryDialog(self.app.shell, SWT.OPEN)
        dlg.filterPath = "."
        dlg.text = "Select directory to scan for images"
        dir = dlg.open()     

        if (not dir):
            return

        self.app.treeViewer.setInput(File(dir))
        self.app.treeViewer.refresh()

class MainMenuManager(MenuManager):
    """ MenuManager is responsible for constructing  menu """

    def __init__(self, app):
        """constructor of MainMenuManager

        arguments:
        app - in order to do anything useful I am passing 
        object of my application.    
        """
        # let parent class to do it's stuff first
        MenuManager.__init__(self)
        self.app = app

    def createMainMenu(self):
        """ creates menu """

        mainMenu = MenuManager("")
        fileMenu = MenuManager("&File")
        mainMenu.add(fileMenu)
        # add Exit action to file menu 
        fileMenu.add(ExitAction(self.app))
        fileMenu.add(OpenDirectoryAction(self.app))
        return mainMenu

class MainToolbarManager(ToolBarManager):
    """ """
    def __init__(self, app):
        """construcotr of MainToolbar

        arguments:
        app - in order to do anything useful I am passing 
        object of my application.    
        """
        # let parent class to do it's stuff first
        ToolBarManager.__init__(self)
        self.app = app        

    def createMainToolBar(self, style):
        """ add items to toolbar """

        mainToolBar = ToolBarManager(style)

        # add Exit action to toolbar 
        mainToolBar.add(ExitAction(self.app))
        mainToolBar.add(OpenDirectoryAction(self.app))
 return mainToolBar

class FileTreeContentProvider(ITreeContentProvider):
    def getChildren(self, element):
        if (not element):
            return None

        kids = element.listFiles()
        return kids

    def getElements(self, element):
        return self.getChildren(element)

    def hasChildren(self, element):
        if (not element):
            return False

        kids = self.getChildren(element)
        if (not kids):
            return False

        if (len(kids) < 1):
            return False

        return True

    def getParent(self, element):
        return element.getParent()

    def dispose(self):
        pass

    def inputChanged(self, viewer, old_input, new_input):
        pass

class FileTreeLabelProvider(LabelProvider):
    def getImage(self, element):
        if (element.isDirectory()):
            return App.getImageRegistry().getDescriptor("file.open").createImage()

        return App.getImageRegistry().getDescriptor("file.image").createImage()

    def getText(self, element):
        return element.getName()

class FileTreeSelectionChangedListener(ISelectionChangedListener):
    def __init__(self, app):
        self.app = app

    def selectionChanged(self, e):
        selection = e.getSelection()

        file = selection.getFirstElement()
        if (file.isDirectory()):
            return

        self.app.image = Image(Display.getCurrent(), file.getPath())
        self.app.setStatus("Open file: " + file.getPath())
        self.app.newOrResizeImage()

        gc = GC(self.app.canvas)
        rect = self.app.canvas.getClientArea()
        gc.drawImage(self.app.image, 0, 0)
        gc.dispose()

        self.app.canvas.redraw()

class App(ApplicationWindow):
    """ Main class for JFace application drived from ApplicationWindow class """

    # add static image registry
    imageRegistry = None

    # add class method for image registry
    @classmethod
    def getImageRegistry(cls):
        if (not cls.imageRegistry):
            cls.imageRegistry = ImageRegistry()
            cls.imageRegistry.put("app.icon", ImageDescriptor.createFromImage(drawIcon(Display.getCurrent())))

            # load icon image from file
            cls.imageRegistry.put("file.exit", ImageDescriptor.createFromImage(Image(Display.getCurrent(), "img/system-log-out.png")))
            cls.imageRegistry.put("file.open", ImageDescriptor.createFromImage(Image(Display.getCurrent(), "img/document-open.png")))
            cls.imageRegistry.put("file.image", ImageDescriptor.createFromImage(Image(Display.getCurrent(), "img/image-x-generic.png")))

        return cls.imageRegistry

    def __init__(self, shell):
        """ application constructor """
        # let parent class to do it's stuff first
        ApplicationWindow.__init__(self, shell)

        self.canvas = None
        self.image = None
        self.origin = Point(0, 0)

        self.treeViewer = None

        # lets add menu
        self.addMenuBar()

        # lets add toolbar
        self.addToolBar(SWT.FLAT | SWT.WRAP)

        # lets add status line
        self.addStatusLine()

    def dispose(self):
        """ dispose resources here """
        if (self.image != None):
            self.image.dispose()

    def createContents(self, parent):
        """Creates the main window's contents
        parent - the main window
        return - control
        """
        self.shell.setImage(drawIcon(Display.getCurrent())) 
        self.shell.text = 'JPictureMaster II (Jython & JFace example)'

        # create split form
        mainForm = SashForm(parent, SWT.HORIZONTAL | SWT.NULL)
        mainForm.setLayout(FillLayout())

        # create tree
        treePanel = Composite(mainForm, SWT.NONE)
        treePanel.setLayout(GridLayout(1, True))

        self.treeViewer = TreeViewer(treePanel, SWT.BORDER | SWT.VIRTUAL)
        self.treeViewer.getControl().setLayoutData(GridData(SWT.FILL, SWT.FILL, True, True, 3, 3))
        self.treeViewer.setContentProvider(FileTreeContentProvider())
        self.treeViewer.setLabelProvider(FileTreeLabelProvider())
        self.treeViewer.setInput(File("."))
        self.treeViewer.addSelectionChangedListener(FileTreeSelectionChangedListener(self))
        self.treeViewer.refresh()

        imagePanel = Composite(mainForm, SWT.NONE)
        # set layout as one column grid
        imagePanel.setLayout(GridLayout(1, True))

        # create canvas for image displaying
        self.canvas = Canvas(imagePanel, SWT.BORDER | SWT.NO_BACKGROUND|SWT.NO_REDRAW_RESIZE|SWT.V_SCROLL|SWT.H_SCROLL)
        self.canvas.setLayoutData(GridData(SWT.FILL, SWT.FILL, True, True, 1, 1))
        # add listeners to canvas, so we could react to events
        self.canvas.getHorizontalBar().addListener(SWT.Selection, HBarListener(self)) 
        self.canvas.getVerticalBar().addListener(SWT.Selection, VBarListener(self))
        self.canvas.addListener(SWT.Paint, CanvasPaintListener(self))
        self.canvas.addListener(SWT.Resize, CanvasResizeListener(self))

        mainForm.setWeights([30, 70])
        return mainForm

    def createMenuManager(self):
        """ create main menu """
        return MainMenuManager(self).createMainMenu()

    def createToolBarManager(self, style):
        """ create main toolbar """
        return MainToolbarManager(self).createMainToolBar(style)

    def getStatusLineManagerForUpdate(self):
        """ get status line manager """
        return self.getStatusLineManager()

    def newOrResizeImage(self):
        if (not self.canvas):
            return

        client = self.canvas.getClientArea()

        if (not self.image):
            self.image = Image(self.shell.getDisplay(), client.width, client.height)

            gc = GC(self.image)
            gc.fillRectangle(0, 0, client.width, client.height)
            gc.drawLine (0, 0, client.width, client.height)
            gc.drawLine (0, client.height, client.width, 0)
            gc.drawText ("No Image", 10, 10)
            gc.dispose ()

        rect = self.image.getBounds()
        self.canvas.getHorizontalBar().setMaximum(rect.width)
        self.canvas.getVerticalBar().setMaximum(rect.height)
        self.canvas.getHorizontalBar().setThumb(Math.min (rect.width, client.width))
        self.canvas.getVerticalBar().setThumb(Math.min (rect.height, client.height))

        hPage = rect.width - client.width
        vPage = rect.height - client.height
        hSelection = self.canvas.getHorizontalBar().getSelection()
        vSelection = self.canvas.getVerticalBar().getSelection()

        if (hSelection >= hPage):
            if (hPage <= 0):
                hSelection = 0
                self.origin.x = -hSelection

        if (vSelection >= vPage):
            if (vPage <= 0):
                vSelection = 0
                self.origin.y = -vSelection

if __name__ == "__main__":
    """ The entry point for our application """
    display = Display()
    shell = Shell(display)

    app = App(shell)
    # Voodoo of SWT message loop
    try:
        app.setBlockOnOpen(True)
        app.open()
    finally:
        if app != None:
            app.dispose()

    display.dispose()

Thursday, June 18, 2009

Dynamically create a type with Python

Create new type on the fly with type in Python Code:
def cat_init(self):
    self.test1 = '1'
    self.test2 = '2'

def some_method(self):
    print 'meow'

# create new class on the fly
Cat = type('Cat', (object,), {'meow': some_method, '__init__': cat_init })

# create instance of the new class
cat = Cat()

# test new instance
print cat.test2
# >>> 2
print cat.test1
# >>> 1
cat.meow()
# >>> meow

Honey, I killed the superbug

AUSTRALIAN researchers have been astonished to discover a cure-all right under their noses -- a honey sold in health food shops as a natural medicine.

Wednesday, June 17, 2009

Rapid application development with Jython and JFace (part V – First application)

Jython 2.5.0 final is out! Big congrats to the Jython team! Go and download it now! Today my friends we will glue all components together and will make our first application. This application will be dump image displaying utility. I’ll call it “JPictureMaster”. I am using some free icons from Tango Desktop Project so you’ll need to download this archive in order to be able to run application. Then done downloading copy two icons: tango-icon-theme-0.8.90\16x16\actions\system-log-out.png and tango-icon-theme-0.8.90\16x16\actions\document-open.png into "img" folder there your jython script is located. In this part I will add FileDialog and StatusLine. FileDialog This is simple single file selection dialog. By using it I’ll show basics of SWT\JFace dialog usage. StatusLine Status line is used for displaying short status information in your application. Search script code for self.app.setStatus("Open file: " + filename) and you will get idea how to use it. Code:
"""
Dump image displaying application JPictureMaster (Jython & JFace example)
Part V - First application
GUID of this code snippet: eef8f89a-d1d6-4211-9063-ba4c736eb620
Author: Darius Kucinskas (c) 2008-2009
Email: d[dot]kucinskas[eta]gmail[dot]com
Blog: http://blog-of-darius.blogspot.com/
License: GPL
"""
from org.eclipse.swt import *
from org.eclipse.swt.SWT import *
from org.eclipse.swt.widgets import *
from org.eclipse.swt.layout import *
from org.eclipse.jface.window import *
from org.eclipse.jface.action import *
from org.eclipse.jface.resource import *

from java.lang import *

# Skip this for now
# Draw glider emblem (I use it as icon for this example)
from org.eclipse.swt.graphics import *
def drawIcon(display):
    image = Image(display, 16, 16)
    gc = GC(image)

    gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT))
    gc.fillRectangle(0, 0, 16, 16)

    gc.setBackground(Color(display, 193, 39, 45))
    gc.fillRectangle( 1, 11, 4, 4)
    gc.fillRectangle( 6, 11, 4, 4)
    gc.fillRectangle(11, 11, 4, 4)
    gc.fillRectangle(11,  6, 4, 4)
    gc.fillRectangle( 6,  1, 4, 4)

    gc.setBackground(Color(display, 253, 185, 19))
    gc.fillRectangle( 1,  1, 4, 4)
    gc.fillRectangle( 1,  6, 4, 4)
    gc.fillRectangle(11,  1, 4, 4)

    gc.setBackground(Color(display, 0, 106, 68))
    gc.fillRectangle( 6,  6, 4, 4)

    gc.dispose()
    return image

class HBarListener(Listener):
    """ Listener for horizontal scroll events """

    def __init__(self, app):
        self.app = app
    
    def handleEvent(self, e):        
        selection = self.app.canvas.getHorizontalBar().getSelection()
        x = -selection - self.app.origin.x
        rect = self.app.image.getBounds()
        self.app.canvas.scroll(x, 0, 0, 0, rect.width, rect.height, False)
        self.app.origin.x = -selection

class VBarListener(HBarListener):
    """ Listener for vertical scroll events """

    def handleEvent(self, e):        
        selection = self.app.canvas.getVerticalBar().getSelection()
        y = -selection - self.app.origin.y
        rect = self.app.image.getBounds()
        self.app.canvas.scroll(0, y, 0, 0, rect.width, rect.height, False)
        self.app.origin.y = -selection

class CanvasPaintListener(HBarListener):
    """ Listener for paint events """

    def handleEvent(self, e):
        gc = e.gc
        gc.drawImage(self.app.image, self.app.origin.x, self.app.origin.y)
        rect = self.app.image.getBounds()
        client = self.app.canvas.getClientArea()
        marginW = client.width - rect.width
        if (marginW > 0):
            gc.fillRectangle(rect.width, 0, marginW, client.height)

        marginH = client.height - rect.height
        if (marginH > 0):
            gc.fillRectangle(0, rect.height, client.width, marginH)

class CanvasResizeListener(HBarListener):
    """ Listener for resize events """

    def handleEvent(self, e):
        rect = self.app.image.getBounds()
        client = self.app.canvas.getClientArea()
        self.app.canvas.getHorizontalBar().setMaximum(rect.width)
        self.app.canvas.getVerticalBar().setMaximum(rect.height)
        self.app.canvas.getHorizontalBar().setThumb(Math.min (rect.width, client.width))
        self.app.canvas.getVerticalBar().setThumb(Math.min (rect.height, client.height))
        hPage = rect.width - client.width
        vPage = rect.height - client.height
        hSelection = self.app.canvas.getHorizontalBar().getSelection()
 vSelection = self.app.canvas.getVerticalBar().getSelection()
 if (hSelection >= hPage):
            if (hPage <= 0):
                hSelection = 0
  self.app.origin.x = -hSelection
  
 if (vSelection >= vPage):
            if (vPage <= 0):
                vSelection = 0
                self.app.origin.y = -vSelection

        self.app.canvas.redraw()

class ExitAction(Action):
    """ This is simple quit application action.
    
    All action classes should inherit from Action (org.eclipse.jface.action.Action) class.
    """
    
    def __init__(self, app):
        """ constructor of ExitAction
        
        arguments:
        app - in order to do anything useful I am passing 
        object of my application.    
        """
        self.app = app
        self.text = "E&xit@Ctrl+Q"
        self.toolTipText = "Exit the application"
        self.imageDescriptor = App.getImageRegistry().getDescriptor("file.exit")
        
    def run(self):
        """ run() method of action. Every action class should have one.
        This time it closes application.
        """
        if self.app != None:
            self.app.close()

class OpenImageAction(Action):
    """ Simple open image action """

    FILTER_NAMES = ["All Files (*.*)"]
    FILTER_EXTS = ["*.*"]

    def __init__(self, app):
        self.app = app
        self.text = "O&pen@Ctrl+O"
        self.toolTipText = "Open and display image"
        self.imageDescriptor = App.getImageRegistry().getDescriptor("file.open")

    def run(self):
        # this code shows FileDialog usage
        dlg = FileDialog(app.getShell(), SWT.OPEN)
        dlg.filterNames = OpenImageAction.FILTER_NAMES
        dlg.filterExtensions = OpenImageAction.FILTER_EXTS
        dlg.text = "Open an image file or cancel"
        filename = dlg.open()
        
        if (filename != ""):
            # now we'll open image and draw it on canvas
            self.app.setStatus("Open file: " + filename)
            self.app.image = Image(Display.getCurrent(), filename)
            if (self.app.image != None):
                gc = GC(self.app.canvas)
                rect = self.app.canvas.getClientArea()
                gc.fillRectangle(0, 0, rect.width, rect.height)
                gc.drawImage(self.app.image, 0, 0)                
                gc.dispose()

class MainMenuManager(MenuManager):
    """ MenuManager is responsible for constructing  menu """
    
    def __init__(self, app):
        """constructor of MainMenuManager
        
        arguments:
        app - in order to do anything useful I am passing 
        object of my application.    
        """
        # let parent class to do it's stuff first
        MenuManager.__init__(self)
        self.app = app
        
    def createMainMenu(self):
        """ creates menu """
        mainMenu = MenuManager("")
        fileMenu = MenuManager("&File")
        mainMenu.add(fileMenu)
        
        # add Exit action to file menu 
        fileMenu.add(ExitAction(self.app))
        fileMenu.add(OpenImageAction(self.app))
        
        return mainMenu

class MainToolbarManager(ToolBarManager):
    """ """

    def __init__(self, app):
        """construcotr of MainToolbar
        
        arguments:
        app - in order to do anything useful I am passing 
        object of my application.    
        """
        # let parent class to do it's stuff first
        ToolBarManager.__init__(self)
        self.app = app        

    def createMainToolBar(self, style):
        """ add items to toolbar """
        mainToolBar = ToolBarManager(style)

        # add Exit action to toolbar 
        mainToolBar.add(ExitAction(self.app))
        mainToolBar.add(OpenImageAction(self.app))
        
 return mainToolBar

class App(ApplicationWindow):
    """ Main class for JFace application drived from ApplicationWindow class """

    # add static image registry
    imageRegistry = None

    # add class method for image registry
    @classmethod
    def getImageRegistry(cls):
        if (cls.imageRegistry == None):
            cls.imageRegistry = ImageRegistry()
            cls.imageRegistry.put("app.icon", ImageDescriptor.createFromImage(drawIcon(Display.getCurrent())))
            # load icon image from file
            cls.imageRegistry.put("file.exit", ImageDescriptor.createFromImage(Image(Display.getCurrent(), "img\system-log-out.png")))
            cls.imageRegistry.put("file.open", ImageDescriptor.createFromImage(Image(Display.getCurrent(), "img\document-open.png")))

        return cls.imageRegistry
    
    def __init__(self, shell):
        """ application constructor """
        
        # let parent class to do it's stuff first
        ApplicationWindow.__init__(self, shell)

        self.canvas = None

        #we will draw default image
 width = 150
 height = 200
 self.image = Image(shell.getDisplay(), width, height)
 gc = GC(self.image)
 gc.fillRectangle (0, 0, width, height)
 gc.drawLine (0, 0, width, height)
 gc.drawLine (0, height, width, 0)
 gc.drawText ("Default Image", 10, 10)
 gc.dispose ()

        self.origin = Point(0, 0)
        
        # lets add menu
        self.addMenuBar()

        # lets add toolbar
        self.addToolBar(SWT.FLAT | SWT.WRAP)

        # lets add status line
        self.addStatusLine()
    
    def dispose(self):
        """ dispose resources here """
        if (self.image != None):
            self.image.dispose()
        
    def createContents(self, parent):
        """Creates the main window's contents
        parent - the main window
        return - control
        """
        self.getShell().setImage(drawIcon(Display.getCurrent())) 
        self.getShell().text = 'JPictureMaster (Jython & JFace example)'
        
        panel = Composite(parent, SWT.BORDER)
        # set layout as one column grid
        panel.setLayout(GridLayout(1, True))
        
        # create canvas for image displaying
        self.canvas = Canvas(panel, SWT.NO_BACKGROUND|SWT.NO_REDRAW_RESIZE|SWT.V_SCROLL|SWT.H_SCROLL)
        self.canvas.setLayoutData(GridData(SWT.FILL, SWT.FILL, True, True, 1, 1))
        # add listeners to canvas, so we could react to events
        self.canvas.getHorizontalBar().addListener(SWT.Selection, HBarListener(self)) 
        self.canvas.getVerticalBar().addListener(SWT.Selection, VBarListener(self))
        self.canvas.addListener(SWT.Paint, CanvasPaintListener(self))
        self.canvas.addListener(SWT.Resize, CanvasResizeListener(self))
        
        return panel
    
    def createMenuManager(self):
        """ create main menu """
        return MainMenuManager(self).createMainMenu()

    def createToolBarManager(self, style):
        """ create main toolbar """
        return MainToolbarManager(self).createMainToolBar(style)

    def getStatusLineManagerForUpdate(self):
        """ get status line manager """
        return self.getStatusLineManager()

if __name__ == "__main__":
    """ The entry point for our application """
    display = Display()
    shell = Shell(display)
    
    app = App(shell)
    
    # Voodoo of SWT message loop
    try:
        app.setBlockOnOpen(True)
        app.open()
    finally:
        if app != None:
            app.dispose()
    
    display.dispose()
P.S. If you think I am some kind of Jython & JFace guru you are wrong my friend. So if you will spot any kind of bug in this example, please let me know about it!

Monday, June 15, 2009

Rapid application development with Jython and JFace (part IV – main toolbar and image registry)

You could read older posts from this series here, here and here. In this part we’ll add toolbar and image registry. Toolbar this useful thing by which user can trigger commands and then application will do its stuff. In order to have it in your application you should write class that will inherit from the ToolBarManager class. Add method to construct toolbar. And the last thing: you need to call addToolBar () method to your application's constructor. Good now you have toolbar, right? Not jet, first I’ll show you how you can use image registry. Image registry Rule(1): in every application you write you should minimize usage of resources. Image of actions are good candidates for rule no. 1. You can minimize resource usage with images by using imgae registry. Code:
"""
Hello world application with Jython and JFace
Part IV - Toolbar and image registry
GUID of this code snippet: 939698cb-d2ef-448b-90f2-32580ca3225es
Author: Darius Kucinskas (c) 2008-2009
Email: d[dot]kucinskas[eta]gmail[dot]com
Blog: http://blog-of-darius.blogspot.com/
License: GPL
"""
from org.eclipse.swt import *
from org.eclipse.swt.SWT import *
from org.eclipse.swt.widgets import *
from org.eclipse.swt.layout import *
from org.eclipse.jface.window import *
from org.eclipse.jface.action import *
from org.eclipse.jface.resource import *

# Skip this for now
# Draw glider emblem (I use it as icon for this example)
from org.eclipse.swt.graphics import *
def drawIcon(display):
    image = Image(display, 16, 16)
    gc = GC(image)

    gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT))
    gc.fillRectangle(0, 0, 16, 16)

    gc.setBackground(Color(display, 193, 39, 45))
    gc.fillRectangle( 1, 11, 4, 4)
    gc.fillRectangle( 6, 11, 4, 4)
    gc.fillRectangle(11, 11, 4, 4)
    gc.fillRectangle(11,  6, 4, 4)
    gc.fillRectangle( 6,  1, 4, 4)

    gc.setBackground(Color(display, 253, 185, 19))
    gc.fillRectangle( 1,  1, 4, 4)
    gc.fillRectangle( 1,  6, 4, 4)
    gc.fillRectangle(11,  1, 4, 4)

    gc.setBackground(Color(display, 0, 106, 68))
    gc.fillRectangle( 6,  6, 4, 4)

    gc.dispose()
    return image

# Draw exit icon
def drawExitIcon(display):
    image = Image(display, 16, 16)
    gc = GC(image)

    gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT))
    gc.fillRectangle(0, 0, 16, 16)

    gc.setBackground(Color(display, 193, 39, 45))
    gc.fillRectangle( 1, 11, 4, 4)
    gc.fillRectangle(11, 11, 4, 4)
    gc.fillRectangle( 1,  1, 4, 4)
    gc.fillRectangle(11,  1, 4, 4)
    gc.fillRectangle( 6,  6, 4, 4)

    gc.dispose()
    return image

class ExitAction(Action):
    """ This is simple quit application action.
    
    All action classes should inherit from Action (org.eclipse.jface.action.Action) class.
    """
    
    def __init__(self, app):
        """ constructor of ExitAction
        
        arguments:
        app - in order to do anything useful I am passing 
        object of my application.    
        """
        self.app = app
        self.text = "E&xit@Ctrl+Q"
        self.toolTipText = "Exit the application"
        self.imageDescriptor = App.getImageRegistry().getDescriptor("file.exit")
        
    def run(self):
        """ run() method of action. Every action class should have one.
        This time it closes application.
        """
        if self.app != None:
            self.app.close()

class MainMenuManager(MenuManager):
    """ MenuManager is responsible for constructing  menu """
    
    def __init__(self, app):
        """constructor of MainMenuManager
        
        arguments:
        app - in order to do anything useful I am passing 
        object of my application.    
        """
        # let parent class to do it's stuff first
        MenuManager.__init__(self)
        self.app = app
        
    def createMainMenu(self):
        """ creates menu """
        mainMenu = MenuManager("")
        fileMenu = MenuManager("&File")
        mainMenu.add(fileMenu)
        
        # add Exit action to file menu 
        fileMenu.add(ExitAction(self.app))
        
        return mainMenu

class MainToolbarManager(ToolBarManager):
    """ """

    def __init__(self, app):
        """construcotr of MainToolbar
        
        arguments:
        app - in order to do anything useful I am passing 
        object of my application.    
        """
        # let parent class to do it's stuff first
        ToolBarManager.__init__(self)
        self.app = app        

    def createMainToolBar(self, style):
        """ add items to toolbar """
        mainToolBar = ToolBarManager(style)

        # add Exit action to toolbar 
        mainToolBar.add(ExitAction(self.app))
 return mainToolBar

class App(ApplicationWindow):
    """ Main class for JFace application drived from ApplicationWindow class """

    # add static image registry
    imageRegistry = None

    # add class method for image registry
    @classmethod
    def getImageRegistry(cls):
        if (cls.imageRegistry == None):
            cls.imageRegistry = ImageRegistry()
            cls.imageRegistry.put("app.icon", ImageDescriptor.createFromImage(drawIcon(Display.getCurrent())))
            cls.imageRegistry.put("file.exit", ImageDescriptor.createFromImage(drawExitIcon(Display.getCurrent())))

        return cls.imageRegistry
    
    def __init__(self, shell):
        """ application constructor """
        
        # let parent class to do it's stuff first
        ApplicationWindow.__init__(self, shell)
        
        # lets add menu
        self.addMenuBar()

        # lets add toolbar
        self.addToolBar(SWT.FLAT | SWT.WRAP);
    
    def dispose(self):
        """ dispose resources here """
        pass
        
    def createContents(self, parent):
        """Creates the main window's contents
        parent - the main window
        return - control
        """
        self.getShell().setImage(drawIcon(Display.getCurrent())) 
        self.getShell().text = 'Fourth Jython & JFace example'
        
        panel = Composite(parent, SWT.BORDER)
        # set layout as one column grid
        panel.setLayout(GridLayout(1, True))
        
        label = Label(panel, SWT.CENTER)
        label.text = 'Hello, World'
        label.setLayoutData(GridData(SWT.CENTER, SWT.CENTER, False, False, 1, 1))
        
        # you can use action instead of button        
        ActionContributionItem(ExitAction(self)).fill(panel)
        
        return panel
    
    def createMenuManager(self):
        """ create main menu """
        return MainMenuManager(self).createMainMenu()

    def createToolBarManager(self, style):
        """ create main toolbar """
        return MainToolbarManager(self).createMainToolBar(style)

if __name__ == "__main__":
    """ The application entry point """
    display = Display()
    shell = Shell(display)
    
    app = App(shell)
    
    # Voodoo of SWT message loop
    try:
        app.setBlockOnOpen(True)
        app.open()
    finally:
        if app != None:
            app.dispose()
    
    display.dispose()