summaryrefslogtreecommitdiffstats
path: root/funcweb/funcweb/widget_automation.py
blob: 9467f21ab1af44953d9c6cfd33ca721658e227f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
#the purpose of that module is to make widget automation 
#for registered minion modules so we dont hace to write
#that same boring stuff for every added module !

from turbogears.widgets.base import Widget,WidgetsList
from turbogears import widgets

class WidgetListFactory(object):
    """
    The class is responsible for taking the method arguments
    and converting them to the appropriate widget equivalents

    Examples :
    """
    #which type matches for which InputWidget
    __convert_table={
            'int':{
                'default_value':"TextField",
                },
            'string':{
                'default_value':"TextField",
                'options':"SingleSelectField"},
            'boolean':{
                'default_value':"CheckBox"},
            'float':{
                'default_value':"TextField",
                },
            'hash':{
                'type':"RepeatingFieldSet"},
            'list':{
                'type':"RepeatingFieldSet"} 
            }
    #will contain the input widget created in that class

    def __init__(self,argument_dict,minion=None,module=None,method=None):
        """
        Initiated with argument_dict of a method to return back
        a WidgetsList object to be placed into a form object

        @param:argument_dict : The structure we got here is like
        {'arg1':{'type':'int'..},'arg2':{'min':111} ...}
        """

        self.__argument_dict = argument_dict
        self.__widget_list={}

        #these fields will be passed ass hidden so we need them
        self.minion = minion
        self.module = module
        self.method = method
    
    def __add_general_widget(self):

        #key is the argument_name and the argument are options
        for key,argument in self.__argument_dict.iteritems():
            #get the type of the argument
            current_type = argument['type']
            
            act_special = False #if it has some special parameters
            #it should be passed to its specialized method,if it has
            #for example options in its key it should be shown as a
            #SingleSelectField not a TextFiled
            
            for type_match in self.__convert_table[current_type].keys():
                if type_match!='default_value' and argument.has_key(type_match):
                    act_special = True

           # print key,argument

            if act_special:
                #calling for example __add_specialized_string(..)
                getattr(self,"_%s__add_specialized_%s"%(self.__class__.__name__,current_type))(argument,key)
            else:
                temp_object = getattr(widgets,self.__convert_table[current_type]['default_value'])()
                #add common options to it
                self.__add_commons_to_object(temp_object,argument,key)
                #add a new entry to final list
                self.__widget_list[key]=temp_object
                #print "That have the object :",getattr(self.__widget_list[key],"default")
                del temp_object

                #print "That have the object :",getattr(self.__widget_list["list_default"],"default")

        #adding the hidden fields (that part wass adde later can be made more generic)
        if self.minion:
            self.__widget_list['minion']= getattr(widgets,'HiddenField')(name="minion",default=self.minion)
        if self.module:
            self.__widget_list['module']= getattr(widgets,'HiddenField')(name="module",default=self.module)
        if self.method:
            self.__widget_list['method']= getattr(widgets,'HiddenField')(name="method",default=self.method)



    def __add_specialized_string(self,argument,argument_name):
        """
        Specialized option adder, called when the type:string is used
        with option 'options' so we should create a new SingleSelectField
        that one canno be created like others because user should supply options
        in the constructor of the SingleSelectField so it becomes a special one

        @param : argument : the argument options,
        @param : argument_name : the name of the argument also the name of the widget
        @return : Nothing
        """
        
        #allittle bit difficult to follow but that structure does
        #temp_object = SingleSelectField() for example
        
        temp_object = getattr(widgets,self.__convert_table[argument['type']]['options'])(options = argument['options'])
        self.__add_commons_to_object(temp_object,argument,argument_name)
        #add a new entry to final list
        self.__widget_list[argument_name]=temp_object
        del temp_object
    
    def __add_specialized_hash(self,argument,argument_name):
        """
        Specialized option adder for hash, we need it to be diffferent
        because the hash and list objects uses an advanced type of widgets
        which make them to be able to add, remove fields during using the
        web UI. It uses the RepeatingFieldSet which is able to contain the
        other normal input widgets. It will have two fields (TextFields)
        one for key : keyfield and other for value : valuefield
        Also the validator addition is a little bit different and should 
        be done in that method also ...

        @param : argument : the argument options,
        @param : argument_name : the name of the argument also the name of the widget
        @return : Nothing
        """
        hash_repeat_data = {
                'template':"funcweb.templates.repeater_form",#may change that if someone doesnt like my design :)
                'fields': [
                    widgets.TextField(name="keyfield",label="Key Field"),
                    widgets.TextField(name="valuefield",label="Value Field")
                    ],
                }
        
        #create the RepeatingFieldSet object and add it to global list like you do for others
        temp_object = getattr(widgets,self.__convert_table[argument['type']]['type'])(**hash_repeat_data)
        #print temp_object.fields
        #add the common options
        self.__add_commons_to_object(temp_object,argument,argument_name)
        #add a new entry to final list
        self.__widget_list[argument_name]=temp_object
        del temp_object
    



    def __add_specialized_list(self,argument,argument_name):
        """
        Very similar to __add_specialized_hash except it has one field
        that is repeated so that provides a dynamic numbers of fields into 
        the web UI.
        
        TODO : combine the 2 methods into a one generic they are very similar 
        @param : argument : the argument options,
        @param : argument_name : the name of the argument also the name of the widget
        @return : Nothing
        """
        list_repeat_data = {
                'template':"funcweb.templates.repeater_form",#may change that if someone doesnt like my design :)
                'fields' : [
                    widgets.TextField(name="listfield",label="List Field")
                    ],
                }
        
        #create the RepeatingFieldSet object and add it to global list like you do for others
        temp_object = getattr(widgets,self.__convert_table[argument['type']]['type'])(**list_repeat_data)
        #add the commno options
        self.__add_commons_to_object(temp_object,argument,argument_name)
        #add a new entry to final list
        self.__widget_list[argument_name]=temp_object
        del temp_object
 

    def __add_commons_to_object(self,object,argument,argument_name):
        """
        As it was thought all input widgets have the same
        common parameters they take so that method will add
        them to instantiated object for ex (TextField) if they 
        occur into the argument ...

        @param object : instantiated inputwidget object
        @param method argument to lookup {type:'int','max':12 ...}
        @return :None
        """
        #firstly set the name of the argument 
        setattr(object,"name",argument_name)
        setattr(object,"label",pretty_label(argument_name))
        
        #print "The argument name is :",argument_name
        #print "The argument options are :",argument

        if argument.has_key('default'):
            setattr(object,"default",argument["default"])
        if argument.has_key('description'):
            setattr(object,'help_text',argument['description'])
    
    def get_widgetlist(self):
        """
        Return back a dictionay with argument_name : input_widget
        pairs. That method may not be called directly,get_widgetlist_object
        is better for using in web interface
        """
        #compute the list
        self.__add_general_widget()
        return self.__widget_list

    def get_widgetlist_object(self):
        """
        Method return back the final widgetlist object
        which is turbogears.widgets.WidgetsList
        """

        #print self.__widget_list
        if len(self.__widget_list.keys())==0:
            self.__add_general_widget() #not very efficient
    
        widget_list_object = widgets.WidgetsList()
        for name,input_widget in self.__widget_list.iteritems():
            #it is a list indeed
            widget_list_object.append(input_widget)

        #get the object back
        #print widget_list_object
        return widget_list_object

####################################################################################################################
from turbogears.widgets.base import CoreWD
from turbogears.widgets import RemoteForm
from turbogears import validators, expose

class RemoteFormAutomation(CoreWD):
    """
    Base class for ajaxian Form creation
    """

    name = "Ajaxian Minion Submit Form"

    template = """ 
    <div>
       ${for_widget.display(action='/funcweb/post_form')}
        <div id="loading"></div>
        <div id="post_data"></div>
    </div>
    """

    full_class_name = "funcweb.controllers.Root"

    def __init__(self,generated_fields,validator_schema,*args,**kwarg):
        """
        The constructor part same as normal one except
        it takes a WidgetsList object into generated_fields
        which is generated by WidgetListFactory
        """
        #call the master :)
        super(RemoteFormAutomation,self).__init__(*args,**kwarg)
        self.for_widget = RemoteForm(
                fields = generated_fields,
                validator = validator_schema,
                name = "minion_form",
                update = "resultbox",
                before='hideElement(getElement(\'resultcontent\'));showElement(getElement(\'resultcontent\'));addDomAjaxREsult();getElement(\'loading\').innerHTML=toHTML(IMG({src:\'../funcweb/static/images/loading.gif\',width:\'100\',height:\'100\'}));',
                on_complete='getElement(\'loading\'  ).innerHTML=\'Done!\';',
                submit_text = "Send Command to Glob"
        )

####################################################################################################
class RemoteFormFactory(object):
    """
    Gets the WidgetListFactory object
    and return back a RemoteForm the same as above
    just for testing
    """
    #some values that may want to change later 
    name = "minion_form",
    update = "col5",
    before='getElement(\'loading\').innerHTML=toHTML(IMG({src:\'../funcweb/static/images/loading.gif\',width:\'100\',height:\'100\'}));',
    on_complete='getElement(\'loading\'  ).innerHTML=\'Done!\';',
    submit_text = "Send Minion Form"
    action = "/funcweb/post_form"

    def __init__(self,wlist_object,validator_schema):
        self.wlist_object = wlist_object
        self.validator_schema = validator_schema

    def get_remote_form(self):
        
        #print self.wlist_object

        return RemoteForm(
                name = self.name,
                fields = self.wlist_object,
                before = self.before,
                on_complete = self.on_complete,
                update = self.update,
                submit_text = self.submit_text,
                action = self.action,
                validator = self.validator_schema
                )


#############################################################################################
def pretty_label(name_to_label):
    """
    Simple util method to show the labels better 
    without __ things and other ugly looking stuff
    """
    tmp = None
    split_tokens = ('__','_','-')
    for st in split_tokens:
        tmp = name_to_label.split(st)
        if len(tmp)>1:
            break

    if tmp :
        name_to_label = " ".join([s.capitalize() for s in tmp])
    else:
        name_to_label = name_to_label.capitalize()

    return name_to_label