g_file_trash ってのがあった

何を今頃気がついた。
Eye of GNOME って Delete キーで「ゴミ箱へ移動」ができるんだね。

sakura241

これは…早速ソースコードを拝ませてもらわなきゃ、ダウンロード。
このポイントだけ知りたいんだから GPL 関係は大丈夫だろう。
というか Y901x はオープンソースだし。

Eye of GNOME

とにかく g_file_trash なんていう関数を使えばいいと解った。
しかしスゲェ、ゴミ箱に入れられるかどうかチェックして g_file_delete と振り分けている。
標準アプリはやはりこういう部分をキチンと考えて作っているんだなと関心する。

コレってやはり Gnome てか Nautilus に依存するのかな?
でもそんなの関係ねぇ(古い…最近マジでテレビ見ないし
つーか Y901x は D&D 処理自体から Nautilus に依存だ、わっはっはシラネ!

それよりこれって Python バインディングではどう書くのだ?
海外を探してもなーんにも見つからないんだが。

思いつくかぎりのワードで探して gio なんてモジュールがあると解った。
後は dir(gio) で gio.File を見つける、どうやらコレっぽい。

gio

あぁやっと見つかった。
何かもの凄い無駄なことをしているような気がしなくもないが私はいつもこんなだ。
ということで実験で書いてみたコード。

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

import gtk
import gio
import urllib
import os.path

class TrashWin(gtk.Window):
    """
        ドロップされたファイルをゴミ箱に捨てる
    """
    def __init__(self):
        gtk.Window.__init__(self)
        # D&D の準備
        dnd_list = [("text/uri-list", 0, 0)]
        self.drag_dest_set( gtk.DEST_DEFAULT_MOTION |
                            gtk.DEST_DEFAULT_HIGHLIGHT |
                            gtk.DEST_DEFAULT_DROP,
                            dnd_list, gtk.gdk.ACTION_MOVE )
        self.connect("drag_data_received", self.on_drop)
        # いつもの処理
        self.connect("delete-event", gtk.main_quit)
        self.resize(320, 150)
        self.show_all()

    def on_drop(self, widget, context, x, y, selection_data, info, time):
        drops = selection_data.data.split("\n")
        for drop in drops:
            name = urllib.unquote(drop)[7:-1]
            if os.path.isfile(name):
                # ゴミ箱へ Go!
                obj = gio.File(name)
                obj.trash()

if __name__ == "__main__":
    w = TrashWin()
    gtk.main()

こんなにアッサリ作れてしまった…例外や失敗の処理無しならたったの二行。
trash メソッドの引数は不要みたい、成功すると True が帰ってくる。

つーことで早速 Y901x に入れて更新!
ボタンも真似させてもらった、set_default_response で OK ボタンが選択できるのね。

Eye of GNOME プラグインは面倒

Eye of GNOME でリネームプラグインを作る。
って書いたけど本当に作れるんかいな?

Gedit/Plugins – GNOME Live!
EyeOfGnome/Plugins – GNOME Live!

gEdit とは扱いが随分違うなぁ… HowTo も何もない、勘で作れと?

Eye of GNOME Reference Manual

これ Python にバインディングされているのだろうか?

EyeOfGnome – SunagaLab

以前貼った所をよく見ると window.get_image() メソッドが使えているからできるのだろう。
ただ、9.04 付属の 2.26.1 はこの機能が標準装備、進化って悲しいなぁ。
他の Python への変換は勘でなんとかなると思う、今更 C で作りたく無いよ。

とにかく実際に書いてみるのが一番早い、とりあえず Plugins ページ一番下にあったコードは動いた。
次は gEdit プラグインを作ったのと同じように MessageBox を出すのを作って試す。

っっって

何これ、Eye of GNOME ってプラグインから例外を出すと終了してくれない!
端末から eog で起動して終了しなかったら Ctrl+C で強制終了さなきゃやってられん。
GUI アプリでコレをやるとは思いもしなかった。

eogdebug

2 と出ているのは debug 用でどこまで動いたかを print しているだけだから気にしない。
最初それが解らなくて再起動やログアウトをやるという無駄なことをしてしまった。

こんなことをやっている間に気がついた。
Ubuntu 9.04 って Ctrl+Alt+BackSpace で X の再起動ができなくなっている!

Ubuntu 9.04 Beta ctrl+alt+backspaceを有効にする。

$ sudo apt-get install dontzap
$ sudo dontzap -d

しなきゃいけないのね、何故わざわざ無効にする必要があったのか理解できない。
おいおい、そんなことをしている間に今日が終わっちゃう。
はたしてこの計画は進むのだろうか?

覚書ページをなんとかしたい

Y901x 0.1.3 公開しました。

結局トグルボタンとラジオボタンの同期は自前で行った。
どうやったかはソースコードを見てください、我ながらナイスなシグナルの逃し方だ。
本当はラジオボタンも同じメニュー選択で解除にしたいけど一般的な動作じゃないし。

boko

ツールバーにしてみたら上のようにボッコリするのと右寄せができないので気に入らなかった。
ソースコードにコメントアウトして残しています、XML のトコも外してね。

まだやることはあるけど、とにかくこれでしばらくは落ち着けるかもしれない。

プレイヤーが作りたいというより PyGtk で何か作ったものを公開したい。
Python で GUI アプリが簡単に作れ環境もデフォルトで揃っているコトを知らない人が多すぎる。
ウチへの検索ワードにヤケに mono が多い理由はソレだと思うので知ってもらいたい。
という感じでやっているのであまり複雑にしたくないし。

つか、そろそろ覚書ページをなんとかしたいんだが今やっているコトを解説は難しいぞ。
GtkUIManager はどう考えたってプログラミング初心者には敷居が高いんだが…
恐ろしく楽ができるウイジェットだけど事前知識がかなり必要になる。

かと思えば Glade もとても初心者には勧められないようなシロモノになっちまった。
個別ウイジェットの解説から始めてゼロから作り直ししたほうが良さげな感じ。

それはそうと、いいかげんに違うアプリを作りたいものだ。
Y901x のリネーム機能を Eye of GNOME のプラグインにしようかと企んでいる。
需要はシラネ、本日はお知らせのみ。

ラジオメニューとトグルボタンの同期

Y901x 0.1.2 公開しました。
こんな Windows 用のノリでやっていても良いものかと思い始めた今日この頃。

っっって…指定倍率変更の計算が間違えているのに今気がついた!
せっかくまとめて listbox クラスにしたのにセパレータサイズを足していた。
あーあ明日もごまかすために更新だ、更新が特定期間に集中する原因はコレです。

ところで。

ラジオメニューとトグルボタンは UIManager から同期させられないっぽい。
と以前書いたけどツールバーならあっさりできるようで。

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

import gtk

ui_str = """<ui>
    <menubar name="MenuBar">
        <menu action="Rep">
            <menuitem action="non"/>
            <menuitem action="one"/>
            <menuitem action="all"/>
            <menuitem action="rdm"/>
        </menu>
    </menubar>
    <toolbar name="Toolbar">
        <toolitem action="one"/>
        <toolitem action="all"/>
        <toolitem action="rdm"/>
    </toolbar>
</ui>"""

class BtnBox(gtk.Window):
    def __init__(self):
        gtk.Window.__init__(self)
        #
        # GtkUIManager 作成
        self.uimanager = gtk.UIManager()
        #
        # GtkActionGroup 作成
        self.actiongroup = gtk.ActionGroup("sasakimamenu")
        #
        # GtkAccelGroup を得てウインドウに突っ込む
        # 何もグループを作らなくてもコレやらないと後のアクセラレータ指定が効かない
        accelgroup = self.uimanager.get_accel_group()
        self.add_accel_group(accelgroup)
        #
        # GtkActionEntry を作成して突っ込む
        # 得にグループにしないものはココでまとめて作成
        # name, stock_id, label, accelerator, tooltip, callback
        self.ac0 = [("Rep", None, "リピート(_R)")]
        self.actiongroup.add_actions(self.ac0)
        #
        # GtkRadioActionEntry の List を作成
        # name, stock_id, label, accelerator, tooltip, value
        self.ac1 = [("non", None, "無し", "0", "無し", 0),
                    ("one", None, "シングル", "1", "シングル", 1),
                    ("all", None, "オール", "2", "オール", 2),
                    ("rdm", None, "ランダム", "3", "ランダム", 3) ]
        # GtkRadioAction を突っ込む
        # entries, value=0, on_change=None, user_data=None
        self.actiongroup.add_radio_actions(self.ac1, 0, self.on_loop_change)
        #
        # GtkUIManager の更新
        self.uimanager.insert_action_group(self.actiongroup, 0)
        self.uimanager.add_ui_from_string(ui_str)
        self.uimanager.ensure_update()
        # menubar を抜き出す
        menubar = self.uimanager.get_widget("/MenuBar")
        # toolbar を抜き出す
        toolbar = self.uimanager.get_widget('/Toolbar')
        # pack
        vbox = gtk.VBox()
        vbox.pack_start(menubar, False)
        vbox.pack_start(toolbar, False,False)
        self.add(vbox)
        self.connect("delete-event", gtk.main_quit)
        self.resize(320, 150)
        self.show_all()
        self.val = 0

    def on_loop_change(self, action, current):
        # コレは無理だった
        num = action.get_current_value()
        if num == self.val:
            action.set_current_value(0)
        else:
            self.val = num

if __name__ == "__main__":
    w = BtnBox()
    gtk.main()

repeat

得に何をするわけでもなく action を共通にすれば同期してくれるわ。
だけどアクティブなボタンを再度押すとオフにするといった処理は無理か。
ボタンオブジェクトを抜いて clicked シグナルを処理すればよさげだけど。

コレ上手く使えないかな?いまここ。

Linux のゴミ箱

Y901x 0.1.1 バグ修正を公開しました。
ココにリネーム方法を書いたのに少し書き換えた私がアホだった…

ところで

何を今頃気がついたが os.remove でファイル削除するとゴミ箱に入らずに消滅する。
そういえば UNIX には元々ゴミ箱なんて無かった、つーか rm で削除すると消滅ですがな。

何か Nautilus に慣れてしまってゴミ箱に入るものだとうっかりしていた。
Windows ShellAPI の SHFileOperation みたいな方法は無いのだろうか?

ちなみに Ubuntu のゴミ箱に捨てたファイルは以下にある。

~/.local/share/Trash/files

しかし調べてみるとディストリビューションによって下記もあるようで。

~/.Trash
~/.Trash-0

ゴミ箱 – Wikipedia

規格の範囲でファイルマネージャ毎に決めているっぽい。
FreeDesktop.org での規格なら xdg-trash とか、無いか…

Ubuntu — Details of package xdg-utils in jaunty

ついでに、メニューのインストールには xdg-desktop-menu を本当は使わなきゃいけないのね。
make や dpkg は勝手にそれをやってくれるということでいいのかな。
Y901x のインストールスクリプトは言うまでもなく直で突っ込んでいる、知らなかったよ。
Ubuntu 限定に近いから別にイイんだが真似しないほうがいいよあの方法は。

Ubuntu日本語フォーラム / HOWTO: CLIからゴミ箱を使う

こういうのがあるのか。
端末からゴミ箱利用はかなり微妙だけど保険にはなるかも。
間違えて Blog の画像を全部消したコトがある私はそう思う。
でもレンタルサーバーで FTP ソフトを使ったら全く意味が無いとも。

コレをインストールしてもらえば…だからソレはやりたくない。
よし決めた、面倒だから当面は消滅のままでいいや!これが私の(略