Top > OOobbs2 > 143
** [[OOobbs2/143]] [#n9c5b288]
-''サマリ'': Python マクロコンソール
-''環境'': General
-''状態'': 未解決
-''投稿者'': [[はにゃ?]]
-''投稿日'': 2008-09-18 (木) 22:16:56

*** 質問 [#w6878bdb]
[[OOobbs2/141]] に関連して以前作りかけの Python マクロコンソールを Writer をコンソールとして作り直しかけてるもの。色々 (Writer の API などを) 使いそうなのでメモなどとして書いておきます。

#contents
** 概要 [#a57bc1f5]
OOo では Python でマクロを記述することが出来ます。Python の code モジュールを使用すればインタラクティブなコンソールが作成できます。OOo のウィンドウにテキストエディットを使って作成したものはいまいちでした (テキストエディットの機能が不十分だったため?)。

Writer をコンソール代わりにすればもう少しだけ使えるのかも?
** ファイル [#x00b1626]
多数の問題点があります。下記参照。

- プロトタイプ: &ref(pycsl_01.zip);~
とりあえず、普通に Python をコンソールから立ち上げた時のようなインタラクティブコンソール。

** 使い方 [#bc4110e6]
+ pycsl.py ファイルをユーザー Scripts/python 以下に入れる
+ マクロの実行、または Python マクロの管理から pycsl - start_NewPyConsole を実行する
+ 新規 Writer ドキュメントが作成されてプロンプトが表示されます

下記の変数が追加されています。XSCRIPTCONTEXT, ctx, smgr, desktop。
 XSCRIPTCONTEXT # com.sun.star.script.provider.XScriptContext
 ctx = XSCRIPTCONTEXT.getComponentContext()
 smgr = ctx.ServiceManager
 desktop = XSCRIPTCONTEXT.getDesktop()

Ctrl - C が効かないので for i in range(10000): print i などとしないでください。出力されている間は Writer がフリーズしたりします。(gotoEnd をやめると少しましになりましたが。)

二つ以上コンソールを立ち上げると出力がおかしくなります。(下記参照)
** 問題点 [#uf591c13]

- OOo 内で存在する Python のインスタンスはひとつだけ。そのため、コンソールを二つ以上使用しようとすると標準出力が別々にならない。~
各行を読み込む前に標準出力を切り替えればよいのかもしれないが、別のコンソールで実行したものがなにかしら動作中の場合変なことになる。~
さらに、拡張機能などからも・・・。

- 出力が遅い~
コントローラをロックすべき?と思ったが、Writer には Calc のようにコントローラをロックできない。
** ToDo [#y054af86]

- 最終行からのみ読み込むように~
Enter を押したときに最終行範囲とカーソルのある行範囲を比較
- 最終行のプロンプトを削除不可に
- 最終行にテーブル、画像などを挿入させないようにする?
- 全クリア
- 一行の出力が 64k を超えたときの処理
- 履歴機能。上下キーで履歴を表示すると、カーソル移動が出来なくなるが。
- Ctrl - C くらいは受け付けるように
- オートコレクト最低
- 終了 (コンソールの終了はバージョンと環境によって異なるのでどのタイプに)
- 書き出し速度の向上? (PyConsole parastyle を各段落に適用するより標準をいじるほうが。今のところ、各行ごとに設定されている)
- 改行を含む s = """\ hoge """ が動かない

- キー操作無効化
- メニューからの操作無効化
- コンテキストメニュー操作無効化

- 問題点の解消…。

- 使い途を見つける
** メモ [#x8a054d1]

 oDoc = ThisComponent
 oController = oDoc.getCurrentController()
 oText = oDoc.getText()
*** 最後の段落のテキストを取得 [#p5fab41b]
  oCursor = oText.createTextCursorByRange(oText.getEnd())
  oCursor.gotoStartOfParagraph(True)
  sTxt = oCursor.getString()

*** 最後の行 [#g9ecb991]
 oCursor.gotoStartOfSentence(True)
 sTxt = oCursor.getString()

最後の行のテキスト範囲が欲しいときには oCursor を使う。

 def get_last_linerange(text):
     cursor = text.createTextCursor(text.getEnd())
     cursor.gotoStartOfSentence(False)
     cursor.gotoEndOfSentence(True)
     return cursor

*** ビューカーソル関連 [#w7cc659a]
コマンドを入力する行でのキー操作に制限をかけるために現在のカーソル位置のテキスト範囲と最後の行のテキスト範囲を知る必要がある。また、その位置関係も調べる。

*** 現在の段落 [#i88ecb00]
 def get_current_pararange(text, view_cursor):
    cursor = text.createTextCursorByRange(view_cursor)
    cursor.gotoStartOfParagraph(False)
    cursor.gotoEndOfParagraph(True)
    return cursor
*** 現在の行 [#pb19e065]
 def get_current_linerange(text, view_cursor):
    cursor = text.createTextCursorByRange(view_cursor)
    cursor.gotoStartOfSentence(False)
    cursor.gotoEndOfSentence(True)
    return cursor
*** 位置関係 [#h20e12c7]
 controller = doc.getCurrentController()
 view_cursor = controller.getViewCursor()
 text = doc.getText()
 
 last_range = get_last_linerange(text)
 current_range = get_current_linerange(text)
 print text.compareRegionStarts(last_range, current_range)
 print text.compareRegionEnds(last_range, current_range)

この方法で比較すると、二つの比較結果が 0, 0 になるとき同じ範囲。

*** カラム位置 [#la238dc3]
現在の行内でのカーソルの桁位置。

 def get_current_column(text, view_cursor):
     if view_cursor.isAtStartOfLine():
         return 0
     elif view_cursor.isAtEndOfLine():
         txt = get_current_sentence(text, view_cursor)
         return len(txt)
     else:
         cursor = text.createTextCursorByRange(view_cursor)
         cursor.gotoEndOfSentence(True)
         txt = cursor.getString()
         return len(txt)
フィールドがあると文字数が狂う。テキスト範囲から com.sun.star.container.XContentEnumerationAccess を利用すれば、そのテキスト範囲内にある個別のフォーマット範囲やフィールドなどを分割して取得できるが…。
*** ビューカーソルの移動 [#eb8db94e]
ビューカーソルは com.sun.star.view.XViewCursor、XScreenCursor、XLineCursor や com.sun.star.text.XTextViewCursor、com.sun.star.text.XTextCursor などで移動できるが実行速度が遅い。

 for i in range(10000): print i

としたとき、毎回 gotoEnd としてカーソルを最終行の最後に移動させると数分かかる。gotoEnd をなしにすると二、三十秒。これでも普通のコンソールより非常に遅い。出力はバッファなどに入れて呼び出し回数?ごとに書き出す方がよさそう。

*** テキストの追加 [#x822c2c9]
API から Writer ドキュメントの最後にテキストを追加していくとき、一番早い方法は?

 def append_a():
     doc = XSCRIPTCONTEXT.getDocument()
     text = doc.getText()
     for i in range(5000):
         text.getEnd().setString(str(i))

 def append_b():
     doc = XSCRIPTCONTEXT.getDocument()
     text = doc.getText()
     cursor = text.createTextCursorByRange(text.getEnd())
     for i in range(5000):
         cursor.getEnd().setString(str(i))

 def append_e():
     doc = XSCRIPTCONTEXT.getDocument()
     cursor = doc.getCurrentController().getViewCursor()
     cursor.gotoEnd()
     for i in range(5000):
         cursor.setString(str(i))
         cursor.collapseToEnd(False)

大体。2: str(i) -> u'\n%s' % i
|type|1 (sec)|2 (sec)|
|a|5.00|10.7|
|b|4.95|10.7|
|e|6.15|10.8|
*** 改行と改段落 [#l6ff4a6f]
Python で print "hoge" などとすると、\n がもれなく付いてくる。, でキャンセルすると付いてこないが、Writer に書き込む時にはそれぞれが行になり、一度の実行で得られるのはひとつの段落になる (\r をわざと入れたりしない場合)。各行または各段落で 64k 文字数を超えないようにする必要がある。

\n: 改行、\r: 改段落。普通は inputTextContent メソッドでコントロールコードを挿入。ビューカーソルからなどの時には面倒なので次のようにしたりする。もちろん、選択中の場合には置換される。
 oViewCursor = oController.getViewCursor()
 oViewCursor.setString("\n")
*** オートコレクト [#p6024669]
オートコレクトでダブルクォート (") を置換にしていると print "hoge" の最初のダブルクォートが置換されて SyntaxError になる。

シングルクォートも多分同じ。

オートコレクトのオプションはさらに曲者…。
マクロから勝手にオフにするわけには・・・?オートコレクトの設定はモジュール共通だからなぁ。

オートコレクトで有効になっている項目にしたがって置換し直すとか。[[Extensions/Configuration]]

- /org.openoffice.Office.Writer/AutoFunction/Format/Option
- /org.openoffice.Office.Common/AutoCorrect

- クォーテーションマークは置換する必要あり。
- 大小文字置換は無視
- 1st、1/2 はそのままで可
*** フィールド [#r02944e9]
Writer で使用できるフィールドがコマンドの含まれていても特に問題ない。getString などで文字列だけを取得しようとするとフィールドに表示されている文字列が取得される。

問題なのは、文字数をカーソルなどで数えるとき。フィールドは一文字だったはず…。今回は関係なし。

 print "FIELD"

*** キー操作制限 [#r15f18f3]
キー操作によるプロンプトの削除やプロンプト行の破壊を防ぐ。

Writer ではコントローラに com.sun.star.awt.XKeyHandler を登録することでキー操作を取得、無効化も行える。キー操作ではキー操作による機能 KeyFunc で com.sun.star.awt.KeyFunction に定義されている削除、ペースト、カットなどの機能的操作も検出できるため、それらも防げるはず。

現在のカーソル位置も知る必要がある、上記。

また、選択範囲を調べる必要がある。プロンプトのある最終行が選択範囲にある場合には操作を無効化するひつようあり?
*** メニュー操作制限 [#f7d0e46c]
メニューからの操作を制限する。変な位置に挿入などを行うとプロンプトがおかしくなる。そのため、特定のコマンド URL を無効化してユーザーによる操作を制限する。

com.sun.star.frame.XDispatchProviderInterceptor をコントローラに登録して特定のコマンドの実行を防ぐ。com.sun.star.frame.XDispatchProviderInterception。

XDispatchProviderInterceptor では各ドキュメントフレームごとでコマンドの実行を制限できる。コンフィグレーションでの場合には全ての同一モジュールで制限されてしまう。

また、この場合特定の条件下のみで無効化も可能。だが、非常に面倒なインターフェース。

*** コンテキストメニュー制限 [#cc6b5ef7]
右クリックでの操作の制限。com.sun.star.ui.XContextMenuInterceptor をコントローラに登録してコンテキストメニューから変な操作が行われるのを防ぐ。登録に利用するのは com.sun.star.ui.XContextMenuInterception インターフェースのメソッド。


*** スタイリスト [#g67c2ebc]
スタイルで番号付きなどに変更されると変になる?

*** マクロなどでの編集 [#t9a0bee3]
防げない。

*** UI [#df46aced]
いっそメニューバー、ツールバーなど全て非表示にする?
*** 日本語 [#e9270368]
 print u'日本語'
*** 回答 [#j36f4212]

#comment


*** 感想,コメント,メモ [#va373e3b]

#comment

Reload   New Lower page making Edit Freeze Diff Upload Copy Rename   Front page List of pages Search Recent changes Backup   Help   RSS of recent changes