CVS: anygui/lib/anygui/backends genericgui.py,NONE,1.1

"Dallas T. Johnston" <[email protected]> Sat, 23 Nov 2002 08:42:59 -0800
Newsgroups gmane.comp.python.anygui.cvs
Message-ID <[email protected]>
Update of /cvsroot/anygui/anygui/lib/anygui/backends
In directory sc8-pr-cvs1:/tmp/cvs-serv5647/lib/anygui/backends

Added Files:
	genericgui.py 
Log Message:
Moved all the funny frontend widget stuff into genericgui.py.
Note that there will be issues with how we want the backend
specific use of dialogs to work.
This issue mainly relates to naming of backend wrappers.


--- NEW FILE: genericgui.py ---
#==============================================================#
# Imports
from __future__ import nested_scopes

# For Widgets
import anygui
from anygui.Wrappers import AbstractWrapper
from anygui.Events import link, send
from time import sleep

# For Dialogs
from anygui.Models import ListModel
from anygui.LayoutManagers import SimpleGridManager
from UserList import UserList
import re
import sys, glob, os
import traceback

# End Imports
#==============================================================#

__all__="""

ComboBoxWrapper
AboutDialog
OpenFileDialog

""".split()

#==============================================================#
# Widgets
#--------------------------------------------------------------#
# Factoring out creational code...

class Wrapper(AbstractWrapper):

    def __init__(self, *args, **kwds):
        AbstractWrapper.__init__(self, *args, **kwds)

        # 'container' before everything...
        self.setConstraints('container','x','y','width','height','items','selection')
        # Note: x,y,width, and height probably have no effect here, due to
        # the way getSetters() works. I'm not sure if that's something
        # that needs fixing or not... - jak

        self.addConstraint('geometry', 'visible')
        # FIXME: Is this the right place to put it? Make sure
        # 'geometry' implies 'x', 'y', etc. too (see Wrappers.py)
        # Also, this scheme will cause flashing... (place before
        # place_forget)

    def enterMainLoop(self):
        self.proxy.push()

    def rebuild(self): pass

    def rebuildAll(self): pass

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

class ComboBoxWrapper(Wrapper):
    """This is a generic implementation of the ComboBox that is provided for
       backends that do not provide the ComboBox widget in their respective
       toolkits. This also models the creation of Mega-widgets using the
       Anygui GUI API."""

    _connected = 0
    _comps     = 0
    _textFld  = None
    _popupBtn = None
    _itemLbx = None
    _currentItem = 0
    _popupOpen = 0
    _visible = 1
    _enabled = 1
    _loop = 0
    _btnWidth = 0
    _lbxHeight = 0
    _cbxHeight = 0


    def _createWidgets(self):
        state = self.proxy.state
        x = state['x']
        y = state['y']
        width = state['width']
        height = state['height']
        self._lbxHeight = state['lbxHeight']
        items = list(self.proxy.items)
        self._textFld  = anygui.TextField(geometry = ( x,
                                                       y,
                                                       width - height,
                                                       height ))
        self._popupBtn = anygui.Button(text = 'v',
                                       geometry = ( x + width - height,
                                                    y,
                                                    height,
                                                    height ))
        self._itemLbx = anygui.ListBox(visible = 0,
                                       items = items,
                                       geometry = ( x,
                                                    y + height,
                                                    width,
                                                    self._lbxHeight ))


    def _setupBtn(self):
        self._popupBtn.container = self.proxy.container

    def _setupTxtFld(self):
        self._textFld.container = self.proxy.container

    def _setupLbx(self):
        self._itemLbx.container = self.proxy.container

    def widgetFactory(self, *args, **kws):
        #print '>> in widgetFactory...'
        self._createWidgets()
        self._comps = 1
        class Class: pass
        widget = Class()
        return widget

    def widgetSetUp(self):
        if self._comps and not self._connected:
            #print '>> in widgetSetUp'
            link(self._popupBtn, self._handlePopup)
            link(self._itemLbx, self._handleSelection)
            self._connected = 1

    def setupChildWidgets(self):
        if self._comps:
            #print '>> in setupChildWidgets'
            self._setupTxtFld()
            self._setupBtn()
            self._setupLbx()

    def setContainer(self, container):
        if container is None: return
        parent = container.wrapper.widget
        try:
            assert parent is None
        except (AssertionError):
            self.create(parent)
            self.proxy.push(blocked=['container'])
            self.setupChildWidgets()

    def _handlePopup(self, event):
        #print '>> handling Popup...'
        self._loop = 1
        self._itemLbx.visible = self._popupOpen = not self._popupOpen
        self._loop = 0

    def _handleSelection(self, event):
        #print '>> handling Selection...'
        if not self._loop:
            self._loop = 1
            self._textFld.text = self._itemLbx.items[self._itemLbx.selection]
            self._itemLbx.visible = 0
            sleep(0.1)
            self._popupOpen = 0
            send(self.proxy, 'select')
            self._loop = 0

    def setX(self, x):
        if self._comps:
            dummy, y, width, height = self.geometry
            self.setGeometry(x, y, width, height)

    def setY(self, y):
       if self._comps:
            x, dummy, width, height = self.geometry
            self.setGeometry(x, y, width, height)

    def setWidth(self, width):
       if self._comps:
            x, y, dummy, height = self.geometry
            self.setGeometry(x, y, width, height)

    def setHeight(self, height):
       if self._comps:
            x, y, width, dummy = self.geometry
            self.setGeometry(x, y, width, height)

    def setPosition(self, x, y):
       if self._comps:
            dummy, dummy2, width, height = self.geometry
            self.setGeometry(x, y, width, height)

    def setSize(self, width, height):
       if self._comps:
            x, y, dummy, dummy2 = self.geometry
            self.setGeometry(x, y, width, height)

    def getGeometry(self):
        if self._comps:
            x, y, dummy, height = self._textFld.geometry
            d, d1, width, d2   = self._itemLbx.geometry
            return (x, y, width, height)

    def setGeometry(self, x, y, width, height):
        if self._comps:
            self._loop = 1
            self._textFld.geometry  = (x,
                                       y,
                                       width - height,
                                       height)
            self._popupBtn.geometry = (x + width - height,
                                       y,
                                       height,
                                       height)
            self._itemLbx.geometry =  (x,
                                       y + height,
                                       width,
                                       self._lbxHeight)
            self._loop = 0

    def getSelection(self):
        if self._comps:
            return self._itemLbx.selection

    def setSelection(self, selection):
        if self._comps:
            self._loop = 1
            self._itemLbx.selection = selection
            self._textFld.text = self._itemLbx.items[selection]
            self._loop = 0

    def getItems(self):
        if self._comps:
            return self._itemLbx.items

    def setItems(self, items):
        if self._comps:
            #print '>> in setItems(items) -> ', items
            self._loop = 1
            self._itemLbx.items = items
            self._loop = 0

    def getText(self):
        items = list(self._itemLbx.items)
        text = self._textFld.text
        if text in items:
            return text
        else:
            return items[self._itemLbx.selection]

    def getLbxHeight(self):
        return self._lbxHeight

    def setLbxHeight(self, lbxHeight):
        if self._comps:
            self._lbxHeight = lbxHeight
            x, y, width, height = self.proxy.geometry
            self._itemLbx.geometry = ( x,
                                       y + height,
                                       width,
                                       lbxHeight)

    def getVisible(self):
        return self._visible

    def setVisibile(self, visible):
        if self._comps:
            self._visible = visible
            if self._popupOpen:
                self._itemLbx.visible = visible
                self._popupOpen = visible
            self._textFld.visible = visible
            self._popupBtn.visible = visible

    def getEnabled(self):
        return self._enabled

    def setEnabled(self, enabled):
        if self._comps:
            if self._popupOpen:
                self._itemLbx.visible = 0
                self._popupOpen = 0
            self._enabled = enabled
            self._textFld.enabled  = enabled
            self._popupBtn.enabled = enabled

    def internalDestroy(self):
        if self._comps:
            self._connected = 0
            self._textFld.destroy()
            self._popupBtn.destroy()
            self._itemLbx.destroy()
            self._comps = 0

#==============================================================#
# Dialogs

#--------------------------------------------------------------#
# About Anygui Dialog

ABOUT_TEXT="""
The purpose of the Anygui project is to create an easy-to-use, simple, \
and generic module for making graphical user interfaces in Python. \
Its main feature is that it works transparently with many different \
GUI packages on most platforms.
"""

class AboutDialog(anygui.Window):

    def __init__(self):
        anygui.Window.__init__(self, title='About Anygui', geometry=(250, 200, 300, 225))
        self.initWidgets()

    def initWidgets(self):
        #self.layout = SimpleGridManager(1,3)
        self.label = anygui.Label(text="Anygui info:")
        self.add(self.label, left=10, top=10)
        self.txtAbout = anygui.TextArea(text=ABOUT_TEXT, enabled=0)
        self.add(self.txtAbout, left=10, right=10, top=(self.label,5), \
                 bottom=45, hstretch=1, vstretch=1)
        self.btnOK = anygui.Button(text="OK")
        self.add(self.btnOK, right=10, bottom=10, hmove=1, vmove=1)
        link(self.btnOK, self.close)

    def close(self, event):
        self.destroy()


#--------------------------------------------------------------#
# FileDialog

PATH_SEPAR=''
ROOT_PATH=''
if sys.platform in ['win32', 'dos', 'ms-dos']:
    PATH_SEPAR = '\\'
    ROOT_PATH  = '[a-zA-Z]:\\\\(?!.)'
else:
    PATH_SEPAR = '/'
    ROOT_PATH  = '/(?!.)'

# === SORT_RULES === #

ALPHABETICAL=0
# uses cmp

DIRS_FIRST=1
def sort_dirs_first(x, y):
    if x.endswith(PATH_SEPAR) and y.endswith(PATH_SEPAR):
        pass
    elif x.endswith(PATH_SEPAR):
        return -1
    elif y.endswith(PATH_SEPAR):
        return 1
    return cmp(x, y)

FILES_FIRST=2
def sort_files_first(x, y):
    if x.endswith(PATH_SEPAR) and y.endswith(PATH_SEPAR):
        pass
    elif x.endswith(PATH_SEPAR):
        return 1
    elif y.endswith(PATH_SEPAR):
        return -1
    return cmp(x, y)

SORT_RULES={ALPHABETICAL: cmp, DIRS_FIRST: sort_dirs_first,\
            FILES_FIRST: sort_files_first}

# == END SORT_RULES == #

class DirManager:

    def __init__(self, dir, filter, sort_rule=DIRS_FIRST):
        #print '>> dir    -> ', dir
        #print '>> filter -> ', filter
        assert os.path.isdir(dir), '!! DirManager: ' + dir + ' is not a directory.'
        if not dir.endswith(PATH_SEPAR):
            dir += PATH_SEPAR
        self.currDir = dir
        self.filter = filter
        self.sortRule = sort_rule

        self.currDirCache = []
        self.oneDirUp = ''
        self.oneDirUpCache = []
        self.twoDirUp = ''
        self.twoDirUpCache = []
        self._genDirCaches()

    def update(self):
        self._genDirCaches()

    def isRootDir(self, dir):
        if dir == ROOT_PATH or re.match(ROOT_PATH, dir):
            return 1
        else:
            return 0

    def currDirIsRoot(self):
        return self.isRootDir(self.currDir)

    def dirUp(self, dir):
        return dir[:dir[:-1].rfind(PATH_SEPAR)+1]

    def goDirUp():
        self.currDir = self.oneDirUp
        self._genDirCaches()

    def globDir(self, dir):
        if self.filter == '':
            self.filter = '*'
        cache = glob.glob(dir + self.filter)
        objCache = [ obj[obj.rfind(PATH_SEPAR)+1:] for obj in cache ]
        for i in range(len(cache)):
            if os.path.isdir(cache[i]):
                objCache[i] += PATH_SEPAR
        objCache.sort(SORT_RULES[self.sortRule])
        return objCache

    def _genDirCaches(self):
        #print '>> self.currDir -> ', self.currDir
        self.currDirCache = self.globDir(self.currDir)
        # now generate cache for self.dir/..
        if not self.currDirIsRoot():
            self.oneDirUp = self.dirUp(self.currDir)
            #print '>> self.oneDirUp -> ', self.oneDirUp
            self.oneDirUpCache = self.globDir(self.oneDirUp)
            # and the same for self.dir/../..
            if not self.isRootDir(self.oneDirUp):
                self.twoUpDir = self.dirUp(self.oneDirUp)
                #print '>> self.twoDirUp -> ', self.twoDirUp
                self.twoDirUpCache = self.globDir(self.twoDirUp)


class OpenFileDialog(anygui.Window):

    def __init__(self, dir, filters, sort_rule=DIRS_FIRST):
        anygui.Window.__init__(self, title='Open File - ' + \
                        anygui.application().name + '-' + anygui.application().version, \
                        geometry=(250, 200, 420, 350))
        self._updating = 0
        self.dirMngr = DirManager(dir, filters[0], sort_rule)
        self._priorSelections = []
        #self.createTripaneDirList()
        self.initWidgets(filters)

    #def createTripaneDirList(self):
    #    dirMngr = self.dirMngr
    #    self.dirList = TripanedDoublyLinkedList([dirMngr.currDirCache])
    #    if not dirMngr.currDirIsRoot():
    #        self.dirList.prepend(dirMngr.oneDirUpCache)
    #        if not dirMngr.isRootDir(dirMngr.oneDirUp):
    #            self.dirList.prepend(dirMngr.twoDirUpCache)

    def initWidgets(self, filters):

        dirMngr = self.dirMngr

        btnDirBack = self.btnDirBack = anygui.Button(text='<', size=(50,25))
        if dirMngr.currDirIsRoot():
            btnDirBack.enabled = 0
        self.add(btnDirBack, left=10, top=10)
        link(btnDirBack, self.goDirBack)

        btnDirFwd = self.btnDirFwd = anygui.Button(text='>', size=(50,25))
        btnDirFwd.enabled = 0
        self.add(btnDirFwd, left=(btnDirBack, 5), top=10)
        link(btnDirFwd, self.goDirFwd)

        frmDirs = self.frmDirs = anygui.Frame()
        frmDirs.layout = SimpleGridManager(3,1)
        self.add(frmDirs, left=10, rigth=10, top=(btnDirBack, 5), \
                 bottom=75, vstretch=1, hstretch=1)

        lbxDirOne = self.lbxDirOne = anygui.ListBox()
        #lbxDirOne.items = self.dirList.tripane[0]
        lbxDirOne.items = self.dirMngr.currDirCache
        lbxDirOne.selection = 0
        frmDirs.add(lbxDirOne)
        link(lbxDirOne, self.lbxSelect)

        lbxDirTwo = self.lbxDirTwo = anygui.ListBox()
        frmDirs.add(lbxDirTwo)
        link(lbxDirTwo, self.lbxSelect)

        lbxDirThree = self.lbxDirThree = anygui.ListBox()
        frmDirs.add(lbxDirThree)
        link(lbxDirThree, self.lbxSelect)

        btnCancel = self.btnCancel = anygui.Button(text='Cancel')
        self.add(btnCancel, right=10, top=(frmDirs, 5), hmove=1, vmove=1)
        link(self.btnCancel, self.close)

        btnOpen = self.btnOpen = anygui.Button(text='Open')
        self.add(btnOpen, right=10, top=(btnCancel, 5), hmove=1, vmove=1)
        link(self.btnOpen, self.open)

        lblLocation = self.lblLocation = anygui.Label(text='Location:', width=55)
        self.add(lblLocation, left=10, top=(frmDirs, 18), vmove=1)

        lblFilter = self.lblFilter = anygui.Label(text='Filter:', width=55)
        self.add(lblFilter, left=10, top=(lblLocation, 20), vmove=1)

        txtLocation = self.txtLocation = anygui.TextField(text=dirMngr.currDir)
        self.add(txtLocation, left=(lblLocation, 5), right=100, top=(frmDirs, 8), \
                 hstretch=1, vmove=1)
        link(txtLocation, self.changeDirs)

        cbxFilter = self.cbxFilter = anygui.ComboBox(items=filters)
        #txtFilter = self.txtFilter = TextField(text=dirMngr.filter)
        self.add(cbxFilter, left=(lblFilter, 5), right=100, top=(txtLocation, 10), \
                 hstretch=1, vmove=1)
        link(cbxFilter, self.applyFilter)

    def open(self, event):
        send(self, 'open', file=self.txtLocation.text)
        self.destroy()

    def close(self, event):
        self.destroy()

    def lbxSelect(self, event):
        if self._updating: return
        self_updating = 1
        source = event.source
        if source is self.lbxDirOne:
            self.handleLbxDirOneEvent()
        elif source is self.lbxDirTwo:
            self.handleLbxDirTwoEvent()
        elif source is self.lbxDirThree:
            self.handleLbxDirThreeEvent()
        self.btnDirFwd.enabled = 0
        self._updating = 0

    def handleLbxDirOneEvent(self):
        #print '>> handling lbxDirOne event'
        dirMngr = self.dirMngr
        s = self._state()
        obj = dirMngr.currDir + s.dirOne
        if os.path.isdir(obj):
            dirMngr.filter = self.cbxFilter.text
            result = dirMngr.globDir(obj)
            try:
                s.lbxTwo.items = result
                s.lbxThree.items = []
            except (AttributeError):
                pass
        else:
            try:
                s.lbxTwo.items = []
                s.lbxThree.items = []
            except (AttributeError):
                pass
        self.txtLocation.text = obj

    def handleLbxDirTwoEvent(self):
        #print '>> handling lbxDirTwo event'
        dirMngr = self.dirMngr
        s = self._state()
        obj = dirMngr.currDir + s.dirOne + s.dirTwo
        if os.path.isdir(obj):
            dirMngr.filter = self.cbxFilter.text
            result = dirMngr.globDir(obj)
            s.lbxThree.items = result
        else:
            s.lbxThree.items = []
        self.txtLocation.text = obj

    def handleLbxDirThreeEvent(self):
        #print '>> handling lbxDirThree event'
        dirMngr  = self.dirMngr
        s = self._state()
        obj = dirMngr.currDir + s.dirOne + s.dirTwo + s.dirThree

        if os.path.isdir(obj):
            dirMngr.currDir += s.dirOne
            dirMngr.update()
            s.lbxOne.items = dirMngr.currDirCache
            s.lbxOne.selection = s.selTwo
            dirMngr.filter = self.cbxFilter.text
            s.lbxTwo.items = dirMngr.globDir(dirMngr.currDir + s.dirTwo)
            s.lbxTwo.selection = s.selThree
            s.lbxThree.items = dirMngr.globDir(obj)
            self.btnDirBack.enabled = 1

        self.txtLocation.text = obj

    def goDirFwd(self, event):
        #print ">> Got event: ", event
        #print ">> event dict: ", event.__dict__
        self._updating = 1
        self.handleLbxDirThreeEvent()
        if self._priorSelections:
            priSels = self._priorSelections
            self.lbxDirThree.selection = priSels[0]
            del priSels[0]
        if not self._priorSelections:
            self.btnDirFwd.enabled = 0

        self._updating = 0


    def goDirBack(self, event):
        #print ">> Got event: ", event
        #print ">> event dict: ", event.__dict__

        self._updating = 1

        dirMngr = self.dirMngr
        s = self._state()

        backDir = dirMngr.currDir
        currDir = dirMngr.currDir = dirMngr.oneDirUp
        dirMngr.update()

        s.lbxOne.items = dirMngr.currDirCache
        s.lbxOne.selection = dirMngr.currDirCache.index(\
            backDir[backDir[:-1].rfind(PATH_SEPAR)+1:]\
        )

        s.lbxTwo.items = s.itemsOne
        s.lbxTwo.selection = s.selOne

        s.lbxThree.items = s.itemsTwo
        s.lbxThree.selection = s.selTwo

        self._priorSelections.append(s.selThree)
        self.btnDirFwd.enabled = 1
        if dirMngr.currDirIsRoot():
            self.btnDirBack.enabled = 0

        s = self._state()
        self.txtLocation.text = currDir + s.dirOne + s.dirTwo + s.dirThree

        self._updating = 0

    def changeDirs(self, event):
        print ">> Got event: ", event
        print ">> event dict: ", event.__dict__

    def applyFilter(self, event):
        #print ">> Got event: ", event
        #print ">> event dict: ", event.__dict__
        self._update = 1

        dirMngr = self.dirMngr
        s = self._state()

        try:
            s.dirThree
            #print '>> filtering lbxThree'
            self.handleLbxDirTwoEvent()
            return
        except (AttributeError):
            pass

        try:
            s.dirTwo
            #print '>> filtering lbxTwo'
            self.handleLbxDirOneEvent()
            return
        except (AttributeError):
            pass

        #print '>> filtering lbxOne'
        dirMngr.filter = self.cbxFilter.text
        dirMngr.update()

        s.lbxOne.items = dirMngr.currDirCache
        try:
            selection = s.lbxOne.selection = dirMngr.currDirCache.index(s.dirOne)
            self.txtLocation.text = dirMngr.currDir + dirMngr.currDirCache[selection]
        except (AttributeError, ValueError):
            traceback.print_exc()
            self.txtLocation.text = dirMngr.currDir

        self.btnDirFwd.enabled = 0

        self._update = 0

    def _state(self):

        class State:
            def __str__(self):
                return str(self.__dict__)
            pass

        s = State()

        s.lbxOne   = self.lbxDirOne
        s.itemsOne = s.lbxOne.items
        s.selOne   = s.lbxOne.selection

        try:
            s.dirOne   = s.lbxOne.items[s.selOne]

            s.lbxTwo   = self.lbxDirTwo
            s.itemsTwo = s.lbxTwo.items
            s.selTwo   = s.lbxTwo.selection
            s.dirTwo   = s.lbxTwo.items[s.selTwo]

            s.lbxThree   = self.lbxDirThree
            s.itemsThree = s.lbxThree.items
            s.selThree   = s.lbxThree.selection
            s.dirThree   = s.lbxThree.items[s.selThree]
        except (IndexError):
            pass

        return s



-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf