顯示包含「雜項」標籤的文章。顯示所有文章
顯示包含「雜項」標籤的文章。顯示所有文章

2013年10月23日星期三

Mac版OpenOffice介面字體修正及使用Automator模擬全螢幕


OpenOffice介面字體修正

話說半年前我一直打算換筆電,可是老是物色不到合意的,經過數月的評估和Scouting後,決定捨棄萬惡的微軟視窗,投向Mac的懷抱。我上一次用Mac,已是大學時用大學電腦室的機器,那大概是Macintosh Classic或Color Classic,所以我認為自己跟Mac新手沒有分別。從萬年Win用家變成Mac友,一開始不習慣是早料到的,但因為自己目前的工作都只依賴瀏覽器(Google Chrome)和文書工具(OpenOffice.org),所以猜想影響不會太大。結果反而叫我意外,Mac OS X相當易上手,縱使有些在Win系統是理所當然必備的東西而Mac竟然沒有,整體上Mac感覺還是比Win好用。

然而,當我安裝了Mac版的OpenOffice.org 3.4.1後,一打開,不禁皺一下眉。天啊,為什麼介面的中文字型毫不統一?這是模仿綁架信風格嗎?


因為沒影響功能,所以我便沒理會,可以一兩個星期後,總是覺得礙眼。我上網找解決方法,可是沒有明確說明情況的網頁,正打算放棄時,偶然從一些描述其他問題的網頁找到端倪。仔細研究一下,再試了幾個方法,找到最簡單修理的途徑。我在這兒說說,留個記錄,希望能幫到跟我一樣有相同問題的人。

首先,打開OpenOffice的「喜好設定」,在左側「OpenOffice.org」的欄目中,選「字型」。


點選「使用取代清單」,再在正下方的「字型」選單中,鍵入「方正明體」。別嘗試在選單裡找,要直接用鍵盤輸入這四個字,因為如果你能在選單中找到「方正明體」,介面便不會如此一塌糊塗了。之後在「取代成」的選單中選出你想要的介面字型(我建議使用Apple LiGothic/蘋果儷中黑),然後按右面的剔號,再選取選單中的「自動」。之後按確定。


介面便修好了。


如果我沒理解錯誤的話,OOo內部設定了中文介面字型為「方正明體」,但由於我的Mac(和你的Mac)沒有這字型,所以程式便亂選一氣,變成如此古怪的情況。上述的做法,其實是指示程式一旦遇到要求「方正明體」的字型,便自動以你選的另一種字型(例如儷中黑)代替。嚴格來說,直接修改OOo的內部設定檔比較好,但上述的方法較簡單。(你喜歡的話,用娃娃體當介面字型也可以)(爆)



模擬全螢幕

再來是全螢幕的問題。我的Mac是Air 11吋,Mountain Lion,使用Mission Control製造多個桌面、將一些軟體打開成全螢幕十分方便。我習慣了「Dashboard、桌面1、全螢幕Chrome、桌面2、全螢幕行事曆」的配置,OpenOffice便在桌面2打開。然而,我沒想到,OpenOffice居然沒有加入Mac全螢幕功能。OpenOffice有「內置全螢幕」,但一使用,菜單和工具列都會消失。我只會在讀稿時使用那個內置功能,平時打字一定用普通的環境。問題是,非全螢幕的Mac軟體,全部都要讓路給下方的Dock。


要拿走那個Dock,讓OOo的編輯空間增大,有兩個選擇,一是將Dock搬到左方或右方變成直立式,一是使用Dock的「隱藏功能」,在滑鼠指標移到畫面下方時Dock才冒出來。我覺得後者較好,可是,一般Mac的全螢幕軟體都很聰明,我移到全螢幕的程式,Dock會自動隱藏,而我跳到旁邊的桌面,Dock又會自動升回原位。為什麼OOo沒有啊……

我希望OOo有這樣的功能:
1.打開時會替我自動隱藏Dock,並放到最大
2.切換至其他程式時,Dock會自動冒出
3.再切換回OOo時,Dock會再次自動隱藏
4.關掉OOo後,Dock會自動關掉隱藏功能

在學習Mac的操作時,我發現了Automator這個偉大的工具。原來Mac內置了「自動化機器」的軟體,容許用家編寫指令,為任何程式添加功能。我審視了好一陣子,瀏覽過好些網頁,發覺Automator配合Applescript(蘋果的Script語言)或者可以做到我上述的要求。求人不如求己,我便寫了一個App,讓OOo模擬全畫面運作。我以下會說明做法,不過先聲明一點,我只用了一個月Mac,對Applescript理解不深,以下做法我不保證在所有機器上都能正常運作,如果在你的Mac上沒成功,別問我解決方法。(我也不知道升級至Maverick後是否繼續正常運作,但至少在我的山獅上,這方法OK)

首先要確認一下「允許使用輔助設備」的選項有沒有打開。這選項在左上角蘋果圖示裡,「系統偏好設定」、「輔助使用」,再在左下角找到。其實我不肯定是否一定要打開,但如果要用Automator自動按一些介面按鈕,這選項一定要選。(我以下的Script改過幾次,最新版本好像不用也可以,不過還是打開這選項較好吧,我懶得測試這細節了)

先打開Launchpad,在「其他」的程式組合裡找出「Automator」,打開。你會看到以下畫面:


在中間的七個文件類型中,選「應用程式」,按選擇。在左面的欄目中,選「工具程式」,再將第二欄中的「執行AppleScript」拖到右面那一大片空間上。


將「on run……end run」的文字全刪去,把以下的Script貼上:

----------------------------------------------------
--Toggle Dock Autohide function
----------------------------------------------------
on toggleDock(toggleOn)
tell application "System Events" to set autohide of dock preferences to toggleOn
tell application "System Events" to set translucent menu bar of current desktop to not toggleOn
end toggleDock

----------------------------------------------------
--Main program starts
----------------------------------------------------
on run {input, parameters}

----------------------------------------------------
--START hiding the annoying gear animation icon in menu bar
----------------------------------------------------

tell application "System Events"
set isAutomator to exists process "Automator Launcher"
end tell
if isAutomator then tell application "Automator Launcher" to quit

----------------------------------------------------
--END hiding the annoying gear animation icon in menu bar
----------------------------------------------------

----------------------------------------------------
--START Data you can change
----------------------------------------------------
set appName to "OpenOffice.org"
-- The Application you want to make fullscreen

set waitTime to 2
-- Wait Time, in second. Smaller value for faster response, but uses up more system resources.

set mainWindowThreadHold to 0.8
-- Threadhold, used to identify the main window.
-- Default is 0.8, which means all windows of target application with 80% screen size would be maximized.

----------------------------------------------------
--END Data you can change
----------------------------------------------------

set debugMode to false

tell application "Finder"
set screenSize to bounds of window of desktop
set screenWidth to (item 3 of screenSize)
set screenHeight to (item 4 of screenSize)
set scrWidthT to (item 3 of screenSize) * mainWindowThreadHold
set scrHeightT to (item 4 of screenSize) * mainWindowThreadHold
end tell


toggleDock(true)
set inputFile to input as string
tell application appName
activate
if inputFile is not equal to "" then
repeat with i from 1 to count of input
open item i of input as string
end repeat
end if
end tell
delay 3 -- wait 3 seconds. Some apps need time to start.

tell application "System Events"
if exists process appName then set frontmost of process appName to true
try
if inputFile is equal to "" then
tell process appName
set position of window 1 to {0, 0}
set size of window 1 to {screenWidth, screenHeight}
end tell
end if
on error
if debugMode is true then display dialog "Error in initializing window(s)"
end try
end tell


repeat
if application appName is not running then exit repeat

tell application "System Events"
if exists process appName then
if frontmost of process appName then
if translucent menu bar of current desktop is true then
set translucent menu bar of current desktop to false
end if
if autohide of dock preferences is false then
set autohide of dock preferences to true
delay 0.5
try
tell process appName
repeat with myWin in windows
set mySize to size of myWin
set myWidth to item 1 of mySize
set myHeight to item 2 of mySize
if myWidth > scrWidthT and myHeight > scrHeightT then
--click button 2 of myWin
set position of myWin to {0, 0}
set size of myWin to {screenWidth, screenHeight}
end if
end repeat
end tell
on error
if debugMode is true then display dialog "Error in resizing window(s)"
end try
end if
else
if translucent menu bar of current desktop is false then
set translucent menu bar of current desktop to true
end if
if autohide of dock preferences is true then
set autohide of dock preferences to false
end if
end if
end if
end tell
delay waitTime
end repeat

toggleDock(false)

return input
end run

按Command-S儲存。app的名字你可以隨意改,例如「我的OOo.app」,位置也可以隨便放(放桌面也可,不過我建議放在其他資料夾,再為這個app建一個替身放桌面)。結束Automator,它功成身退了。以後,你便可以打開這個新建的App代替OpenOffice,它會替你隱藏Dock、打開OOo、放到最大,並且在切換至其他程式時,自動升降Dock。這App支援拖放文件到圖示來打開,你也可以像我一樣把圖示換成OOo,將替身放桌面。以下是運作時的樣子:



其實這段Script不單能應用到OOo,也可以改成LibreOffice或其他軟體,只要改掉Script中部分關鍵字便可以(我已將可以改的變數集中放在開頭)。各位有興趣可以隨意複製修改發佈使用,但如果你想改但不懂編程,請先找些入門網站看看再試。這個小工具本來只是我為了自用而編寫的,所以我懶得逐行說明,而且流程滿簡單的,我想懂一點AppleScript的朋友也能看懂。

2010年4月29日星期四

OpenOffice的小工具:字數顯示器


(本來想發在另一個部落格,但想想這邊應該較多有需要的用戶,橫豎跟寫作相關,貼這邊了)
譚劍兄的部落格看到他感嘆OpenOffice沒有像MS Word長期顯示字數的功能,在下作為OOo的支持者,便去找找看有沒有plugin可用(OOo是開放源碼軟件,吸引了不少開發者為他們編寫擴充插件)。說來有趣,我從來沒想過讓文字處理器不斷更新字數,但細心一想,這也的確很方便。找了好些插件也沒有完全合用的,於是往巨集的方向出發,結果找到一個好東西:Real-Time Word Count MACRO

然而,這個巨集是外國人用的,所以是Word Count(字數)不是Character Count(字元數),這對咱們中文系統的沒啥用。既然如此,我便發揮典型的developer精神--它沒有這個功能,便自己寫囉。(爆)

其實也不是真的自己寫,上面那個WordCount MACRO已十分完整,只要把計算字數的地方換成計算字元便行。可是,我從沒寫過Python,到OOo看API Reference,他們又寫得含糊。我實在懶得花時間去慢慢學Python和OOo API入門,於是用囫圇吞棗的方式,利用吃完晚飯的休息時間把WordCount改成以下的CharCount:


# Continuously updating word count
import unohelper, uno, os, time
from com.sun.star.i18n.WordType import WORD_COUNT
from com.sun.star.i18n import Boundary
from com.sun.star.lang import Locale
from com.sun.star.awt import XTopWindowListener

#socket = True
socket = False
localContext = uno.getComponentContext()

if socket:
resolver = localContext.ServiceManager.createInstanceWithContext('com.sun.star.bridge.UnoUrlResolver', localContext)
ctx = resolver.resolve('uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
else: ctx = localContext

smgr = ctx.ServiceManager
desktop = smgr.createInstanceWithContext('com.sun.star.frame.Desktop', ctx)

waittime = 5 # seconds
goal = 0

def printOut(txt):
if socket: print txt
else:
model = desktop.getCurrentComponent()
text = model.Text
cursor = text.createTextCursorByRange(text.getEnd())
text.insertString(cursor, txt + '\r', 0)

def updateCount(wordCountModel, percentModel):
'''Updates the GUI.

Updates the word count and the percentage completed in the
Tkinter GUI. If some text of more than one word is selected,
it updates the GUI based on the selection; if not, on the
whole document.'''

model = desktop.getCurrentComponent()
try:
if not model.supportsService('com.sun.star.text.TextDocument'):
return
except AttributeError: return

try: wc = model.CharacterCount
except AttributeError: return

wordCountModel.Label = str(wc)

if goal != 0:
pc_text = '(%.2f %%)' % (100 * (wc / float(goal)))
percentModel.Label = pc_text

# This is the user interface bit. It looks more or less like this:

###############################
# Word Count _ o x #
###############################
# _____ #
# 451 of |500| (90.20 percent)#
# ----- #
###############################

# The boxed `500' is the text entry box.

class WindowClosingListener(unohelper.Base, XTopWindowListener):
def __init__(self):
global keepGoing

keepGoing = True
def windowClosing(self, e):
global keepGoing

keepGoing = False
e.Source.setVisible(False)

def addControl(controlType, dlgModel, x, y, width, height, label, name = None):
control = dlgModel.createInstance(controlType)
control.PositionX = x
control.PositionY = y
control.Width = width
control.Height = height
if controlType == 'com.sun.star.awt.UnoControlFixedTextModel':
control.Label = label
elif controlType == 'com.sun.star.awt.UnoControlEditModel':
control.Text = label

if name:
control.Name = name
dlgModel.insertByName(name, control)
else:
control.Name = 'unnamed'
dlgModel.insertByName('unnamed', control)

return control

def loopTheLoop(goalModel, wordCountModel, percentModel):
global goal

while keepGoing:
try: goal = int(goalModel.Text)
except: goal = 0
updateCount(wordCountModel, percentModel)
time.sleep(waittime)

if not socket:
import threading
class UpdaterThread(threading.Thread):
def __init__(self, goalModel, wordCountModel, percentModel):
threading.Thread.__init__(self)

self.goalModel = goalModel
self.wordCountModel = wordCountModel
self.percentModel = percentModel

def run(self):
loopTheLoop(self.goalModel, self.wordCountModel, self.percentModel)

def charCount(*args):
'''Displays a continuously updating character count.'''
dialogModel = smgr.createInstanceWithContext('com.sun.star.awt.UnoControlDialogModel', ctx)

dialogModel.PositionX = 300
dialogModel.PositionY = 20
dialogModel.Width = 100
dialogModel.Height = 16
dialogModel.Title = 'Char Count'

lblWc = addControl('com.sun.star.awt.UnoControlFixedTextModel', dialogModel, 2, 2, 20, 14, '', 'lblWc')
lblWc.Align = 2 # Align right
addControl('com.sun.star.awt.UnoControlFixedTextModel', dialogModel, 23, 2, 10, 14, '/')
addControl('com.sun.star.awt.UnoControlEditModel', dialogModel, 30, 2, 25, 14, '', 'txtGoal')

addControl('com.sun.star.awt.UnoControlFixedTextModel', dialogModel, 62, 2, 50, 14, '(%)', 'lblPercent')
addControl('com.sun.star.awt.UnoControlFixedTextModel', dialogModel, 114, 2, 12, 14, '', 'lblMinus')

controlContainer = smgr.createInstanceWithContext('com.sun.star.awt.UnoControlDialog', ctx)
controlContainer.setModel(dialogModel)

controlContainer.addTopWindowListener(WindowClosingListener())
controlContainer.setVisible(True)
goalModel = controlContainer.getControl('txtGoal').getModel()
wordCountModel = controlContainer.getControl('lblWc').getModel()
percentModel = controlContainer.getControl('lblPercent').getModel()

if socket:
loopTheLoop(goalModel, wordCountModel, percentModel)
else:
uthread = UpdaterThread(goalModel, wordCountModel, percentModel)
uthread.start()

keepGoing = True
if socket:
charCount()
else:
g_exportedScripts = charCount,

# Disclaimer and license from acb's macros
#
# Standard disclaimer and MIT licence .
# These macros are copyright (c) 2003-4 Andrew Brown.
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the 'Software'), to deal in the Software without
# restriction, including without limitation the rights to use, copy,
# modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
用法是先把以上的程式碼貼到記事本,把檔案命名為CharCount.py,放到OpenOffice下的子目錄「\Basis\share\Scripts\python」。打開OpenOffice Write,「工具→巨集→執行巨集」,在左邊選「OpenOffice.org巨集」,會找到一個叫「charcount」的項目,執行。


看,字元數目的視窗出來了。你可以在那個空格輸入目標字數,後方便顯示進度百分比(不過那個目標字數要每次輸入,暫時沒法儲存下來)。如果覺得每次打開OOo也要按一次「工具→巨集→……」很麻煩,你可以在「工具→自訂」裡設Hotkey,在「鍵盤」頁裡選一個你喜歡的熱鍵(我選Shift+F3),在下方函數種類選「OpenOffice巨集→share→charcount」,然後按上方的「修改」,以後只要按指定的鍵(例如Shift+F3)便會執行了。


放在上方,還有空位放iTune Mini-player!

原來的word count的功能更完善,可以讓用戶選擇文字,顯示選擇中的段落的字數,但我Trace Code後發覺改這部分很麻煩,OOo的API裡要計算某段文字的字元數沒有直接用的函式,自己計算的話又不準(會錯誤計算換行的字元),要準的話又花時間(運算時間),結果不改了,讓這個小程式更簡潔吧(老實說,修改期間花了80%以上的時間在研究這方面,如果單純要改成現在的樣子,真是五分鐘也不用……)。現在更新速度是五秒一次,想快些的話可以把「waittime = 5 # seconds」那個5改成3或1,不過別忘了愈小愈吃資源。

最後提醒一下,Python是一種以空白位元來計算流程的高階語言,所以不要多手把程式碼前方的空白增減耶。

2009年9月1日星期二

推理成癮:推理及創作專門網誌

突然弄這個部落格出來,可不是在下一時興起,而是經過深思熟慮的。事實上,去年已有這個打算,可是一直拖著拖著,今天才成事。

設這個BLOG純是為了讓自己有個小地方,撰寫一下一些中文推理的讀後感,以及討論一下小說創作的心得而已。本來的部落格混七雜八,一時談科技、一時聊時事、偶而寫寫廢話,實在有夠混亂,故此把上述的兩項拉出來,另闢新地,方便彙整。我當然不會把話說死,保證一個月寫多少篇文章(我可不像嘉振兄那麼有毅力 XD),遇上想寫的題材時便會寫,不過近年中文推理的數量有增無減,我想,把這兒獨立出來是個正確的決定。

除了中文推理,我會不會把外國推理小說的心得放這兒呢?唔……我還未決定。一切隨緣吧,反正我一向喜歡不按牌理出牌。(笑)