commit-gnue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

r5757 - in trunk/gnue-forms: samples samples/tree src src/GFObjects src/


From: florin
Subject: r5757 - in trunk/gnue-forms: samples samples/tree src src/GFObjects src/uidrivers/wx/widgets
Date: Sat, 24 Apr 2004 16:49:58 -0500 (CDT)

Author: florin
Date: 2004-04-24 16:49:57 -0500 (Sat, 24 Apr 2004)
New Revision: 5757

Added:
   trunk/gnue-forms/samples/tree/
   trunk/gnue-forms/samples/tree/README
   trunk/gnue-forms/samples/tree/tree.gfd
   trunk/gnue-forms/src/GFObjects/GFColsrc.py
   trunk/gnue-forms/src/GFObjects/GFColumn.py
   trunk/gnue-forms/src/GFObjects/GFLeaf.py
   trunk/gnue-forms/src/GFObjects/GFTree.py
   trunk/gnue-forms/src/uidrivers/wx/widgets/tree.py
Modified:
   trunk/gnue-forms/src/GFObjects/__init__.py
   trunk/gnue-forms/src/GFParser.py
Log:
added tree widget support (wx only for now...)


Added: trunk/gnue-forms/samples/tree/README
===================================================================
--- trunk/gnue-forms/samples/tree/README        2004-04-21 14:42:03 UTC (rev 
5756)
+++ trunk/gnue-forms/samples/tree/README        2004-04-24 21:49:57 UTC (rev 
5757)
@@ -0,0 +1,5 @@
+This is a GFD for testing the gnue tree widget.
+You might need to change it to match your DB design.
+Sorry, that's all I can do for you now... :-(
+
+Florin Boariu <address@hidden>
\ No newline at end of file

Added: trunk/gnue-forms/samples/tree/tree.gfd
===================================================================
--- trunk/gnue-forms/samples/tree/tree.gfd      2004-04-21 14:42:03 UTC (rev 
5756)
+++ trunk/gnue-forms/samples/tree/tree.gfd      2004-04-24 21:49:57 UTC (rev 
5757)
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="iso8859-1"?>
+
+<!--  GNUe-Designer (0.5.3.99)
+      Saved on: 2004-03-17 22:07:45  -->
+
+<form>
+  <options/>
+
+  <datasource name="dtsProdtype" connection="borg_test" primarykey="id" 
table="prodtype"/>
+  <datasource name="dtsPerson"   connection="borg_test" primarykey="id" 
table="person"/>
+  <datasource name="dtsCurrency" connection="borg_test" primarykey="id" 
table="currency"/>
+
+  <logic>
+    <block name="blkProdtype" datasource="dtsprodtype" rows="1">
+      <field name="fldId" field="id" required="Y" typecast="number"/>
+      <field name="fldDescription" field="description"/>
+      <field name="fldParent_id" field="parent_id" typecast="number"/>
+      <field name="fldInfo_table" field="info_table"/>
+      <field name="fldInfo_id" field="info_id" typecast="number"/>
+    </block>
+   
+    <block name="blkPerson" datasource="dtsperson" rows="1">
+      <field name="fldId" field="id"/>
+      <field name="fldName" field="name"/>
+    </block>
+
+    <block name="blkCurrency" datasource="dtscurrency" rows="1">
+      <field name="fldId" field="id"/>
+      <field name="fldShort_name" field="short_name"/>
+      <field name="fldLong_name" field="long_name"/>
+    </block>
+
+  </logic>
+  <layout xmlns:Char="GNUe:Layout:Char" Char:height="12" Char:width="45">
+    <page name="Page">
+      <entry name="ntryDescription" block="blkProdtype" field="fldId"
+             Char:x="0" Char:y="1" Char:width="2" Char:height="1"/>
+
+      <entry name="ntryName" block="blkPerson" field="fldName"
+             Char:x="3" Char:y="0" Char:width="20" Char:height="1" 
style="label"
+             hidden="false"/>
+
+      <entry name="ntryLong_name" block="blkCurrency" field="fldLong_name"
+             Char:x="3" Char:y="1" Char:width="20" Char:height="1" 
style="label"
+             hidden="false"/>
+
+      <tree name="treeProd" block="blkProdtype"
+            fld_tblhint="fldInfo_table" fld_desc="fldDescription"
+            fld_id="fldId" fld_parentid="fldParent_id"
+            Char:height="11" Char:width="40" Char:x="3" Char:y="2">
+
+       <trigger type="POST-KIDSCHANGED" name="trigChanged"><![CDATA[
+#
+# composing first column entry for tree-nodes: ID sum of leaf-entries
+#
+node = treeProd.getIncompleteNode()
+sum = 0
+print "parent: ", node.desc
+for item in node.children:
+  print "  child: ", item.desc
+  sum = sum + item.columns[0]
+node.columns[0] = sum
+treeProd.popIncompleteNode()
+
+]]></trigger>
+
+        <column name="id"   align="right" field="fldId"/>
+        <column name="desc" align="left"  field="fldDescription"/>
+
+        <leaf name="lfPerson" block="blkPerson" tblhint="person"
+              fld_desc="fldName" fld_id="fldId">
+               <colsrc covers="id"   field="fldId"/>
+               <colsrc covers="desc" field="fldName"/>
+        </leaf>
+
+        <leaf name="lfCurrency" block="blkCurrency" tblhint="currency"
+              fld_desc="fldLong_name" fld_id="fldId">
+               <colsrc covers="id" field="fldId"/>
+               <colsrc covers="desc" field="fldShort_name"/>
+        </leaf>
+
+      </tree>
+    </page>
+  </layout>
+</form>

Added: trunk/gnue-forms/src/GFObjects/GFColsrc.py
===================================================================
--- trunk/gnue-forms/src/GFObjects/GFColsrc.py  2004-04-21 14:42:03 UTC (rev 
5756)
+++ trunk/gnue-forms/src/GFObjects/GFColsrc.py  2004-04-24 21:49:57 UTC (rev 
5757)
@@ -0,0 +1,59 @@
+#
+# This file is part of GNU Enterprise.
+#
+# GNU Enterprise is free software; you can redistribute it 
+# and/or modify it under the terms of the GNU General Public 
+# License as published by the Free Software Foundation; either 
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be 
+# useful, but WITHOUT ANY WARRANTY; without even the implied 
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright 2000-2004 Free Software Foundation
+#
+#
+# FILE:
+# GFColumn.py
+#
+# DESCRIPTION:
+"""
+Column data source information for GFLeaf
+"""
+# NOTES:
+#
+
+from GFValue import GFValue
+from GFObj import GFObj
+import string
+
+#
+# GFColsrc
+#
+class GFColsrc (GFObj):
+  def __init__(self, parent=None):
+    GFObj.__init__(self, parent, 'GFColsrc')
+
+    # Runtime Variables
+    self._inits = [self.initialize]
+
+  def _buildObject(self):
+    return GFObj._buildObject(self)
+
+  #
+  # Routines called during a phaseInit
+  #
+  def initialize(self):
+    self._form = self.findParentOfType ('GFForm')
+    self._leaf = self.findParentOfType ('GFLeaf')
+ 
+    self._leaf._colsrcList.append (self)
+    self._leaf._colsrcMap[self.covers] = self
+    print "added colsrc for: ", self.covers
+

Added: trunk/gnue-forms/src/GFObjects/GFColumn.py
===================================================================
--- trunk/gnue-forms/src/GFObjects/GFColumn.py  2004-04-21 14:42:03 UTC (rev 
5756)
+++ trunk/gnue-forms/src/GFObjects/GFColumn.py  2004-04-24 21:49:57 UTC (rev 
5757)
@@ -0,0 +1,59 @@
+#
+# This file is part of GNU Enterprise.
+#
+# GNU Enterprise is free software; you can redistribute it 
+# and/or modify it under the terms of the GNU General Public 
+# License as published by the Free Software Foundation; either 
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be 
+# useful, but WITHOUT ANY WARRANTY; without even the implied 
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright 2000-2004 Free Software Foundation
+#
+#
+# FILE:
+# GFColumn.py
+#
+# DESCRIPTION:
+"""
+Column information for GFTree
+"""
+# NOTES:
+#
+
+from GFValue import GFValue
+from GFObj import GFObj
+import string
+
+#
+# GFColumn
+#
+class GFColumn (GFObj):
+  def __init__(self, parent=None):
+    GFObj.__init__(self, parent, 'GFColumn')
+
+    # Runtime Variables
+    self._inits = [self.initialize]
+
+  def _buildObject(self):
+    return GFObj._buildObject(self)
+
+  #
+  # Routines called during a phaseInit
+  #
+  def initialize(self):
+    self._form = self.findParentOfType ('GFForm')
+    self._tree = self.findParentOfType ('GFTree')
+ 
+    self._tree._colList.append (self)
+    #self._tree._colMap[self.name] = self
+    print "added column: ", self.name
+

Added: trunk/gnue-forms/src/GFObjects/GFLeaf.py
===================================================================
--- trunk/gnue-forms/src/GFObjects/GFLeaf.py    2004-04-21 14:42:03 UTC (rev 
5756)
+++ trunk/gnue-forms/src/GFObjects/GFLeaf.py    2004-04-24 21:49:57 UTC (rev 
5757)
@@ -0,0 +1,66 @@
+#
+# This file is part of GNU Enterprise.
+#
+# GNU Enterprise is free software; you can redistribute it 
+# and/or modify it under the terms of the GNU General Public 
+# License as published by the Free Software Foundation; either 
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be 
+# useful, but WITHOUT ANY WARRANTY; without even the implied 
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright 2000-2004 Free Software Foundation
+#
+#
+# FILE:
+# GFTree.py
+#
+# DESCRIPTION:
+"""
+Leaf support (sub-tree pointing to another table)
+"""
+# NOTES:
+#
+
+from GFValue import GFValue
+from GFObj import GFObj
+import string
+
+#
+# GFLeaf
+#
+class GFLeaf (GFObj):
+  def __init__(self, parent=None):
+    GFObj.__init__(self, parent, 'GFLeaf')
+
+    # Runtime Variables
+    self._inits = [self.initialize]
+
+    self._colsrcMap = {}    # column source information
+    self._colsrcList = []   # column source information
+
+  def _buildObject(self):
+    if not hasattr(self, 'rows') and hasattr(self,'visibleCount'):
+      self.rows = self.visibleCount
+      del self.visibleCount
+    return GFObj._buildObject(self)
+
+  #
+  # Routines called during a phaseInit
+  #
+  def initialize(self):
+    if hasattr (self, 'block'):
+      self._form = form = self.findParentOfType ('GFForm')
+      self._tree =        self.findParentOfType ('GFTree')
+      self._blk = form._logic._blockMap[self.block]
+
+    if hasattr (self, 'tblhint'):
+      self._tree._leafMap[self.tblhint] = self
+

Added: trunk/gnue-forms/src/GFObjects/GFTree.py
===================================================================
--- trunk/gnue-forms/src/GFObjects/GFTree.py    2004-04-21 14:42:03 UTC (rev 
5756)
+++ trunk/gnue-forms/src/GFObjects/GFTree.py    2004-04-24 21:49:57 UTC (rev 
5757)
@@ -0,0 +1,453 @@
+#
+# This file is part of GNU Enterprise.
+#
+# GNU Enterprise is free software; you can redistribute it 
+# and/or modify it under the terms of the GNU General Public 
+# License as published by the Free Software Foundation; either 
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be 
+# useful, but WITHOUT ANY WARRANTY; without even the implied 
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright 2000-2004 Free Software Foundation
+#
+#
+# FILE:
+# GFTree.py
+#
+# DESCRIPTION:
+"""
+Logical tree support
+"""
+# NOTES:
+#
+
+from GFValue import GFValue
+from GFObj import GFObj
+from gnue.common import events
+from gnue.forms import GFDisplayHandler
+from GFBlock import GFBlock
+import string
+import copy
+
+#
+# internal tree node representation
+#
+class TreeNode:
+  def __init__(self, parent=None):
+    self.desc     = "n/a"    # description -- will appear in the tree view
+    self.id       = 0        # database ID -- may be used to find the selected 
value in the DB
+    self.parent   = parent   # parent node
+    self.children = []       # children list (to spawn a subtree)
+    self.columns  = []       # values of the columns
+    self.leaf     = None     # GFLeaf reference
+    self.srcinfo  = None     # reference to info struct in GFTree._infoMap
+    self.recno    = 0        # record number in the block
+    self._ui_obj = None      # this one will be set to the TreeItem obj by the 
UI
+
+  def getUiObj (self):
+    return self._ui_obj
+
+  def setUiObj (self, obj=None):
+    self._ui_obj = obj
+
+#
+# will hold information on the various sources (GFBlocks)
+# and column namings.
+#
+class NodeInfo:
+  def __init__(self):
+    self.block = None      # the block we represent
+    self.fld_id = ""       # ID field (primary key)
+    self.fld_desc = ""     # Description field (Human readable)
+    self.fld_query = ""    # Query field
+    self.pat_query = None  # Query pattern
+
+#
+# GFTree
+#
+class GFTree (GFObj):
+  def __init__(self, parent=None):
+    GFObj.__init__(self, parent, 'GFTree')
+
+    # Default attributes (these may be replaced by parser)
+    self.Char__height = int(gConfigForms('widgetHeight'))
+
+    # Runtime Variables
+    self._inits = [self.initialize]
+
+    self._treeRoot = TreeNode() # here's our internal tree representation
+    self._leafMap = {}          # block information for other tables (leaves)
+    self._colList = []          # column information for main tree
+
+    self._infoMap = {}          # saves information on tree/leaves 
sources/fields/blocks
+
+    self._incompleteNodes = []  # nodes that don't have columns yet set (but 
their kids have)
+
+    self._loadList = []         # root items we have to load kids for (i.e. on 
IdleEvent)
+
+    # note on columns:
+    # the ListView right next to the tree will hold
+    # be updated OnSelect to contain all children of
+    # the current selection. (alternative: update it
+    # to give the feel of an Qt-ListView
+    # (multi-column tree-view)
+
+    # note on leaves:
+    # leaves should have an attribute "big" or "don't show in tree"
+    # or whatever. it should prevent the items of a leafnode
+    # from being loaded into the tree and instead only be shown
+    # in the ListView (which might be implemented to have a decent
+    # caching). 'normal' tree items (no leafnodes) are assumed to be
+    # "small" (loadable in one single step, no caching needed...)
+
+    # operations on big leaves (like computation/loading of several
+    # columns) should be done in idleEvents.
+
+    # still need to specify decent column info
+
+    # trigger stuff
+    self._validTriggers = {
+               'ON-SELECTED':      'On-Selected',
+               'POST-KIDSCHANGED': 'Post-KidsChanged'
+       }
+
+    self._triggerGlobal = 1
+    self._triggerFunctions = {
+                       'setNodeCol':        { 'function': self._trigSetNodeCol 
},
+                       'getIncompleteNode': { 'function': 
self._trigGetIncompleteNode },
+                        'popIncompleteNode': { 'function': 
self._trigPopIncompleteNode }
+               }
+   
+    #self._triggerProperties = {'name': {'get': self.getName} }
+
+  #
+  # builds _infoMap structure
+  #
+  def _buildInfoMap (self):
+    ## tree nodes info
+    i = NodeInfo()
+    i.block     = self._blk
+    i.fld_id    = self.fld_id
+    i.fld_desc  = self.fld_desc
+    i.fld_query = self.fld_parentid
+    i.pat_query = ''   # this only goes for the root node! FIXME!
+    self._infoMap[self.name] = i
+
+    ## leaf nodes info
+    for leaf in self._leafMap.values():
+      info = NodeInfo()
+      info.block     = leaf._blk
+      info.fld_id    = leaf.fld_id
+      info.fld_desc  = leaf.fld_desc
+      info.fld_query = leaf.fld_id
+      info.pat_query = '*'
+      self._infoMap[leaf.name] = info
+
+  #
+  # returns the currently changing (i.e. no-column-values-set-yet) node
+  #
+  def _trigGetIncompleteNode (self):
+    if not self._incompleteNodes:
+      return None
+    else:
+      return self._incompleteNodes[0]
+
+  #
+  # pops the next incomplete node from the incomplete-list (-> node is 
"complete" now)
+  #
+  def _trigPopIncompleteNode (self):
+    self._incompleteNodes.pop (0)
+  
+  #
+  # sets the column text for the current node
+  #
+  def _trigSetNodeCol (self, col, val):
+    pass
+
+  def _buildObject(self):
+    if not hasattr(self, 'rows') and hasattr(self,'visibleCount'):
+      self.rows = self.visibleCount
+      del self.visibleCount
+    return GFObj._buildObject(self)
+
+  #
+  # Routines called during a phaseInit
+  #
+  def initialize(self):
+    if hasattr (self, 'block'):
+      self._form = form = self.findParentOfType ('GFForm')
+      self._orig_blk = form._logic._blockMap[self.block]
+      self._blk = self._orig_blk
+      
+      # bad attempt to make a copy of a block... :-(
+      #self._blk = copy.copy (self._orig_blk)
+      #self._blk.initialize()
+
+    self.evtCtrl = self._form._instance.eventController
+    self.evtCtrl.registerEventListeners ({
+               'uitreeItemSelected':  self._onItemSelected,
+               'uitreeItemExpanded':  self._onItemExpanded,
+               'uitreeItemCollapsed': self._onItemCollapsed
+       })
+  
+  #
+  # OnExpand handler. params: node
+  #
+  def _onItemExpanded (self, event):
+    pass
+
+  #
+  # OnCollapse handler. params: node (surprise :-)
+  #
+  def _onItemCollapsed (self, event):
+    pass
+
+  #
+  # OnSelect handler. params: cursel, lastsel
+  #
+  def _onItemSelected (self, event):
+    try:
+      blk = event.cursel.parent.leaf._blk
+      blk.jumpRecord (event.cursel.recno)
+      blk = event.lastsel.parent.leaf._blk
+    except AttributeError:
+      pass
+
+    self.processTrigger ('ON-SELECTED')
+
+  #
+  # build tree from DB
+  #
+  def buildTree (self):
+
+    self._buildInfoMap()
+
+    self._treeRoot.id      = 0
+    self._treeRoot.desc    = "kick me!"
+    self._treeRoot.srcinfo = self._infoMap[self.name]
+
+    #self.__populate_tree (self._treeRoot)
+
+    self.__pop_query (self._treeRoot, 0)
+    self.__pop_load_init (self._treeRoot)
+    self.__pop_load_part (self._treeRoot, -1)
+    self.__pop_load_finish (self._treeRoot)
+
+    return self._treeRoot
+
+  #
+  # wrapper function for __populate_base
+  # to populate tree nodes
+  #
+  def __populate_tree (self, rootnode):
+    self.__populate_base (rootnode, self._blk,
+                          self.fld_id, self.fld_desc,
+                          self.fld_parentid, rootnode.id)
+
+  # wrapper function for __populate_base
+  # to populate leaf nodes
+  def __populate_leaf (self, rootnode):
+    leaf = rootnode.leaf
+    self.__populate_base (rootnode, leaf._blk,
+                          leaf.fld_id, leaf.fld_desc,
+                          leaf.fld_id, '*')
+ 
+  #
+  # starts query for items to populate a (sub)tree with.
+  # parameters:
+  #   rootnode:  the root node
+  #   pat_query: select pattern
+  #
+  def __pop_query (self, rootnode, val_query): 
+    blk = rootnode.srcinfo.block
+    fld_query = blk._fieldMap[rootnode.srcinfo.fld_query]
+    #print "query for ", rootnode.srcinfo.fld_query, "=", val_query
+    blk.initQuery()
+    fld_query.setValue (val_query)
+    blk.processQuery()
+
+  #
+  # initializes load phase for tree items
+  # parameters:
+  #   rootnode: root node to add items to
+  #
+  def __pop_load_init (self, rootnode):
+    rootnode.srcinfo.block.firstRecord()
+    self._loadList.append (rootnode)
+
+  #
+  # loads given number of tree items (call __pop_load_init first!)
+  # nr: maximum number of items to read
+  # returns the number of items actually loaded
+  #
+  def __pop_load_part (self, rootnode, nr):
+    blk      = rootnode.srcinfo.block
+    fld_id   = blk._fieldMap[rootnode.srcinfo.fld_id]
+    fld_desc = blk._fieldMap[rootnode.srcinfo.fld_desc]
+
+    total   = nr
+    do_loop = not blk._resultSet.isLastRecord()
+
+    while nr != 0 and do_loop:
+      ## main item stuff
+      node_data = TreeNode (rootnode)
+      node_data.id       = fld_id.getValue()
+      node_data.desc     = fld_desc.getValue()
+      node_data.children = []
+      node_data.recno    = blk._currentRecord
+      node_data.columns  = []
+      node_data.leaf     = None
+      node_data.srcinfo  = self._infoMap[self.name] # goes for tree nodes
+
+      ## column stuff (pretty clumsy... still waiting for enlightenment)
+      if blk == self._blk:        # if this is tree-node (!= leaf-node)...
+        leaf_tbl = blk._fieldMap[self.fld_tblhint].getValue()
+        if leaf_tbl:
+          node_data.leaf    = self._leafMap[leaf_tbl]
+          node_data.srcinfo = self._infoMap[node_data.leaf.name]
+        for ci in self._colList:  # add columns to the tree item
+          node_data.columns.append (blk._fieldMap[ci.field].getValue())
+      else:
+        #node_data.srcinfo = self._infoMap[node_data.leaf.name]
+        for ci in self._colList:  # add column to a leaf
+          colsrc = rootnode.leaf._colsrcMap[ci.name]
+          node_data.columns.append (blk._fieldMap[colsrc.field].getValue())
+
+      rootnode.children.append (node_data)
+      
+      ## while-loop stuff
+      nr = nr - 1
+      do_loop = not blk._resultSet.isLastRecord()
+      blk.nextRecord()
+
+    # while-loop ends.
+
+    self.evtCtrl.dispatchEvent (events.Event ('gftreeAppendKids',
+                            root=rootnode, kids=rootnode.children,
+                            _form=self._form))
+
+    return total-nr
+
+  #
+  # ends load phase for tree items
+  #
+  def __pop_load_finish (self, rootnode):
+    self._loadList.remove (rootnode)
+
+    ## populate sub-trees/leaves
+    if rootnode.srcinfo.block == self._blk:    # if this is _not_ a leaf-list
+      for n in rootnode.children:
+        pat = '*'
+        if n.leaf == None: pat = n.id
+        self.__pop_query (n, pat)
+        self.__pop_load_init (n)
+        self.__pop_load_part (n, -1)
+
+    # trigger KidsChanged -- that should fill in column values for tree nodes
+    if rootnode != self._treeRoot:
+      self._incompleteNodes.append (rootnode)
+      self.processTrigger ('POST-KIDSCHANGED')
+
+  #
+  # aborts load phase for tree items
+  #
+  def __pop_load_cancel (self, rootnode, blk):
+    pass
+
+  #
+  # functions populates list subnode 'rootnode' with
+  # items from DB with items in the DB that have parent id 'rootid'
+  #
+  # (or populates with items from another table that match the
+  #  val_query in fld_query => leafnodes)
+  #
+  # fld_id:    ID field (primary key). will be used to jump to records (??)
+  # fld_desc:  human readable information field
+  # fld_query: "use it or not"-decision information field
+  # val_query: "use it or nor"-decision query string
+  # blk:       block to use
+  # rootnode:  root node to insert items into (see above for type)
+  #
+  def __populate_base (self, rootnode, blk, fld_id, fld_desc, fld_query, 
val_query):
+
+    blk.initQuery()
+    blk._fieldMap[fld_query].setValue (val_query)
+    blk.processQuery()
+   
+    blk.firstRecord()
+    go = not blk._resultSet.isLastRecord()
+    while go == True:
+      item = blk
+      node_data = TreeNode (rootnode)
+      node_data.desc     = item._fieldMap[fld_desc].getValue()
+      node_data.id       = item._fieldMap[fld_id].getValue()
+      node_data.parent   = rootnode
+      node_data.children = []
+      node_data.columns  = []
+      node_data.recno    = blk._currentRecord
+      node_data.leaf     = None
+
+      # if this is a leafnode (main tree item which
+      # spawns a sub-tree from another table)
+      if blk == self._blk:
+        leaf_tbl = item._fieldMap[self.fld_tblhint].getValue()
+        if leaf_tbl:
+          node_data.leaf = self._leafMap[leaf_tbl]
+        
+        # load column information for tree-nodes and leaf-nodes
+        for ci in self._colList:
+          node_data.columns.append (item._fieldMap[ci.field].getValue())
+
+      else:
+
+        # load columns for leaf-ends
+       #for ci in rootnode.leaf._colsrcList:
+        #  node_data.columns.append (item._fieldMap[ci.field].getValue())
+        for ci in self._colList:
+          colsrc = rootnode.leaf._colsrcMap[ci.name]
+          node_data.columns.append (item._fieldMap[colsrc.field].getValue())
+
+      rootnode.children.append (node_data)
+
+      go = not blk._resultSet.isLastRecord()
+      if go:
+         blk.nextRecord()
+
+    # end 'while'
+    
+    self.evtCtrl.dispatchEvent (events.Event ('gftreeAppendKids',
+                                root=rootnode, kids=rootnode.children,
+                                _form=self._form))
+
+    ## populate sub-trees/leaves
+    if blk == self._blk:
+      for n in rootnode.children:
+        if n.leaf == None:
+          self.__populate_tree (n)
+        else:
+          self.__populate_leaf (n)
+
+    # trigger KidsChanged -- that should fill in column values for tree nodes
+    if rootnode != self._treeRoot:
+      self._incompleteNodes.append (rootnode)
+      self.processTrigger ('POST-KIDSCHANGED')
+
+  #
+  # removes the children of a node (and sends rm event to ui)
+  # 
+  def __remove_kids (self, rootnode):
+    for item in rootnode.children:
+      if item.children:
+        self.__remove_kids (item)
+    self.evtCtrl.dispatchEvent (events.Event ('gftreeRemoveKids',
+                                root=rootnode, _form=self._form))
+    for item in rootnode.children:
+      rootnode.children.remove (item)

Modified: trunk/gnue-forms/src/GFObjects/__init__.py
===================================================================
--- trunk/gnue-forms/src/GFObjects/__init__.py  2004-04-21 14:42:03 UTC (rev 
5756)
+++ trunk/gnue-forms/src/GFObjects/__init__.py  2004-04-24 21:49:57 UTC (rev 
5757)
@@ -31,6 +31,10 @@
         "GFOption",
         "GFScrollBar",
         "GFBox",
+        "GFTree",
+        "GFLeaf",
+        "GFColumn",
+        "GFColsrc",
         "GFOptions",
         "GFValue",
         "GFButton",

Modified: trunk/gnue-forms/src/GFParser.py
===================================================================
--- trunk/gnue-forms/src/GFParser.py    2004-04-21 14:42:03 UTC (rev 5756)
+++ trunk/gnue-forms/src/GFParser.py    2004-04-24 21:49:57 UTC (rev 5757)
@@ -688,6 +688,111 @@
          'ParentTags': ('page',),
          'Description': 'TODO' },
 
+     'tree': {
+         'BaseClass': GFObjects.GFTree,
+         'Attributes': {
+            'name': {
+               'Unique': True,
+               'Typecast': GTypecast.name,
+               'Description': 'Tree Widget.' },
+            'rows': {
+               'Typecast': GTypecast.whole,
+               'Description': 'Overrides the rows setting defined at the block 
level. ' },
+            'rowSpacer': {
+               'Typecast': GTypecast.whole,
+               'Label': _('Row Spacing'),
+               'Description': 'Overriders the rowSpace setting defined at the 
block level.' },
+             'block': {
+               'Typecast': GTypecast.name,
+               'Required': True,
+               'References': 'block.name',
+               'Description': 'The name of the block the tree ties to.' },
+            'fld_desc': {
+               'Label': _('Description field'),
+               'Typecast': GTypecast.name,
+               'Required': True,
+               'Description': 'The visible text of the TreeViewItem' },
+            'fld_id': {
+               'Label': _('Own ID field'),
+               'Typecast': GTypecast.name,
+               'Required': True,
+               'Description': 'The field containing the TreeViewItem ID' },
+            'fld_parentid': {
+               'Label': _('Parent ID field'),
+               'Typecast': GTypecast.name,
+               'Required': True,
+               'Description': 'The field containing the TreeViewItem parent' },
+            'fld_tblhint': {
+               'Label': _('Table hint for leaf tables'),
+               'Typecast': GTypecast.name,
+               'Required': True,
+               'Description': 'The field containing the table-hint for leaves' 
} },
+           'Positionable': True,
+           'ParentTags': ('page',),
+           'Description': 'Tree/List-View of a table' },
+
+      'leaf': {
+         'BaseClass': GFObjects.GFLeaf,
+         'Attributes': {
+            'name': {
+               'Unique': True,
+               'Typecast': GTypecast.name,
+               'Description': 'Leaf of the Tree Widget' },
+            'block': {
+               'Typecast': GTypecast.name,
+               'Required': True,
+               'References': 'block.name',
+               'Description': 'Block used for db operations' },
+            'fld_id': {
+               'Label': _('ID of a field'),   # TODO: we need some kind of 
restriction
+               'Typecast': GTypecast.name,    # TODO: on which entries we 
pick...
+               'Required': True },
+            'fld_desc': {
+               'Label': _('Description field'),
+               'Typecast': GTypecast.name,
+               'Required': True },
+            'tblhint': {
+               'Typecast': GTypecast.name,
+               'Required': True,
+               'Description': 'Table of this leaf' } },
+         'Positionable': True,
+         'ParentTags': ('tree',),
+         'Description': 'Leaf information of a tree view' },
+
+      'column': {
+        'BaseClass': GFObjects.GFColumn,
+          'Attributes': {
+             'name': {
+               'Unique': True,
+               'Required': True,
+               'Typecast': GTypecast.name,
+               'Description': 'Column info for leaves/trees' },
+             'align': {
+               'Typecast': GTypecast.name,
+               'Required': True,
+               'Description': 'Contents alignment: left/right/center' },
+             'field': {  # we'll have to remove this, or replace it with some 
more general source
+               'Typecast': GTypecast.name,
+               'Description': 'Field to get column text from' } },
+          'Positionable': False,
+          'ParentTags': ('tree',),
+          'Descrpition': 'Column information for trees' },
+
+      'colsrc': {
+        'BaseClass': GFObjects.GFColsrc,
+          'Attributes': {
+             'covers': {
+               'Unique': True,
+               'Required': True,
+               'Typecast': GTypecast.name,
+               'Description': 'Specifies the column this belongs to' },
+             'field': {
+               'Typecast': GTypecast.name,
+               'Description': 'Field to get column text from' } },
+          'Positionable': False,
+          'ParentTags': ('leaf',),
+          'Descrpition': 'Column information for trees' },
+
       'options': {
          'BaseClass': GFObjects.GFOptions,
          'UsableBySiblings': True,

Added: trunk/gnue-forms/src/uidrivers/wx/widgets/tree.py
===================================================================
--- trunk/gnue-forms/src/uidrivers/wx/widgets/tree.py   2004-04-21 14:42:03 UTC 
(rev 5756)
+++ trunk/gnue-forms/src/uidrivers/wx/widgets/tree.py   2004-04-24 21:49:57 UTC 
(rev 5757)
@@ -0,0 +1,227 @@
+#
+# This file is part of GNU Enterprise.
+#
+# GNU Enterprise is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation; either
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright 2000-2004 Free Software Foundation
+#
+# FILE:
+# UIwxpython.py
+#
+# DESCRIPTION:
+# A wxPython based user interface driver for GNUe forms.
+#
+# NOTES:
+#
+from wxPython.wx import *
+
+from gnue.forms.uidrivers.wx.widgets._base import UIHelper
+from gnue.forms.uidrivers.wx.common import wxEncode
+from gnue.common import events
+from gnue.forms.uidrivers.wx.common import _eventObjTowxWindow, wxEncode, 
wxDecode
+from types import *
+
+import thread
+
+import string
+
+#
+# UITree
+#
+# Widget set specific function that creates a single instance of a tree
+#
+class UITree(UIHelper):
+
+  def _createWidget(self, event, spacer):
+    self._gftree = object = event.object
+    app = wx.wxGetApp()
+    self._eventHandler = self._sendEvt = event.eventHandler
+    self.evtCtrl = object._form._instance.eventController
+
+    self.splitter = wxSplitterWindow (event.container, -1,
+                                      wxPoint (object.Char__x * 
event.widgetWidth,
+                                      (object.Char__y + spacer + 
(spacer*object._gap)) * event.widgetHeight),
+                                      wxSize (self.itemWidth, self.itemHeight))
+
+    self.treeWg = wxTreeCtrl (self.splitter, -1)
+    self.listWg = wxListCtrl (self.splitter, -1, wxPoint (0, 0), wxSize (0, 0),
+                              wxLC_REPORT | wxLC_SINGLE_SEL)
+    self.listWg_root = None    # root TreeNode of the current GFTree selection
+    
+    self.splitter.SplitVertically (self.treeWg, self.listWg)
+    self.splitter.SetMinimumPaneSize (20)
+
+    EVT_TREE_SEL_CHANGED (app, self.treeWg.GetId(),    self._onTreeSelected)
+    EVT_TREE_ITEM_ACTIVATED (app, self.treeWg.GetId(), self._onTreeActivated)
+    EVT_TREE_ITEM_EXPANDED (app, self.treeWg.GetId(),  self._onTreeExpanded)
+    EVT_TREE_ITEM_COLLAPSED (app, self.treeWg.GetId(), self._onTreeCollapsed)
+
+    EVT_LIST_ITEM_SELECTED (app, self.listWg.GetId(), self._onListSelected)
+
+    #EVT_IDLE (self.treeWg, self.__onIdle)
+
+    self.evtCtrl.registerEventListeners ({
+               'gftreeItemSelected': self._gfItemSelected,
+               'gftreeAppendKids':   self._gfAppendKids,
+               'gftreeRemoveKids':   self._gfRemoveKids
+               #'gftreeDetailView':   self._gfDetailView
+       })
+
+    object.buildTree()
+
+    wx_align = {'left': wxLIST_FORMAT_LEFT,
+                'center': wxLIST_FORMAT_CENTER,
+                'right': wxLIST_FORMAT_RIGHT }
+
+    # insert description column -- this col is actually not part of
+    # the XML widget description. it is a work-around for missing
+    # column support in wx-treeviews (as is this whole treeview/listview
+    # thingy)
+    self.listWg.InsertColumn (0, _("Node"))
+    cnr = 1
+    for col in object._colList:
+      self.listWg.InsertColumn (cnr, col.name, wx_align[col.align])
+      cnr = cnr + 1
+
+    return self.treeWg
+
+  #
+  # shows the kids of the selected node in TreeView in the ListView
+  #
+  def showDetail (self, node):
+    self.listWg.DeleteAllItems()
+    nr = 0
+    self.listWg_root = node
+    
+    # go though the children
+    for item in node.children:
+      self.listWg.InsertStringItem (nr, item.desc)
+  
+      # add default column -- we always have this one as first column :-)
+      self.listWg.SetStringItem (nr, 0, item.desc)
+      
+      # add column labels for current item
+      cnr = 1
+      for col in item.columns:
+        label = "n/a"
+        if isinstance(col, UnicodeType):
+          label = wxEncode (col)
+        else:
+          label = str (col)
+        self.listWg.SetStringItem (nr, cnr, label)
+        cnr = cnr + 1
+
+      nr = nr + 1
+
+  #
+  # called by gfobj after (sub)tree items are added and need to be displayed
+  #
+  def _gfAppendKids (self, event):
+    if not event.root.getUiObj(): # we don't have a root node... adding it.
+      wxroot = self.treeWg.AddRoot (event.root.desc)
+      self.treeWg.SetPyData (wxroot, event.root)
+      event.root.setUiObj (ui_info (wxroot))
+
+    root = event.root.getUiObj().tree_item
+    old = self.treeWg.GetChildrenCount (root, False)
+
+    for gfi in event.kids[old:]:
+      wxi = self.treeWg.AppendItem (root, gfi.desc)
+      self.treeWg.SetPyData (wxi, gfi)
+      gfi.setUiObj (ui_info(wxi))
+  
+  #
+  # called by gfobj before (sub)tree items are deleted and need to be erased
+  #
+  def _gfRemoveKids (self, event):
+    for gfi in event.root.children:
+      self.treeWg.SetPyData (gfi.getUiObj().tree_item, None)
+
+    self.treeWg.DeleteChildren (event.root.getUiObj().tree_item)
+  
+  def _gfItemSelected (selv, event):
+    print "gf item selected!"
+
+  def _onIdle(self, event):
+    pass
+ 
+  #
+  # list selected -- select same item in TreeView
+  #
+  def _onListSelected (self, event):
+    node = self.listWg_root.children[event.GetIndex()]
+    tsel = self.treeWg.GetSelection()
+    if tsel and self.treeWg.GetPyData(tsel) != node:
+      self.treeWg.SelectItem (node.getUiObj().tree_item)
+
+  #
+  # called when user selects an item -- passes event to gfobj
+  # 
+  def _onTreeSelected (self, event):
+
+    csel = self.treeWg.GetPyData (event.GetItem())
+
+    if csel.children:                      # build detail list
+      self.showDetail (csel)
+    else:                                  # select item in already built 
detail list
+      if csel.parent != self.listWg_root:  # user switched to another leafnode
+        self.showDetail (csel.parent)      # => rebuild detail list
+      pass  # wxListCtrl won't give me any function to change selection :-(
+
+    self._sendEvt (events.Event ('uitreeItemSelected',
+                   cursel  = self.treeWg.GetPyData (event.GetItem()),
+                   lastsel = self.treeWg.GetPyData (event.GetOldItem()),
+                   _form   = self._gftree._form))    
+ 
+    #event.Skip() -- don't skip, it actually comes in handy :-)
+
+  #
+  # the new, digitally remastered, thx enhanced _onTreeActivated handler :-) 
+  #
+  def _onTreeActivated (self, event):
+    #print "activated: ", self.treeWg.GetPyData (event.GetItem()).desc
+    thread.start_new_thread (thread_proc, ())
+    pass
+ 
+  #
+  # on item expanded/collapsed we need to update the list view
+  #
+  def _onTreeExpanded (self, event):
+    self._sendEvt ('uitreeItemExpanded',
+                   node=self.treeWg.GetPyData(event.GetItem()),
+                   _form=self._gftree._form)
+
+  def _onTreeCollapsed (self, event):
+    self._sendEvt ('uitreeItemCollapsed',
+                   node=self.treeWg.GetPyData(event.GetItem()),
+                   _form=self._gftree._form)
+
+#
+# stores ui specific information about tree nodes
+#
+class ui_info:
+  def __init__ (self, t=None, l=-1):
+    self.tree_item  = t
+    self.list_index = l
+
+def thread_proc():
+  print "foo"
+
+configuration = {
+    'baseClass'  : UITree,
+    'provides'   : 'GFTree',
+    'container'  : 0,
+    }





reply via email to

[Prev in Thread] Current Thread [Next in Thread]