Entries For: March 2007
2007-03-26
Open source Zope app in the news!
Today, on the front page of Slashdot, there was a link for an open source server monitoring & system management application. Well, what do you know, it runs on Zope 2! The visible source code is here
2007-03-25
One issue using Prototype's Ajax form submission with Zope 3
I've found a weird issue while trying to debug why on of my Ajax loaded forms wasn't, apparently, properly validated. Even though that the schema specified that the fields are required, the form action would get executed as if the validation wouldn't have been done or the request was properly validated. I thought at first that there's an issue with the form class/handling itself, but after some testing I came to the conclusion that it has to be the way I'm doing the AJAX request.
What I have discovered is that I was using the parameters option of the Ajax.Request to make a form submit with POST method, which apparently causes Zope to validate the fields as having a value, even though they were empty. The right way to do this request is using the postBody parameter, as fixing that made my forms work again. I'm not sure what causes this behaviour in Zope: the visible difference is that postBody includes all the form inputs, even the empty ones, while the parameters version includes just those with a value (in my case, the submit button). And I have tried leaving out a field from the Zope request by saving the html page, deleting one of the inputs and doing a form submission, but Zope does the right thing in this case.
I'm not sure how popular is using the parameters option with POST and Ajax.Request, but I'm adding this note here, just in case.
postBody version
POST /++skin++course/site/new_design.html HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061024 Firefox/2.0 (Swiftfox)
Accept: text/javascript, text/html, application/xml, text/xml, */*
Accept-Language: en-us,en;q=0.7,ro;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
X-Requested-With: XMLHttpRequest
X-Prototype-Version: 1.5.1_rc1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://localhost:8080/++skin++course/site/
Content-Length: 94
Cookie: top_http___localhost_9080_t2_sticky_view=354px; left_http___localhost_9080_t2_sticky_view=646px; state_http___localhost_9080_t2_sticky_view=hide; zindex_http___localhost_9080_t2_sticky_view=5; WT_FPC=id=82.79.74.153-1913305056.29841814:lv=1172488789513:ss=1172484509013
Authorization: Basic dGliaTp2aWNlcm95
Pragma: no-cache
Cache-Control: no-cache
add_design.title=&add_design.description=&add_design.actions.4164642064657369676e=Add%20design
HTTP/1.x 200 OK
Content-Length: 4408
X-Powered-By: Zope (www.zope.org), Python (www.python.org)
Accept-Ranges: bytes
Server: Twisted/2.5.0+rUnknown TwistedWeb/[twisted.web2, version 0.2.0 (SVN rUnknown)]
Date: Sun, 25 Mar 2007 11:56:52 GMT
Content-Type: text/html;charset=utf-8
----------------------------------------------------------
parameters version
POST /++skin++course/site/new_design.html HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061024 Firefox/2.0 (Swiftfox)
Accept: text/javascript, text/html, application/xml, text/xml, */*
Accept-Language: en-us,en;q=0.7,ro;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
X-Requested-With: XMLHttpRequest
X-Prototype-Version: 1.5.1_rc1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://localhost:8080/++skin++course/site/
Content-Length: 52
Cookie: top_http___localhost_9080_t2_sticky_view=354px; left_http___localhost_9080_t2_sticky_view=646px; state_http___localhost_9080_t2_sticky_view=hide; zindex_http___localhost_9080_t2_sticky_view=5; WT_FPC=id=82.79.74.153-1913305056.29841814:lv=1172488789513:ss=1172484509013
Authorization: Basic dGliaTp2aWNlcm95
Pragma: no-cache
Cache-Control: no-cache
add_design.actions.4164642064657369676e=Add%20design
HTTP/1.x 200 OK
Content-Length: 3491
X-Powered-By: Zope (www.zope.org), Python (www.python.org)
Accept-Ranges: bytes
Server: Twisted/2.5.0+rUnknown TwistedWeb/[twisted.web2, version 0.2.0 (SVN rUnknown)]
Date: Sun, 25 Mar 2007 11:56:15 GMT
Content-Type: text/html;charset=utf-8
----------------------------------------------------------
2007-03-24
Roll for initiative, monkey boy!
I thought I'd put a link here for a source of great entertainment of mine: The Knights of the Dinner Table. Hope you'll be as entertained as I am every time I'm watching them or reading the KODT comic strip.
And another link: Barbarian Prince, a downloadable solitaire game, a mixture of boardgame/RPG/choose your own adventure. I found a review of this game in the KODT comics magazine, but there are a couple of other games there, for two players or solitaire.
2007-03-23
Getting the registered Zope 3 skin name for an interface
Problem: I need to get the skin name for a Zope 3 interface registered as skin.
Solution
Starting with Zope 3.3, the skinning mechanism has been simplified and skins are now just interfaces. This means that a skin interface is now a named utility for the IBrowserSkinType. To get the name with which this class has been registered as an utility, something along these lines is needed:
>>> from myapp.layer import IMyAppSkin
>>> from zope.app.apidoc.component import getUtilities
>>> from zope.publisher.interfaces.browser import IBrowserSkinType
>>> skins = getUtilities(IBrowserSkinType)
>>> for skinreg in skins:
... if skinreg.component == IMyAppSkin:
... skin_name = skinreg.name
... break
I'm using the apidoc module here, which feels a bit like cheating. Another, "apidoc-free" version is something like this:
>>> from zope.component import getGlobalSiteManager
>>> gsm = getGlobalSiteManager()
>>> skins = gsm.getUtilitiesFor(IBrowserSkinType)
>>> for skinreg in skins:
... if IMyAppSkin == skinreg[1]:
... skin_name = skinreg[0]
... break
getUtilitiesFor() returns a list of tuples, for example: [(u'Basic', <InterfaceClass zope.app.basicskin.IBasicSkin>), (u'Debug', <InterfaceClass zope.app.debugskin.IDebugSkin>), ... ]
UPDATE: fixed a small bug in the second example, that's what you get if I don't test...
You can get the current skin interface with:
curentSkinInterface = [iskin for iskin in interface.directlyProvidedBy(self.request) if
IBrowserSkinType.providedBy(iskin)][0]
2007-03-20
Freeciv rediscovered
I've recently "rediscovered" Freeciv. I'm a very casual gamer (15 minutes/day), but also an old, addicted, Civilization fan. Lately I've been looking for a nice game to play on my Linux desktops and I've found that Freeciv is finally getting some good graphics, as this was my biggest turn off I've had with it before. I've tried first the SDL client on Windows, but it is buggy and tends to freeze its popup windows. The GTK Windows client is a lot better, works quite flawless as far as I can tell. I've compiled the Linux version (on Ubuntu Edgy), first I've tried the SDL client, but it complained (at configure time) about a missing sdl-image library, which I have (and no -dev version in my apt sources). Using the freeland-big tiles, the game had a huge memory footprint (40% of 1024 Mb RAM). The most apparent improvements are new tile graphics, with bigger size, new graphics for the city titles on the play screen, a new full-screen mode, even for the GTK version and a tree-based research screen. There is another tileset on the freeciv.org site, called Freeland-big. This has, IMHO, some improved tiles. Click on the image below to see the new graphics I'm talking about (this is the default tileset). And another one, this time on Linux, with Freeland-big tileset.
UPDATE: Using the svn/trunk version the huge memory footprint problem of the Linux client is solved, but I can't use the freeland-big tileset anymore. To compile it on Ubuntu, I first had to apt-get install automake1.8 and libgtk2.0-dev. After that, run autoconf.sh to start the configure script generation and then make install.
2007-03-10
Embeding the Gecko engine in Python applications
I've got to deploy a new desktop based application, created, of course, with Zope 3. When you've got a hammer, everything looks like a nail, indeed. This application uses HTML and CSS as its presentation layer (right, it's a web page), with a bit of Ajax thrown in. Due do time constraints, I'm not even trying to get it to work properly on Internet Explorer (although it looks about 90% right, but I have some problems with Javascript), so I won't be embeding the Internet Explorer this time engine in my Python application, I'll just try to get the Gecko rendering engine, the one used in Firefox.
First, I've installed the ActiveX control for the Gecko engine. Following some ActiveX migration details on wxpython.org, I've generated a wxpython "binding" class, using the genaxmodule.py tool (after a quick dig in the Windows registry to find out which is the Mozilla control class name):
C:\Python24\Lib\site-packages\wx-2.6-msw-unicode\wx\tools>genaxmodule.py "Mozilla.Browser" Gecko
Creating module in: .\Gecko.py
ProgID: Mozilla.Browser.1
CLSID: {1339B54C-3453-11D2-93B9-000000000000}
The python code would that would use the ActiveX control would be something like this:
# -*- coding: ISO-8859-1 -*-
# generated by wxGlade 0.4.1cvs on Sat Mar 10 16:40:22 2007 from C:\Work\CourseBuilder.wxg
import wx
import Gecko
def createGeckoControl(parent, id):
gecko = Gecko.Gecko(parent, id)
return gecko
# begin wxGlade: dependencies
# end wxGlade
class MainFrame(wx.Frame):
def __init__(self, *args, **kwds):
# begin wxGlade: MainFrame.__init__
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.panel_1 = wx.Panel(self, -1)
self.gecko = createGeckoControl(self.panel_1, -1)
self.__set_properties()
self.__do_layout()
# end wxGlade
self.gecko.SetFocus()
self.gecko.Navigate2('http://slashdot.org', 0)
def __set_properties(self):
# begin wxGlade: MainFrame.__set_properties
self.SetTitle("frame_1")
# end wxGlade
def __do_layout(self):
# begin wxGlade: MainFrame.__do_layout
sizer_1 = wx.BoxSizer(wx.VERTICAL)
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
sizer_2.Add(self.gecko, 1, wx.EXPAND, 0)
self.panel_1.SetSizer(sizer_2)
sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
sizer_1.Fit(self)
self.Layout()
# end wxGlade
# end of class MainFrame
And the main app file:
#!/usr/bin/env python
# -*- coding: ISO-8859-1 -*-
# generated by wxGlade 0.4.1cvs on Sat Mar 10 16:40:22 2007 from C:\Work\CourseBuilder.wxg
import wx
from MainFrame import MainFrame
class CourseBuilderApp(wx.App):
def OnInit(self):
wx.InitAllImageHandlers()
main_frame = MainFrame(None, -1, "")
self.SetTopWindow(main_frame)
main_frame.Show()
return 1
# end of class CourseBuilderApp
if __name__ == "__main__":
CourseBuilderBrowser = CourseBuilderApp(0)
CourseBuilderBrowser.MainLoop()
Unfortunately I hit a problem that I can't find a solution for: this application crashes when I type something in the Gecko window. Blah :-( If anyone reading this know the answer, help me! :) Please! (tibi@life.org.ro)
My only option left is to go for the XULRunner and the MyBrowser demo. I'm not extremely happy about this, but at this point I don't see other options. Plus, it will be fun learning some about the Mozilla development platform.
Update: I've tested the Mozilla ActiveX Control using a simple Delphi 7 form and, while I don't get a crash, I still can't get it to accept keyboard input.
