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()