2009年04月12日

PowerPointを外部DSLとして利用する

InfoQ主催のQConに行ってきました。書きたいことはたくさんあるけど、まずはMartin FowlerのDSLのお話を聞いて思ったことです。DSLに関しては僕も一回「英語に近いからDSLっておかしくね?」という思いをLTで発表したことがあるぐらいなので、色々思うところはあるわけです。まぁ、あんまり注目されたLTではなかったのですし、将来DSLが流行ったときに「既にこういうことを考えているヤツがいた!」と僕の名前が発掘されるのが僕の希望です。

Fowlerは、XMLよりもRubyの方が見やすいとか、そういうことを説明されていましたが、ステートチャートは上から下にシーケンシャルに流れるのではなくて、平面空間上にネットワーク構造を構成しています。フローチャートもUMLのアクティビティ図も、UMLのステートチャートも全部そうですけど。それならばいっそのこと、2Dで表現できるツールを使った方がいいですよね?Rubyで書かれたネットリストよりもね。ということで、このときにすでに考えていた「PowerPointのオートシェープを使ってネットワーク構造を表現するDSLってありじゃないの?」というのを実装してみました。Python+win32comです。矢印の向き情報を参照してノード間の接続情報を取得して出しています。また、吹き出しはコメント扱いで無視する実装になっています。

20090412 133312

このパワーポイントを処理した結果は以下のようになります。

id:2056 text:End
id:2052 text:Start
id:2053 text:State1
id:2054 text:State2
2053 -> 2056
2052 -> 2053
2053 -> 2054
2054 -> 2053
2054 -> 2056

発展の余地はたくさんあって、形状に意味を持たせたり、矢印の色や太さに意味を持たせる、というのがまず考えられますよね。トランジションというか、矢印に意味というかテキストを載っけるのも検討すると幅が広がります(おそらく座標値でヒットテストをする必要あり)。もちろん、図形に載っけるテキストの文法を定義するのもありですよね。調査したところ、OpenOfficeでもAPIが色々あるので大丈夫そうですが、業務でプログラマ以外の人にこのファイルを扱ってもらう(読む by Fowler)というDSLのメリットを生かしてもらうには今のところPower Pointかな、と思います。あ、残念ながら、Google DocsのPresentationはAPIで絵の情報が取得できないので使用できません。KeyNoteは手元に環境がないのでパス。

以下、ソースコードです。

import win32com.client
import pythoncom

class ExternalPowerPointDsl(object):
    def __init__(self, file_name):
        pythoncom.CoInitializeEx(pythoncom.COINIT_APARTMENTTHREADED)
        ppt = win32com.client.DispatchEx('Powerpoint.Application')
        ppt_obj = ppt.Presentations.open(file_name, False, False, False)
        self.connectors = []
        self.entities = {}
        for slide in self._slides(ppt_obj):
            for shape in self._shapes(slide):
                if self._is_callout(shape):
                    continue
                elif self._is_connector(shape):
                    self._check_connector(shape)
                else:
                    self.entities[shape.Id] = self._label(shape)

    def _label(self, shape):
        return shape.TextFrame.TextRange.Text

    def _is_callout(self, shape):
        callout_types = range(105, 124)
        return shape.AutoShapeType in callout_types

    def _is_connector(self, shape):
        connector_type = -2
        return shape.AutoShapeType == connector_type

    def _shapes(self, slide):
        for i in range(slide.Shapes.Count):
            yield slide.Shapes(i+1)

    def _slides(self, ppt):
        for i in range(ppt.Slides.Count):
            yield ppt.Slides(i+1)

    def _check_connector(self, shape):
        format = shape.ConnectorFormat
        style = shape.Line
        if not format.BeginConnected or not format.EndConnected:
            return
        shapes = [format.BeginConnectedShape.Id, format.EndConnectedShape.Id]
        if style.BeginArrowheadStyle != 1 and style.EndArrowheadStyle != 1:
            self.connectors.append((shapes[0], shapes[1]))
            self.connectors.append((shapes[1], shapes[0]))
        elif style.BeginArrowheadStyle != 1:
            self.connectors.append((shapes[1], shapes[0]))
        elif style.EndArrowheadStyle != 1:
            self.connectors.append((shapes[0], shapes[1]))


if __name__ == "__main__":
    dsl = ExternalPowerPointDsl("test_data.ppt")
    for key, value in dsl.entities.items():
        print "id:%s text:%s" % (key, value)
    for begin, end in dsl.connectors:
        print "%s -> %s" % (begin ,end)

最後に僕が以前発表したスライドも貼り付けておきますね。

posted by @shibukawa at 13:51 | Comment(185) | TrackBack(0) | 日記 はてなブックマーク - PowerPointを外部DSLとして利用する
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/28422677

この記事へのトラックバック
検索ボックス

Twitter

www.flickr.com
This is a Flickr badge showing public photos and videos from shibukawa.yoshiki. Make your own badge here.
<< 2019年02月 >>
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28    
最近の記事
カテゴリ
過去ログ
Powered by さくらのブログ