I think I found the problem. No, I wasn't in Windows. I spend very little
time in that state of depression.
OK we have a tree. The root is always the user and the leaf is always the
action script for a job to be submitted to a grid. The action scripts are
named and the names are unique... Usr names are also unique.
A user can have projects which is a container, similar to a folder. The
projects are unique by name within the user namespace, but also have
associated with them an id which is universally unique.
Within a project are analysis runs. Each analysis run is named uniquely in
the project namespace. Analysis Runs contain a series of workflows. The
workflows are bash scripts which may call several programs and which have
instantiated parameters within the analysis run.
Inside that environment, we have functionality that goes to buttons
Add Project--valid ONLY when the user is selected.
Rename Project
Delete Project
Duplicate Analysis Run (from another project)
Those three are valid only when a project is selected.
Then when an Analysis Run is selected
Add Workflow
Rename Analysis Run
Delete Analysis Run
Go To Run Menu
And finally: when a workflow is selected...
Insert Workflow Above Current Selection
Delete Workflow
The question arises, will this be enough in terms of categorical containers
(two levels). I am assuming it is not going to be adequate moving forward
(remember someone's famous pronouncement that any program can run in 640K?
So I want to build the page(s) to be data-driven. With a csv of the layers
and their names, and button functionality--the controller can produce JSON
responses that provide a list of buttons for each layer and the layer to
which they belong, and also a flattened list of nodes for the user tree. I
am putting sample data in the main() of this to demonstrate how it might
work.
I have solved half the problem... When the selection occurs within the
tree, the buttons appropriate appear. The other part, using a dispatcher
with onClick() doesn't seem quite so hopeful. Of course since there are
several points where some regeneration is needed to add another layer of
nodes, we could look at metaprogramming to autogenerate this page and
submit it to pyjsbuild. But I cannot aford toupees for all the Java
programmers around here, and I am sure the word Metaprogramming would
precipitate a session of breast-beating and hair tearing. I left out the
other page elements as they are not germane to the discussion... The
default html template is ok, and the css stylesheet .... Well the
stylesheet needs at least the line
.gwt-TreeItem-selected {background-color: #5ff1f3;}
#!/opt/pylib/pypy-1.9/bin/pypy #attach to whatever python you are using
from pyjamas.ui.SimplePanel import SimplePanel
from pyjamas.ui.ScrollPanel import ScrollPanel
from pyjamas.ui.Tree import Tree
from pyjamas.ui.TreeItem import TreeItem
from pyjamas import DOM
from pyjamas import Window
from pyjamas.ui.RootPanel import RootPanel
from pyjamas.ui.HTML import HTML
from pyjamas.HTTPRequest import HTTPRequest
import pyjd # dummy in pyjs
from pyjamas.ui.TextArea import TextArea
from pyjamas.ui.Label import Label
from pyjamas.ui.Button import Button
from pyjamas.ui.VerticalPanel import VerticalPanel
from pyjamas.ui.HorizontalPanel import HorizontalPanel
from pyjamas.ui.ListBox import ListBox
from pyjamas.JSONService import JSONProxy
from pyjamas.ui.TabPanel import TabPanel
from pyjamas.ui.TextBox import TextBox
from pyjamas.ui.PasswordTextBox import PasswordTextBox
from pyjamas.ui.NamedFrame import NamedFrame
from pyjamas.ui.Frame import Frame
from pyjamas.ui.Hidden import Hidden
from pyjamas.ui.FormPanel import FormPanel
# some of those imports are unnecessary fro the demo purpose, but rather
represent wht I am using in the finished product.
class BeyondDesignLimitError(Excepton):
pass
class ButtonPanel(VerticalPanel):
def __init__(self, button_list, test=False):
VerticalPanel.__init__(self)
self.button_list=button_list
self.buttons = []
self.button_dict={0:[],1:[],2:[],3:[],4:[],5:[],6:[]}
for (button_name, button_level) in self.button_list:
self.buttons.append(Button(button_name,getattr(self,"on%sClick"
%button_name.replace(" ",""))))
self.buttons[-1].setVisible(test)
self.buttons[-1].setWidth('180px')
self.button_dict[button_level].append(self.buttons[-1])
self.add(self.buttons[-1])
def onAddProjectClick():
Window.alert("You Clicked Add Project")
# This seems to work, with the specific button functions ID'd
# But try onClick() with a dispatcher and we go sideways...
def onRenameProjectClick():
Window.alert("You Clicked Rename Project")
def onDeleteProjectClick():
Window.alert("You Clicked remove Project")
def onAddAnalysisRunClick():
Window.alert("You Clicked Add Analysis Run")
def onDuplicateAnalysisRunClick():
Window.alert("you clicked to Duplicate Analysis Run from some"
" other project")
def onDeleteAnalysisRunClick():
Window.alert("You Clicked remove Analysis Run")
def onRenameAnalysisRunClick():
Window.alert("You Clicked rename Analysis Run")
def onAddWorkflowClick():
Window.alert("You Clicked Add Workflow")
def onGoToRunMenuClick():
Window.alert("You Clicked Go To Run Menu")
def onInsertWorkflowAboveCurrentSelectionClick():
Window.alert("You Clicked for inserting a workflow")
def onDeleteWorkflowClick():
Window.alert("You Clicked to remove a workflow from the AR"
" list")
class MainTree(ScrollPanel):
def __init__(self, arc,b):
self.buttons=b.buttons #Note that the use of a local instance
variable is necessary
self.button_dict=b.button_dict # Same caution as above.
ScrollPanel.__init__(self, widget)
self.setHeight(450)
self.setWidth(280)
self.node_dict = {}
tree = Tree()
tree.addTreeListener(self)
levels = [[] for i in range(MAXLEVELS)]
while arc:
obj, (valuex, level,), = arc.pop(0)
if level == 0:
s1=self.createItem(obj, value=(valuex, level))
s1.setState(True, fireEvents=False)
levels[0].append(s1)
continue
if level>0 and level<MAXLEVELS+1:
levels[level].append(levels[level-1][-1].addItem(
self.createItem(obj, value = (valuex,level))))
levels[level][-1].setState(False, fireEvents=False)
continue
else:
raise BeyondDesignLimitError
tree.addItem(s1)
tree.ensureSelectedItemVisible()
self.add(tree)
def createItem(self, label, value=None):
item = TreeItem(label)
DOM.setStyleAttribute(item.getElement(), "cursor",
"pointer","images")
if value is not None:
item.setUserObject(value)
return item
def onTreeItemSelected(self, item):
level = item.getUserObject()[1]
for bat in self.buttons:
bat.setVisible(False)
for bat in self.button_dict[level]:
bat.setVisible(True)
Window.alert("You clicked on " + value)
def onTreeItemStateChanged(self, item):
pass # We ignore this.
"""************End of MainTRee******************"""
def traveler(node, ndex=0, blist=None):
"""Small utility function in controller to flatten user tree adapted to
immediate data"""
if blist is None:
blist = []
#
# blist.append((node.name, (node.id, ndex)))
# uncomment this ^^ and comment that VV for full JSONRPC
# Current setup is demo
#
blist.append((node.name, (0,ndex))) #that
if node.isLeaf():
return
ndex += 1
for cnode in node.child:
traveler(cnode, ndex=ndex, blist=blist)
return blist
"""That function is not to be used in the main app on a page, just in the
controller"""
"""Next is for demo purposes only"""
"""The data model has this class 'Nodal' as an ABCMeta and used as a
mixin"""
class TTS(object):
def __init__(self, name, child=[]):
self.name = name
self.child = child
def isLeaf(self):
return not self.child
"""End of Demo purposes only"""
MAXLEVELS = 10
USER = 'User'
def main():
root = RootPanel()
""" Demo only--real button list generated other side of JSONRPC"""
button_list = [('Add Project',0),
('Rename Project',1),
('Delete Project', 1),
('Duplicate Analysis Run', 1),
('Add Analysis Run',1),
('Rename Analysis Run',2),
('Delete Analysis Run',2),
('Add Workflow',2),
('Go To Run Menu', 2),
('Delete Workflow',3),
('Insert Workflow Above Current Selection', 3)]
b = ButtonPanel(button_list)
buttons = [el[0] for el in button_list]
button_dict = {}
for i in range(4):
button_dict[i] = []
for (button_name, cat) in button_list:
button_dict[cat].append(button_name)
built222 = [TTS('performance_plot',[]), TTS('howler_algorithm', [])]
built221 = [TTS('wf9',[])]
built123 = [TTS('sum_stats', [])]
built122 = [TTS('sum_stats',[])]
built121 = [TTS('scan_reads',[]),TTS('analyze_reads',[])]
built023 = [TTS('wf7',[]), TTS('performance_plot',[])]
built021 = [TTS('wf1',[])]
built022 = [TTS('wf1',[]), TTS('scan_reads',[]), TTS('analyze
reads',[])]
built02 = [TTS('SNP calls',built021),
TTS('contrast bwa/bismark', built022),
TTS('test_fidelity',built023)]
built12 = [TTS('export',built121), TTS('fastq',built122),
TTS('bam', built123)]
built22 = [TTS('Mosaik',built221), TTS('Measurements', built222)]
blis1 = [TTS('Special Alignment',built02),
TTS('Scan',built12),
TTS('SureSelect', built22)]
trroot = TTS(USER,blis1)
# user_list is passed in as a value in a JSON object (Python dict)
arc = traveler(trroot)
"""Ideally, arc is passed as a JSON object value (list of tuples). """
t=MainTree(arc,b)
h=HorizontalPanel()
v=VerticalPanel()
v.add(t)
h.add(v)
v1=VerticalPanel()
v1.add(b)
h.add(v1)
h.add(b)
root.add(h)
if __name__ == '__main__':
main()
On Wed, Sep 12, 2012 at 9:29 AM, C Anthony Risinger <[email protected]> wrote:
> On Tue, Sep 11, 2012 at 5:53 PM, Michael Moore
> <[email protected]> wrote:
> >
> > If anyone knows how to automagically make one function in a Tree class
> > instantiation recognize objects from anothe class (buttons), maybe I can
> > avoid giving some Java programmers a conniption by not using Python to
> put
> > together a source file on the basis of number of layers or node levels
> in a
> > tree and then exec'ing it before handing it over to pyjsbuild.
>
> you'll need to whip up a small example highlighting the problem -- i'm
> not sure i even know what you're asking.
>
> in 99% of cases problems can be attributed to the application, and
> every now and again is a bug in pyjs somewhere ... sadly, the errors
> are not particularly clear, and even this depends on the build opts
> used ...
>
> ... are you building with `--enable-strict`? you may be using python
> features in the application code but not enabling them in the build.
>
> ... are you building with `--enable-debug`? this can improve the
> debugging experience, but it's value is subjective ...YMMV
>
> ... are you on Windows? download/install `comtypes` and use native
> "pyjd" runners ... this will run your app code in a real python
> interpreter, and is massively valuable for development.
>
> ^^^^ if you're not on Windows a new runner [giwebkit] "should" be
> available in the coming days ... i had a deadline at work sucking up
> all my time recently, but this weekend the family is out of town and i
> intend to merge it, regardless of any remaining bugs (if any ;-)
>
>
> --
>
> C Anthony
>
> --
>
>
>
>
--