Hi Tomas, > I tried httpGate and found that it makes apps significantly less > responsive compared to connecting directly via specific port. Is that > expected behaviour?
Hm, strange. 'httpGate should not be a bottleneck, and I never observed any slow down. How strong is the effect (e.g. in millisecs)? Could you perhaps try to locate the reason? For example, can you see where it possibly hangs if you start it as strace -f /.../httpGate ... > I found that if I choose [New] in the example app/ and then do not > fill anything in the dialog and do not choose [Save], a new db object > is created even though it is possibly not valid (e.g. if +Need is > specified for some field). This is due to the fact that the db object > is created before user choses [Save] in the dialog: > > (gui '(+Button) ,"New" '(newUrl '(+A) '(f genKey 'f '+A))) > > Is it a bug or am I doing something wrong? No, but this is the desired behavior :-) A new object is created immediately if you press the "New" button, because the following GUI page needs that object to be operative. The behavior of most components in that page depends on the underlying object. IMHO, It does no harm if the object is not yet completely filled in. Even more, the user should not be forced to enter all data immediately, he may decide to continue his work later. The object is created if the user says so, it can be found from now on in search dialogs, or he can decide to delete it later. Also, many constraints may depend on mutual conditions, where you have to enter data on possibly different objects and locations, until these conditions can be checked. So the philosophy in that GUI is to let the user continue to work as he likes, and postpone critical checks until these data are really needed. Real-world applications have a 'check>' method for most classes. Unfortunately, the demo "app/" does not contain an example for this. A typical case would be the '+Ord' class to have a 'check>' method, checking that this order has a number, a date, a customer, and at least one position, and a button in the GUI to actually "book" or "close" that order. The 'check>' method usually recursively calls the 'check>' method of connected objects (here the data in the customer object (name, address etc.) and the articles in the postion objects (prices etc.). Then the user can enter and modify data as needed, and in the final step of closing that order it will be verified. But all this is a philosophical issue, any application is free to implement additional checks at each stage. This was all omitted in the demo "app/" to keep it simple. OK, having said this, I should provide an example. For the matter of demonstration, I implemented those checks for the demo app (see attachments). They are called when the "PDF-Print" button is pressed (this demo never "closes" orders). I don't know if I should keep them in the official release. The problem is that all these messages have to be translated :-( > Suppose I have two classes +A and +B with m-n relationship f: > > (class +A) BTW, please don't forget to inherit from '+Entity': (class +A +Entity) > (rel f (+List +Joint) f (+B)) > > (class +B) > (rel f (+List +Joint) f (+A)) > > What is the easiest way to display and edit the f field (link > instances of +A and +B together)? I thought of something like > <select> with "multiple" attribute but what is the picolisp way > (reusing existing components)? > > (gui '(+E/R ???) '(f : home obj) ???) Each object of '+A' or '+B' have a list of objects of the other class. So the recommended way is to have a '+Chart' on each side. (gui '(+E/R +Chart) '(f : home obj) ..) The contents of these charts depend very much on what should be displayed of each object. I think there are some applicable examples in "app/" and "doc/family.l". Select boxes with multiple selections are currently not supported. > There is bin/psh mentioned in app dev manual. How do I eval an > expression in the picolisp server it is attached to? The repl seems > to be local but what if I want to change and inspect something in the Yes, it runs in a child process (like each of the connected GUIs) of the application server. > running server without stopping it? You can do manual changes to the DB witout problems. Any 'put!>' etc. will be properly propagated. However, if you really want to change something in the parent process (e.g. loading a file or modifying a global variable), there is the "boss" mechanism. To use it, "main.l" should include (load "lib/boss.l") Then you can say in 'psh' things like: (boss 'load "someAdditionalFile.l") or (boss 'setq '*GlobalVariable 123) so that further child processes will inherit these changes. Cheers, - Alex
# 14apr08abu # (c) Software Lab. Alexander Burger ### Entity/Relations ### # # nr nm nr nm nm # | | | | | # +-*----*-+ +-*----*-+ +--*-----+ # | | sup | | | | # str --* CuSu O-----------------* Item *-- inv | Role @-- perm # | | | | | | # +-*-*--O-+ +----O---+ [EMAIL PROTECTED] # | | | | | usr # nm tel -+ | | | | # | | | | itm | role # +-*-----+ | | +-------+ +---*---+ +----*---+ # | | | | | | ord | | | | # | Sal +---+ +---* Ord @--------* Pos | nm --* User *-- pw # | | cus | | pos | | | | # +-*---*-+ +-*---*-+ +-*---*-+ +--------+ # | | | | | | # hi sex nr dat pr cnt (extend +Role) (dm url> (Tab) (and (may RoleAdmin) (list "app/role.l" '*ID This)) ) (extend +User) (rel nam (+String)) # Full Name (rel tel (+String)) # Phone (rel em (+String)) # EMail (dm url> (Tab) (and (may UserAdmin) (list "app/user.l" '*ID This)) ) # Salutation (class +Sal +Entity) (rel nm (+Key +String)) # Salutation (rel hi (+String)) # Greeting (rel sex (+Any)) # T:male, 0:female (dm url> (Tab) (and (may Customer) (list "app/sal.l" '*ID This)) ) (dm hi> (Nm) (or (text (: hi) Nm) ,"Dear Sir or Madam,") ) # Customer/Supplier (class +CuSu +Entity) (rel nr (+Need +Key +Number)) # Customer/Supplier Number (rel sal (+Link) (+Sal)) # Salutation (rel nm (+Sn +Idx +String)) # Name (rel nm2 (+String)) # Name 2 (rel str (+Ref +String)) # Street (rel plz (+Ref +String)) # Zip (rel ort (+Ref +String)) # City (rel cty (+Ref +String)) # Country (rel tel (+Fold +Ref +String)) # Phone (rel fax (+String)) # Fax (rel mob (+Fold +Ref +String)) # Mobile (rel em (+String)) # EMail (rel txt (+Blob)) # Memo (dm url> (Tab) (and (may Customer) (list "app/cusu.l" '*Tab Tab '*ID This)) ) (dm check> () (make (or (: nr) (link ,"No customer number")) (or (: nm) (link ,"No name")) (unless (and (: str) (: plz) (: ort)) (link ,"Incomplete address") ) ) ) # Item (class +Item +Entity) (rel nr (+Need +Key +Number)) # Item Number (rel nm (+Sn +Idx +String)) # Item Description (rel sup (+Ref +Link) NIL (+CuSu)) # Supplier (rel inv (+Number)) # Inventory (rel pr (+Ref +Number) NIL 2) # Price (rel txt (+Blob)) # Memo (rel jpg (+Blob)) # Picture (dm url> (Tab) (and (may Item) (list "app/item.l" '*ID This)) ) (dm cnt> () (- (or (: inv) 0) (sum '((This) (: cnt)) (collect 'itm '+Pos This) ) ) ) (dm check> () (make (or (: nr) (link ,"No item number")) (or (: nm) (link ,"No item description")) ) ) # Order (class +Ord +Entity) (rel nr (+Need +Key +Number)) # Order Number (rel dat (+Need +Ref +Date)) # Order date (rel cus (+Ref +Link) NIL (+CuSu)) # Customer (rel pos (+List +Joint) ord (+Pos)) # Positions (dm url> (Tab) (and (may Order) (list "app/ord.l" '*ID This)) ) (dm sum> () (sum 'sum> (: pos)) ) (dm check> () (make (or (: nr) (link ,"No order number")) (or (: dat) (link ,"No order date")) (or (: cus) (link ,"No customer")) (and (: cus) (check> @) (chain @)) (or (: pos) (link ,"No positions")) (chain (mapcan 'check> (: pos))) ) ) (class +Pos +Entity) (rel ord (+Dep +Joint) (art) pos (+Ord)) # Order (rel itm (+Ref +Link) NIL (+Item)) # Item (rel pr (+Number) 2) # Price (rel cnt (+Number)) # Quantity (dm sum> () (* (: pr) (: cnt)) ) (dm check> () (make (or (: itm) (link ,"Position without item")) (and (: itm) (check> @) (chain @)) (or (: pr) (link ,"Position without price")) (or (: cnt) (link ,"Position without quantity")) ) ) # Database sizes (dbs (1 +Role +User +Sal) # (1 . 128) (2 +CuSu) # (2 . 256) (1 +Item +Ord) # (3 . 128) (0 +Pos) # (4 . 64) (2 (+Role nm) (+User nm) (+Sal nm)) # (5 . 256) (3 (+CuSu nr nm str plz ort cty tel mob)) # (6 . 512) (3 (+Item nr nm sup pr)) # (7 . 512) (3 (+Ord nr dat cus) (+Pos itm)) ) # (8 . 512) # vi:et:ts=3:sw=3
# 14apr08abu # (c) Software Lab. Alexander Burger (must "Order" Order) (menu ,"Order" (ifn *ID (prog (<h3> NIL ,"Select" " " ,"Order") (form 'dialog (choOrd T)) ) (<h3> NIL ,"Order") (form NIL (<h2> NIL (<id> (: nr))) (panel T ,"Order No. @1" '(may Delete) '(choOrd T) 'nr '+Ord) (<grid> 4 ,"Date" NIL (gui '(+E/R +DateField) '(dat : home obj) 10) (gui '(+View +TextField) '(text ,"(@1 Positions)" (length (: home obj pos))) ) ,"Customer" (gui '(+ChoButton) '(choCuSu (field 1))) (gui '(+E/R +Obj +TextField) '(cus : home obj) '(nm +CuSu) 30) (gui '(+View +TextField) '(field -1 'obj 'ort) 30) ) (----) (gui '(+Set +E/R +Chart) '((L) (filter bool L)) '(pos : home obj) 8 '((Pos I) (with Pos (list I NIL (: itm) (or (: pr) (: itm pr)) (: cnt) (sum> Pos)) ) ) '((L D) (cond (D (put!> D 'itm (caddr L)) (put!> D 'pr (cadddr L)) (put!> D 'cnt (get L 5)) (and (get D 'itm) D) ) ((caddr L) (new! '(+Pos) 'ord (: home obj) 'itm (caddr L) ) ) ) ) ) (<table> NIL NIL '((align) (btn) (NIL ,"Item") (NIL ,"Price") (NIL ,"Quantity") (NIL ,"Total") (btn) (btn)) (do 8 (<row> NIL (gui 1 '(+NumField)) (gui 2 '(+ChoButton) '(choItem (field 1))) (gui 3 '(+Obj +TextField) '(nm +Item) 30) (gui 4 '(+FixField) 2 12) (gui 5 '(+NumField) 8) (gui 6 '(+Sgn +Lock +FixField) 2 12) (gui 7 '(+DelRowButton)) (gui 8 '(+BubbleButton)) ) ) (<row> NIL NIL NIL (scroll 8) NIL NIL (gui '(+Sgn +View +FixField) '(sum> (: home obj)) 2 12) ) ) (<spread> (gui '(+Rid +Button) ,"PDF-Print" '(if (check> (: home obj)) (note ,"Can't close order" (uniq @)) (psOut 0 ,"Order" (ps> (: home obj))) ) ) (editButton T) ) ) ) ) # vi:et:ts=3:sw=3