Read in gjotsfile

昨日のコードを .gjotsfile を読み込むように改造してみた。
Gjots2 が保存するファイルは

“\NewEntry” でエントリーの追加
“\NewFolder” で入れ子の作成
“\EndFolder” で入れ子を一階層戻る
ツリータイトルはエントリーの一行め

だけという恐ろしく単純明解な構造である。
ルールもタイトルの一文字めには \ を使わないということだけ。
これなら初心者でも自力で読み書きするコードが書けそうです。

Python でファイルを一行毎に処理する方法は

path = os.path.expanduser("~/.gjotsfile")
f = open(path)
x = f.read()
f.close()
lines = x.split("\n")
for line in lines:
    hoge

という一番単純な方法と

path = os.path.expanduser("~/.gjotsfile")
f = open(path)
try:
    for line in f:
        hoge
finally:
    f.close()

の方法がある、下の方法のほうが圧倒的に早い。
一度全部読み込んで展開するのかストリームで読むかの差である。
但し行末に改行コードが含まれている、それと try 文にしないと何かあった場合に close できないというオチがあるので注意して使いましょう。

とりあえず上記フラグがあった場合に分岐して if 文を作成。
現在は空状態を示す方法として “\NonTitle” みたいなフラグを追加。
“\NewEntry” で GtkTreeStore にアペンドして読み込んだ部分を空にする。
イテレータを “\NewFolder” で入れ替え “\EndFolder” で書き戻し。

そんな感じにして上手くいったコード。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import os
from gi.repository import Gtk, Gio, GtkSource

class TreeWin(Gtk.Window):
    """
        GtkTreeView Sample
    """
    def __init__(self):
        Gtk.Window.__init__(self)
        # CellRenderer
        cell = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("Tree Title", cell)
        column.add_attribute(cell, "text", 0)
        # TreeView and TreeStore
        store = Gtk.TreeStore.new([str, str])
        tree = Gtk.TreeView.new_with_model(store)
        tree.append_column(column)
        # Hide Header
        tree.props.headers_visible = False
        # Signal
        selection = tree.get_selection()
        selection.connect("changed", self.selection_changeed)
        #
        # Data
        self.path = os.path.expanduser("~/.gjotsfile")
        t = ".gjotsfile"
        s = ""
        it = None
        itold = None
        f = open(self.path)
        try:
            for line in f:
                if line == "\\NewEntry\n":
                    if t == ".gjotsfile":
                        it = store.append(it, [t, s])
                    elif t != "\\NoneTitle":
                        store.append(it, [t, s])
                    s = ""
                    t = "\\NoneTitle"
                elif line == "\\NewFolder\n":
                    itold = it.copy()
                    it = store.append(it, [t, s])
                    s = ""
                    t = "\\NoneTitle"
                elif line == "\\EndFolder\n":
                    store.append(it, [t, s])
                    it = itold
                    s = ""
                    t = "\\NoneTitle"
                else:
                    if t == "\\NoneTitle":
                        t = line[:-1]
                    s += "{0}".format(line)
        finally:
            f.close()
        #
        # GtkSourceView
        self.view = GtkSource.View()
        self.view.set_show_line_numbers(True)
        # Paned and ScrolledWindow
        swa = Gtk.ScrolledWindow()
        swa.add(tree)
        swb = Gtk.ScrolledWindow()
        swb.add(self.view)
        hp = Gtk.HPaned()
        hp.add1(swa)
        hp.add2(swb)
        # self
        self.set_title("TreeView Test")
        self.add(hp)
        self.show_all()

    def selection_changeed(self, widget, data=None):
        """
            Params @ widget: GtkTreeSelection
        """
        model, it = widget.get_selected()
        if it:
            buf = self.view.get_buffer()
            buf.set_text(model.get_value(it, 1))

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(
                self,
                application_id="apps.test.treeview",
                flags=Gio.ApplicationFlags.FLAGS_NONE)
        self.connect("activate", self.on_activate)
        
    def on_activate(self, data=None):
        w = TreeWin()
        w.set_application(self)
    
if __name__ == "__main__":
    app = App()
    app.run(None)

もう少しスマートにできそうなんだけど…
そういえば Ubuntu でも動くかな、仮想マシンの 11.10 で実験。

よし動く、後は書き込みとツリーの追加削除移動なんかだ。
とりあえず今日はココまで、ノンビリすぎだと思うけど。