LibreOffice5(122)Javaの例: ClipboardをPythonにする

2018-01-20

旧ブログ

t f B! P L
Office Development examplesのClipboardをPythonにします。Clipboardはクリップボードを操作する例です。

前の関連記事:LibreOffice5(121)SystemClipboardのサービスとインターフェイスの一覧


Javaの例: ClipboardをPythonにする

import unohelper  # オートメーションには必須(必須なのはuno)。
import sys
import time
from com.sun.star.view import DocumentZoomType
from com.sun.star.datatransfer.clipboard import XClipboardListener
from com.sun.star.datatransfer.clipboard import XClipboardOwner
from com.sun.star.datatransfer import XTransferable
from com.sun.star.datatransfer import DataFlavor  # Struct
from com.sun.star.datatransfer import UnsupportedFlavorException
def macro():
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。
 doc = XSCRIPTCONTEXT.getDocument()  # 現在開いているドキュメントを取得。
 doc.getText().setString("""In the first step, paste the current content of the clipboard in the document!
The text \"Hello world!\" shall be insert at the current cursor position below.

In the second step, please select some words and put it into the clipboard! ...
 
Current clipboard content = """);
 controller = doc.getCurrentController()
 controller.getViewSettings().setPropertyValue("ZoomType", DocumentZoomType.OPTIMAL)
 systemclipboard = smgr.createInstanceWithContext("com.sun.star.datatransfer.clipboard.SystemClipboard", ctx)
 clipboardlistener = ClipboardListener()
 systemclipboard.addClipboardListener(clipboardlistener)
 readClipBoard(systemclipboard)
 print("Becoming a clipboard owner...\n") 
 clipboardowner = ClipboardOwner()
 systemclipboard.setContents(TextTransferable("Hello World!"), clipboardowner)
 first = 0
 while clipboardowner.isowner:
  if first!=2:
   if first==1:
    print("""Change clipboard ownership by putting something into the clipboard!

Still clipboard owner...""")
   else:
    print("Still clipboard owner...")
   first += 1
  else:
   print(".", end="")
  time.sleep(1)
 readClipBoard(systemclipboard)
 systemclipboard.removeClipboardListener(clipboardlistener)
 if hasattr(doc, "close"):
  doc.close(True)
 else:
  doc.dispose() 
 sys.exit(0)
def readClipBoard(systemclipboard):
 transferable = systemclipboard.getContents()
 dataflavors = transferable.getTransferDataFlavors()
 print("""Reading the clipboard...
Available clipboard formats:""")
 flavor = None
 for dataflavor in dataflavors:
  print("""MimeType: {}
HumanPresentableName: {}""".format(dataflavor.MimeType, dataflavor.HumanPresentableName))
  if dataflavor.MimeType=="text/plain;charset=utf-16":
   flavor = dataflavor
 if flavor is None:
  print("""
Requested format is not available on the clipboard!""")
 else:
  print("""
Unicode text on the clipboard ...
Your selected text \"{}\" is now in the clipboard.
""".format(transferable.getTransferData(flavor)))
class TextTransferable(unohelper.Base, XTransferable):
 def __init__(self, txt):
  self.txt = txt
  self.unicode_content_type = "text/plain;charset=utf-16"
 def getTransferData(self, flavor):
  if flavor.MimeType.lower()!=self.unicode_content_type:
   raise UnsupportedFlavorException()
  return self.txt
 def getTransferDataFlavors(self):
  return DataFlavor(MimeType=self.unicode_content_type, HumanPresentableName="Unicode Text"),  # DataTypeの設定方法は不明。
 def isDataFlavorSupported(self, flavor):
  return flavor.MimeType.lower()==self.unicode_content_type
class ClipboardOwner(unohelper.Base, XClipboardOwner):
 def __init__(self):
  self.isowner = True
 def lostOwnership(self, clipboard, transferable):
  print("""
Lost clipboard ownership...
""")
  self.isowner = False
class ClipboardListener(unohelper.Base, XClipboardListener):
 def changedContents(self, clipboardEvent):
  print("\nClipboard content has changed!\n")
 def disposing(self, eventobject):
  pass
g_exportedScripts = macro, #マクロセレクターに限定表示させる関数をタプルで指定。
if __name__ == "__main__":  # オートメーションで実行するとき
 import officehelper
 from functools import wraps
 import sys
 from com.sun.star.beans import PropertyValue
 from com.sun.star.script.provider import XScriptContext  
 def connectOffice(func):  # funcの前後でOffice接続の処理
  @wraps(func)
  def wrapper():  # LibreOfficeをバックグラウンドで起動してコンポーネントテクストとサービスマネジャーを取得する。
   try:
    ctx = officehelper.bootstrap()  # コンポーネントコンテクストの取得。
   except:
    print("Could not establish a connection with a running office.", file=sys.stderr)
    sys.exit()
   print("Connected to a running office ...")
   smgr = ctx.getServiceManager()  # サービスマネジャーの取得。
   print("Using {} {}".format(*_getLOVersion(ctx, smgr)))  # LibreOfficeのバージョンを出力。
   return func(ctx, smgr)  # 引数の関数の実行。
  def _getLOVersion(ctx, smgr):  # LibreOfficeの名前とバージョンを返す。
   cp = smgr.createInstanceWithContext('com.sun.star.configuration.ConfigurationProvider', ctx)
   node = PropertyValue(Name = 'nodepath', Value = 'org.openoffice.Setup/Product' )  # share/registry/main.xcd内のノードパス。
   ca = cp.createInstanceWithArguments('com.sun.star.configuration.ConfigurationAccess', (node,))
   return ca.getPropertyValues(('ooName', 'ooSetupVersion'))  # LibreOfficeの名前とバージョンをタプルで返す。
  return wrapper
 @connectOffice  # mainの引数にctxとsmgrを渡すデコレータ。
 def main(ctx, smgr):  # XSCRIPTCONTEXTを生成。
  class ScriptContext(unohelper.Base, XScriptContext):
   def __init__(self, ctx):
    self.ctx = ctx
   def getComponentContext(self):
    return self.ctx
   def getDesktop(self):
    return ctx.getByName('/singletons/com.sun.star.frame.theDesktop')  # com.sun.star.frame.Desktopはdeprecatedになっている。
   def getDocument(self):
    return self.getDesktop().getCurrentComponent()
  return ScriptContext(ctx)  
 XSCRIPTCONTEXT = main()  # XSCRIPTCONTEXTを取得。
 doc = XSCRIPTCONTEXT.getDocument()  # 現在開いているドキュメントを取得。
#  doctype = "scalc", "com.sun.star.sheet.SpreadsheetDocument"  # Calcドキュメントを開くとき。
 doctype = "swriter", "com.sun.star.text.TextDocument"  # Writerドキュメントを開くとき。
 if (doc is None) or (not doc.supportsService(doctype[1])):  # ドキュメントが取得できなかった時またはCalcドキュメントではない時
  XSCRIPTCONTEXT.getDesktop().loadComponentFromURL("private:factory/{}".format(doctype[0]), "_blank", 0, ())  # ドキュメントを開く。ここでdocに代入してもドキュメントが開く前にmacro()が呼ばれてしまう。
 flg = True
 while flg:
  doc = XSCRIPTCONTEXT.getDocument()  # 現在開いているドキュメントを取得。
  if doc is not None:
   flg = (not doc.supportsService(doctype[1]))  # ドキュメントタイプが確認できたらwhileを抜ける。
 macro()
結果をprint()で出力しているのでオートメーションで実行しないと結果が見れません。
Using LibreOffice 5.4
Reading the clipboard...
Available clipboard formats:
MimeType: text/plain;charset=utf-16
HumanPresentableName: 
MimeType: TIMESTAMP
HumanPresentableName: 
MimeType: TARGETS
HumanPresentableName: 
MimeType: MULTIPLE
HumanPresentableName: 
MimeType: SAVE_TARGETS
HumanPresentableName: 
MimeType: GTK_TEXT_BUFFER_CONTENTS
HumanPresentableName: 
MimeType: application/x-gtk-text-buffer-rich-text
HumanPresentableName: 
MimeType: text/plain;charset=utf-8
HumanPresentableName: 
MimeType: TEXT
HumanPresentableName: 
MimeType: text/plain;charset=iso8859-1
HumanPresentableName: 
MimeType: text/plain;charset=utf-8
HumanPresentableName: 
MimeType: text/plain
HumanPresentableName: 

Unicode text on the clipboard ...
Your selected text "クリップボードの内容" is now in the clipboard.

Becoming a clipboard owner...


Clipboard content has changed!

Still clipboard owner...
Change clipboard ownership by putting something into the clipboard!

Still clipboard owner...
実行するとWriterドキュメントを開き、コンソールにはそのときのクリップボードに入っている内容についての情報を出力します。

今回は「クリップボードの内容」というテキストがクリップボードに入っている状態で実行しました。

SystemClipboardサービスのインスタンスのgetContents()の戻り値のXTransferableインターフェイスをもったオブジェクトのgetTransferDataFlavors()で取得した各DataFlavorStructについてそれぞめMimeTypeとHumanPresentableNameを出力しています。

その後SystemClipboardのsetContents()でMimeTypeにtext/plain;charset=utf-16が入ったDataFlavorをもつXTransferableオブジェクトを渡しています。

このオブジェクトはgetTransferData()が呼ばれるとHello World!という文字列を返しますので、この状態でペーストすると「Hello World!」という文字列がペーストされます。

SystemClipboardにはXClipboardListenerがつけてあるので、クリップボードの内容が変更されるとchangedContents()メソッドが発火します。

SystemClipboardにはXClipboardOwnerをsetContents()で渡してあるので、LibreOffice以外でクリップボードを操作するとlostOwnership()メソッドが発火します。
.................................
Lost clipboard ownership...

Reading the clipboard...
Available clipboard formats:
MimeType: text/plain;charset=utf-16
HumanPresentableName: 
MimeType: TIMESTAMP
HumanPresentableName: 
MimeType: TARGETS
HumanPresentableName: 
MimeType: MULTIPLE
HumanPresentableName: 
MimeType: SAVE_TARGETS
HumanPresentableName: 
MimeType: text/plain;charset=utf-8
HumanPresentableName: 
MimeType: TEXT
HumanPresentableName: 
MimeType: text/plain;charset=iso8859-1
HumanPresentableName: 
MimeType: text/plain;charset=utf-8
HumanPresentableName: 
MimeType: text/plain
HumanPresentableName: 

Unicode text on the clipboard ...
Your selected text "Hello World!" is now in the clipboard.
lostOwnership()メソッドが発火するとその後クリップボードの内容を再度出力してWirterドキュメントを閉じます。

LibreOffice以外でクリップボードを操作するまで1秒ごとに.を出力するはずですが、Eclipse4.6.2のコンソールでは\rは\nと同じ扱いで、end=""とするとTerminalでも\nがくるまで出力されませんでした。

参考にしたサイト


LibreOffice 6.0 SDK - Developer's Guide Examples
Office Development examplesのClipboardをPythonにしました。

python - Text Progress Bar in the Console - Stack Overflow
\rを使ったPythonコンソールでのプログレスバーの例。

OOoBasic/Generic/Clipboard - ...?
クリップボードの解説。

次の関連記事:LibreOffice5(123)コントロールダイアログのサービスとインターフェイスの一覧

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ