八月 27, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Plone 4 Way to Get Icon

昇級 Plone 4 的過程,發現有些 content type icon 沒有顯示,在 log 裡找到線索:

WARNING Plone Deprecation Warning
The icon for the 'controlpanel/DropdownConfiguration' action
was obtained from the action icons tool.
The action icons tool has been deprecated
and will be removed in Plone 5.
You should register action icons directly on the action now,
using the 'icon_expr' setting.
繼續追查後,原來 icon 存取方式已經改變,在 CMF 2.2.0-alpha 正式引入新的方式,而 Plone 4 使用 CMF 2.2.0 版本,自然也受到影響。如果到 ZMI 裡的 portal_actionicons 查看比較,會發現大有不同。

八月 22, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Ploneboard 2.1 with Plone 3.3.5

雖然 Plone 4.0 近期就要正式問世,最近還是先搭配 Plone 3.3.5 安裝了 Ploneboard 2.1b2。執行 buildout 安裝過程沒問題,但在 quick install 過程遇到 AttributeError: portal_placeful_workflow 的錯誤訊息,原因在於 CMFPlacefulWorkflow 是它的相依模組,但沒有自動隨之啟用,解決方法很簡單,就是手動先把 CMFPlacefulWorkflow 啟用,再啟用 Ploneboard 就行,這個動作也會順便把 SimpleAttachment 啟用。正式的解法已寫成 trunk,訊息翻譯的成果也要放在這裡。

選擇想要新增討論區的目錄,以首頁為例,從新增項目的下拉選單找到 Message Board。

設定討論區的基本資料,包括標題、摘要描述、分類關鍵詞等。

討論區的基本樣貌已經具備,接著,點選 Add Forum 就可新增討論板。

設定討論板的資料,包括標題、摘要描述、分類關鍵詞、附件檔案最大數量等。

討論板的預設狀態是 Requite membership to post,表示註冊會員在登入系統後才能張貼討論文章,新的討論主題稱為 conversation。

設定討論主題的資料,包括標題、內文、附件檔案等。

八月 16, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» bzr Tip: These branches have diverged

Bazaar 是搭配 Launchpad 所用的管理工具,屬於分散式版本管理方式,由 Canonical 公司支援發展。
最近使用 bzr 2.0.1 的經驗,遇到 "bzr: ERROR: These branches have diverged. Use the missing command to see how. Use the merge command to reconcile them." 訊息,有撇步表示可以使用 bzr pull --overwrite 指令,再把 patch 重新擺回去。

八月 8, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Plone Theme Resource Customizer

想要更換 Plone 網站的 logo 或 CSS 設定值,傳統方式是到後台介面 (也就是 Zope Management Interface, ZMI) 進行設定,現在由前台介面 (也就是 Plone Site Setup) 也可以搞定了。

安裝 plone.app.themeeditor 後,原本要到 portal_skins 或 portal_view_customizations 才能編輯的佈景主題資源檔案,現在都可以在 Plone Site Setup 裡統一進行修改,操作方式請見教學影片,甚至可以搭配 windmill 進行測試工作

八月 5, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» How Sahana Eden Uses Launchpad

幾天前看了 launchpad 的介紹,網頁講得像是天下無敵,因此就問 Fran 有打算完全使用 launchpad 來開發嗎? Fran 表示 launchpad 的 branch 支援很棒,但 ticket 並不能搭配 branch 來排序,如果 branch 數量不多是夠用,但 branch 數量多時,就亂到難以管理。
因此 Sahana Eden 目前只使用 bzr 及 launchpad 來管理 branch,但使用 trac 來管理 ticket,另外 trac 本來就有 wiki 能整理文件。
還有一點,Eden 借用 lauchpad 的 BluePrint 概念,但直接在 trac wiki 上撰寫 BluePrint。
或許日後 launchpad 會改善上述的排序問題,

七月 23, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Setting Random Times with zope.sendmail

This is an abstract from How to add a random time between two emails sent from zope.sendmail.

需要搭配 Plone 架設 newsletter 的場合,可以使用 collective.dancing,它能夠管理訂戶資料,並利用 zope.sendmail 協助自動發信。如果訂戶數量過大,批次發信可能會被列入黑名單,此時,試試設定亂數時點,來處理這樣的問題。方式是撰寫 plone.smtp 程式碼:

import random
import time

from zope.sendmail import mailer

class SMTP(mailer.SMTPMailer):
"""Override SMTPMailer to let a random time"""

def send(self, fromaddr, toaddrs, message):
time.sleep(random.uniform(0,2))
super(SMTP, self).send(fromaddr, toaddrs, message)

六月 20, 2010
» 第一章 與直譯器互動

計算機功能 基本資料型態 變數的觀念 Help!Help! 第一個複合資料型態:字串 印出"哈囉!你好" 線上與直譯器互動 玩遊戲時速度曾經突然變慢嗎?為什麼呢?啊!MSN忘記登出,偶然的訊息打斷電腦目前的運作,原先一件件電腦已經排定的工作,現在又得重排一次。 電腦是如何安排工作的呢?對了,就是作業系統。作業系統是我們與電腦溝通最重要的介面,當我們利用電腦完成我們日常的工作時,開啟多個視窗好像已經是再普通不過的事情了。 點擊開啟大圖...... 許許多多的應用軟體透過作業系統的協調,重疊的視窗讓我們得以同時進行處理。那麼,如果我們要寫程式跟電腦溝通又該如何進行呢?仍是一樣,透過作業系統。 利用編譯式語言寫程式,我們需要另外用文字編輯器,如記事本之類的軟體先寫好程式碼,然後進行連結、編譯等流程。當發展的程式越趨龐大時,每一次寫完程式之後的測試動作變成一件很恐怖的事情,

六月 7, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Tips on LeadImage and Folder View

Folder 預設的標準顯示方式,如果覺得單調,想要增加圖示,可以藉助於 Content Lead Image



使用 buildout 新增擴充模組的方法,就可以安裝 collective.contentleadimage,在 Site Setup 裡可以指定使用 lead image 的 content type,包括 Folder。指定後,在 Folder 的 display 選項裡,就看得到 Folder lead-image view。

如果逐行顯示目錄的方式,還是覺得單調,想要改成兩欄式,可以在 ploneCustom.css 裡調整 vevent 的 class 設定值。

.vevent {
float: left;
height: 137px;
width: 42%;
margin-left: 4em;
}
如果發現 History 的位置亂掉,可以到 ZMI portal_view_customizations 修改 plone.belowcontentbody.contenthistory (zope.interface.interface-plone.belowcontentbody.contenthistory),在上方新增一行:
<div class="visualClear"></div>
以上是 Through The Web (TTW) 的修改方式,如果要在程式碼裡調整,可以參考 Plone Manual dynamic views 的說明

五月 28, 2010
» Install Python2.5 on Ubuntu 10.04 for Google App Engine

Ubuntu 10.04 已經預設不包 Python2.5 了,對寫 GAE 的人來說,這有點麻煩,到目前為止 GAE 並未正式地支援 2.6 ,所以最好認命地在 Ubuntu 10.04 中創建一個 Python2.5 的環境。


裝 2.5 的目的是為了開發 GAE 程式,所以我們需要額外下載這些程式碼:
  1. Python2.5
  2. PIL
  3. python-ipaddr
# 利用 apt-get 安裝相關函式庫,除 libssl-dev 外,其他的套件是給 PIL 用的
$ sudo apt-get install liblcms1-dev zlib1g-dev libfreetype6-dev libjpeg62-dev libsqlite3-dev libssl-dev

# 安裝 Python2.5.5 至 /usr/local
$ tar -jxf Python-2.5.5.tar.bz2
$ cd Python-2.5.5
$ ./configure -with-zlib=/usr/include
$ make
$ sudo make install

# 安裝 GAE 相依模組 ipaddr
$ tar -zxf ipaddr-2.1.1.tar.gz
$ cd ipaddr-2.1.1/
$ sudo /usr/local/bin/python2.5 setup.py install

#安裝 PIL
$ tar -zxf Imaging-1.1.7.tar.gz
$ cd Imaging-1.1.7
# 修改 setup.py 中的使用函式庫位置
# LCMS_ROOT = '/usr/lib'
# TCL_ROOT = '/usr/lib'
# JPEG_ROOT = "/usr/lib"
# ZLIB_ROOT = "/lib"
# TIFF_ROOT = '/usr/lib'
# FREETYPE_ROOT = "/lib"

#檢查模組是否可使用
$ /usr/local/bin/python2.5 setup.py build_ext -i
#測試模組
$ /usr/local/bin/python2.5 selftest.py
$ sudo /usr/local/bin/python2.5 setup.py install

最後,再把 dev_appserver.py, appcft.py 中的 #!/usr/bin/env python 改成 #!/usr/bin/env python2.5 即可。這樣就可以在 Ubuntu 10.04 中開發 GAE 程式了。

五月 24, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» web2py I18N Translation Tool

web2py 是個類似 Django 或 Ruby on Rails 的 web application framework,使用案例之一是 Sahana Eden,Sahana 是一套災難管理系統,最早以 PHP 語言開發,後來有 Python 語言的分支版本,稱為 Eden,便是採用 web2py 開發架構。
web2py 以 Python dictionary 為基礎,有個處理介面訊息翻譯的內部引擎,在管理頁面就可以編輯訊息檔內容,檔案放在 applications 目錄裡專案的 languages 目錄。不過,要是想利用 PO 檔來管理訊息翻譯,就得搭配 web2py2po 工具,原始碼在 nursixsourceforge 上。

» Developer Options for Plone 4

從 Plone 4 beta 版本開始,buildout.cfg 裡關於
開發者的設定值,被獨立放在 develop.cfg 檔案裡,如此一來,paster 和 ZopeSkel 之類的工具,預設就不會馬上安裝,要額外執行指令,才會安裝開發工具:

bin/buildout -c develop.cfg
安裝開發工具後,還可以測試寄送通知信的工作,這類開發測試的工作獨立出來後,可以進一步簡化一般使用者的安裝步驟。

五月 5, 2010

limodou的學習記錄
limodou
limodou的学习生活 is about »
» web2py中的block支持

这两天web2py中的Thadeus Burgess与我讨论起uliweb中的模板,他想做移植,因为uliweb中的模板是来源于web2py的,但是经过我的修改支持block语法。不过就不再支持原来的{{include}}的。Thadeus Burgess进行了比较大的修改,现在已经被Massimo合并到web2py的trunk中了。对web2py感兴趣的同学可以去试试了。现在的web2py的模板既可以象以前一样使用,也可以使用block了。不过我没有把这个新的代码合并到uliweb中,因为有些功能还是不太一样,所以应该不会合并的。
类别:Python 查看评论

五月 4, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Get Id of Items

My customized content types need a link passing its ID to another PHP script. This PHP script looks into database and performs based on the ID. Here is the sample page template:

<div tal:define="itemId context/getId;
itemIdUpper python: itemId.upper()">
<a href=""
tal:attributes="href python: 'http://another.site.com/some.php?k='+itemIdUpper;
title itemIdUpper;">Show in Another App</a>
</div>

四月 29, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Plone 4 Upgrading

目前 Plone 4 處於 beta 2 階段,測試 Plone 3 昇級的結果,還算順利,值得一提的訊息有:

INFO PythonScripts Some of your Scripts have stale code cached.
Since Zope cannot use this code, starup will be slightly slower
until these Scripts are edited.
You can automatically recompile all Scripts that have this problem
by visiting /manage_addProduct/PythonScripts/recompile
of your server in a browser.
ERROR PortalTransforms Cannot register transform rtf_to_html,
using BrokenTransform: Error Unable to find binary "rtf-converter"
工作原理和以前一樣,把 Data.fs 放到新版環境裡的 var/filestorage 再啟動,同樣有 dry run mode 提示,但整體的介面訊息變得更清楚。
目前遇到的狀況是 webcouturier.dropdownmenu 在昇級後,造成 LocationError: (None, 'html_tag') 的錯誤訊息,來源之一是 webcouturier/dropdownmenu/browser/dropdown_recurse.pt Line 29, Column 12。事先把 dropdownmenu 模組停用,就可以避掉這問題。
另外,可能會遇到 Default Theme 跳到 Unstyled 的狀態,只要進 plone_control_panel 或 @@skins-controlpanel 指定為佈景主題為 Plone Classic Theme 或 Sunburst Theme 就搞定。

四月 21, 2010
» (又)一個小而美的 Python 網站框架:Flask

荒廢好久的網誌,因有沒有網站開發經驗的人寫信問我關於 Pylons 的問題,特此更新一文。

聲明在先,此文並不是為了回答 Pylons 的問題而寫的,而是分享另一個 Web Framework(是的,又來了)。 

近日聽說了一個看來更小,更簡單而且(表面)也很優雅的 Python 網站框架:Flask

我想對沒有相關經驗的人而言,東西愈小愈容易學習,如果這東西還有良好而成熟的設計,那就更棒了。Flask 正是一個看起來像這樣的東西。在 Python 經歷了 ZopeDjangoTurboGearsPylonsBottle 等等網站框架之後,還是有人另外寫了這個網站框架,我猜……它別有意圖

 不過它意圖在官網也寫得很清楚,就是(另)一個微網站框架(Micro Web Framework)。什麼是「微」(micro)?原諒我忍不住想在這裡簡單地說,就是「很小」(very small)。(給認真魔人的連結:"Flask - Foreword - What does Micro Mean?")

好吧官網上還寫了一些也許有點可口的菜單:

都流口水了。不過不免一提上述的功能 Pylons 也幾乎都內建了。

呃,時光匆匆,我該睡了,最後幾分鐘剛好來裝個網站框站跑個應用程式起來。

安裝:(更詳細的官網安裝說明連結
easy_install Flask

寫一個 Hello 網站應用程式(都這種時候了,當然是從官網上複製過來的):
檔名:hello.py


from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()


跑:
python hello.py

四月 16, 2010
» Virtualenv 簡單入門

功用

使用 Virtualenv 可以讓你預先建立一個虛擬環境,在虛擬環境中開發 Python 程式,可以保持 Python path 乾淨,並減少因為機器上需要同時支援不同版本函式庫,造成各函式庫彼此之間相依性的困擾。

而且使用虛擬環境後,到時要將環境轉移到別台機器上,也減少很多設定上的問題。

安裝

$ easy_install virtualenv

設定環境

$ virtualenv --no-site-packages [dev_place]

即建立一個名為 [dev_place] 的資料夾(中括號裡的名稱自行填寫取代)。

切換到虛擬環境

進入 [dev_place] 目錄,輸入命令:

$ source bin/activate

若看到路徑提示前多了個([dev_place])符號,即表示已經進入了虛擬環境。

這時我們可以使用預設提供的 easy_install 工具安裝要使用的函式庫、或是安裝各種 Python 程式。

安裝的函式庫會被放到 [dev_place]/lib/Python[版本]/site-packages/ 目錄中,跟一般的 Python 函式庫配置方式相似。

離開虛擬環境

要離開虛擬環境,只需輸入命令:

$ deactivate

即可回到預設的命令行狀態。

其他操作

如果你的電腦上有裝多個 Python 版本,在下 virtualenv 命令時加上「--python=python[版本] 」當作參數,例如建立2.6版的虛擬環境命令為

$ virtualenv --no-site-packages [dev_place] --python=python2.6

也可以建立出不同版本的 Python 虛擬環境,讓你可以更容易地在多個 Python 版本間做測試。

其他使用方法可以輸入「virtualenv --help」參考印出的說明。

四月 13, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Changing Tabs with Viewlet

在 Plone 的 Navigation Settings 裡,利用 automatically generate tabs 的設定,可以在 portal-globalnav 區域自動產生根目錄的 tab 項目,如果只想限定目錄自動產生為 tab 項目,那就把 Generate tabs for items other than folders 取消勾選,如果某個自動產生的目錄 tab 項目,不希望它出現在 portal-globalnav 區域,除了取消自動產生 tab 項目的方式外,還可以動手修改 viewlet 來達成。

上述的 portal-globalnav 名稱,是從 CSS 角度來稱呼它,用 firebug 查得到它在 CSS 檔案的位置,如果是從 viewlet 角度來稱呼它,它的名稱是 global_sections。



例如根目錄有個名稱為 tmp 的目錄,不希望它出現在 portal-globalnav 區域,到 portal_view_customizations 裡的 plone.global_sections 加個 tal:condition 就行:

<ul id="portal-globalnav">
<tal:tabs tal:repeat="tab view/portal_tabs">
<li tal:attributes="
id string:portaltab-${tab/id};
class python:view.selected_portal_tab==tab['id']
and 'selected' or 'plain'">
<a href=""
tal:condition="python: tab['id'] != 'tmp'"
tal:content="tab/name"
tal:attributes="href tab/url;
title tab/description|nothing;">
Tab Name
</a></li></tal:tabs>
</ul>
想要知道有哪些 viewlet 以及它們的位置,可使用 http://localhost:8080/Plone/@@manage-viewlets 之類的網址來查詢。

» Changing Tabs with CSS

在 Plone 的 Navigation Settings 裡,利用 automatically generate tabs 的設定,可以在 portal-globalnav 區域自動產生根目錄的 tab 項目,如果只想限定目錄自動產生為 tab 項目,那就把 Generate tabs for items other than folders 取消勾選,如果某個自動產生的目錄 tab 項目,不希望它出現在 portal-globalnav 區域,除了取消自動產生 tab 項目的方式外,還可以動手修改 viewlet 來達成。

例如根目錄有個名稱為 tmp 的目錄,不希望它出現在 portal-globalnav 區域,到 portal_view_customizations 裡的 plone.global_sections 加個 tal:condition 就行:

<ul id="portal-globalnav">
<tal:tabs tal:repeat="tab view/portal_tabs">
<li tal:attributes="
id string:portaltab-${tab/id};
class python:view.selected_portal_tab==tab['id'] and 'selected' or 'plain'"
><a href=""
tal:condition="python: tab['id'] != 'tmp'"
tal:content="tab/name"
tal:attributes="href tab/url;
title tab/description|nothing;">
Tab Name
</a></li></tal:tabs>
</ul>

四月 4, 2010

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Plone3 Theme

概念Plone3 Theme 包括 template (page template)、stylesheet (CSS)、image 三種類型,以及 browser、skin 兩種機制。剛接觸 Plone 的朋友,先從修改 image 和 CSS 下手,比較容易入門。

以 CSS 為例,開發的準備工作之一,要將 Plone 執行模式設定成 debug mode 而非 production mode,也就是 parts/instance/etc/zope.conf 檔案的內容,要有下列的設定結果:

debug-mode on
這樣 CSS 修改結果才能馬上生效,而不會受到 cache 和 compression 的影響。

在 ZMI 的 plone_skins/plone_styles 裡,找得到 ploneCustom.css 檔案,預設是個空白範例,可以用來測試設定效果。想要修改它,先確定下拉選單的選項是 custom,再按 Customize 鈕,這樣會把這份灰底設定檔複製到 portal_skins/custom 目錄,並打開在網頁上等待編輯。值得留意的是,僅管下列內容看似是註釋文字,但它們是會被執行的程式碼,通常不該被刪除:
/*  (do not remove this :) */
/* <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either :) */

/* </dtml-with> */
除此之外的 /* */ 內容都是註釋文字,要刪要留,悉聽尊便。

例如,下列是一段可以讓版面置中對齊的設定範例:
#visual-portal-wrapper {
background: #aaaaaa url(&dtml-portal;_url;/banner.jpg) no-repeat top left;
margin-left: auto !important;
margin-right: auto !important;
width: 900px !important;
}
還有 sectional CSS 的範例,可以單獨修改首頁的顯示方式。更多的資訊,可參考 Plone 3 Theming 書籍。

四月 3, 2010
» Flickr Random Image Picker

P6216480
Annecy.France

It's a small tool written to randomly show my photos from flickr. I quite enjoy viewing photos in this way. It helped me to discover photos that I didn't notice before. However, there are some limitations to it:
1. in current configuration, 10 photos will be shown every time I launch it. it takes too much time to do so. I have to wait for tens of seconds or even longer.
2. in GUI version, no thread is implemented, so the UI is blocked after the button is pressed.

To make it better, I did some minor changes:
1. create a thread for fetching photos from flickr, and use wx events to post event to htmlwindow. Don't know how to use lock or mutex under python yet, though...

import threading
from time import sleep

(FetchDoneEvent, EVT_FETCH_DONE) = wx.lib.newevent.NewEvent()

class FetchThread(threading.Thread):
def __init__(self,w):
threading.Thread.__init__(self)
# windows for posting events
self.w = w

def run (self):
fi = None
for x in range(10):
print x
if fi == None:
(content,fi) = fetch_photo()
else:
content = fetch_photo(fi)

evt = FetchDoneEvent(source=content)
while (self.w.loading):
sleep(0.5)
wx.PostEvent(self.w, evt)

class MyHtmlWindow(html.HtmlWindow):
def __init__(self, parent, id ):
html.HtmlWindow.__init__(self, parent, id, style=wx.NO_FULL_REPAINT_ON_RESIZE)
self.Bind(EVT_FETCH_DONE, self.OnFetchDone)
self.loading = 0

def OnLinkClicked(self, linkinfo):
import os
os.startfile(linkinfo.GetHref())

def OnFetchDone(self, e):
#self.LoadPage("myflickr.html")
self.loading = 1
if self.start_fetching != 1:
self.AppendToPage(e.source)
else:
self.SetPage(e.source)
self.start_fetching = 0
self.loading = 0

class SimpleFrame(wx.Frame):

def __init__(self, *args, **kwargs):
...

def OnButtonClicked(self,e):
FetchThread(w=self.html).start()
self.html.SetPage("

Fetching......

")
self.html.start_fetching = 1
2. add a function to only return a photo info at a time, instead of returning a html file with 10 photo infos.
def fetch_photo(fi=None):
print 'fetch_photo'
if fi == None:
fi = FlickrIndex(API_KEY, SECRET_KEY, MY_USER_ID)
return fi.print_random_photos(10),fi
else:
return fi.print_random_photos(10)

A Feedjack powered Planet
A Django site.