ThreadPaneのツリーにチェックボックス型のカラムを挿入する方法(ごり押し) 〜Thunderbird Extention④〜

受信トレイや送信済みトレイ等の"ThreadPane"にチェックボックス型のカラムを追加する方法を調べていたが、
全然情報が集まらず、結局ごり押しの方法でそれっぽいことができたので載せておく。

ちなみに、
# チェックボックス型のカラムは、treecol要素でtype属性にcheckboxを設定した上に、CSSで画像を指定しないと見えない。また、チェックボックス型のカラムを編集可能にするには、tree要素とtreecol要素の両方のeditable属性をtrueにしなくてはいけない。

ということは調べていたら分かったのだが、その通りにしてもチェックボックスが機能しなかった。

var CheckBoxColumnHandler = {

    getCellText: function(row, col) {},
    isEditable: function(row, col) {
        return true;
    },
    getRowProperties:	function(row, props){}
    getCellProperties:   function(row, col, props){},

    getImageSrc:         function(row, col) {
    var key = gDBView.getKeyAt(row);
    var hdr = gDBView.db.GetMsgHdrForKey(key);
    var CheckFlg = hdr.getStringProperty("X-Check");
    var retval;

    if(CheckFlg == "true")
    	retval = "chrome://global/skin/checkbox/cbox-check.gif";  //ここはチェック時の画像
    else
    	retval = "chrome://global/skin/checkbox/cbox-check-dis.gif";  //ここはチェックなしの画像
    	
    return retval;
    },
}

function ThreadPaneOnClick(event){
    if (event.button != 0)
	return;
 
    var t = event.originalTarget;

    if (t.localName == "treecol") {
       HandleColumnClick(t.id);
    }
    else if (t.localName == "treechildren") {
	var row = new Object;
	var col = new Object;
	var childElt = new Object;
        var tree = GetThreadTree();

        tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, childElt);
        if (row.value == -1)
            return;

        var key = gDBView.getKeyAt(row.value);
        var hdr = gDBView.db.GetMsgHdrForKey(key);
        //チェックボックス型のカラムIDを"CheckBoxCol"とする
        if(col.value.id == "CheckBoxCol")
	    {
	    	if(hdr.getStringProperty("X-Check") == "true")
	    	{
	    		hdr.setStringProperty("X-Check","false");
	    	}
	    	else
	    	{
	    		hdr.setStringProperty("X-Check","true");
	    	}
	    }

        gDBView.addColumnHandler("CheckBoxCol",CheckBoxColumnHandler);

	var boxobject = tree.boxObject;
  	boxobject.QueryInterface(Components.interfaces.nsITreeBoxObject);
	//ツリーを再描画
	boxobject.invalidate();
    }
    else
        return;
}
document.getElementById("threadTree").addEventListener("mousedown",threadPaneOnClick,true);

とりあえずこれでチェックボックスまがいのことはできるようになったので、よしとしようw
画像をチェックボックスっぽい画像にすれば問題はないだろう(たぶん)

ちょっとしたメモ 〜Thunderbird Extention③〜

メッセージ送信時の送信メッセージ保存先

//デフォルトの設定(アカウント名:account)
gMsgCompose.compFields.fcc = "mailbox://account/Sent";
//別のフォルダにもコピー(フォルダ「Temp」にも保存)
gMsgCompose.compFields.fcc2 = "mailbox://account/Temp";
//fccの数字を増やすことでコピー数を増やせる

(選択されている)メッセージを別のフォルダへコピー

//アカウント名:accountのTempフォルダへコピー
MsgCopyMessage("mailbox://account/Temp");

ローカルフォルダにTest1というフォルダがあれば作成、なければそのまま

if(GetMsgFolderFromUri("mailbox://nobody@Local%20Folders/Test1",true) == null)
    NewFolder("Test1", "mailbox://nobody@Local%20Folders");


全てのアカウントのルートフォルダURIとアカウント名

var accountMgr=
    Components.classes["@mozilla.org/messenger/account-manager;1"].
      getService(Components.interfaces.nsIMsgAccountManager);
var allAccounts=accountMgr.accounts; 
var accountsCount = allAccounts.Count();
for (var i = 0; i < accountsCount; i++){
    var account = allAccounts.QueryElementAt(i, Components.interfaces.nsIMsgAccount);
    account.incomingServer.rootFolder.URI;  //それぞれのルートフォルダURI
  account.incomingServer.prettyName;        //それぞれのアカウント名
}

デフォルトのアカウントのルートフォルダURI

var currentFolder = GetMsgFolderFromUri(msgComposeService.defaultIdentity.fccFolder); 
var accountFolderURI = currentFolder.rootFolder.URI; //デフォルトアカウントのルートフォルダURI

クリックしたthreadTree上の行や列等

document.getElementById("threadTree").addEventListener("click",threadPaneOnClick,true);
function threadPaneOnClick(event){
    if (event.button != 0)
	return;
 
    var t = event.originalTarget;

    if (t.localName == "treecol") {
       HandleColumnClick(t.id);
    }
    else if (t.localName == "treechildren") {
      var row = new Object;
      var col = new Object;
      var childElt = new Object;

      var tree = GetThreadTree();
     
// figure out what cell the click was in
      tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, childElt);
      if (row.value == -1)
       return;
      
      row.value;      //何行目か(index)
      col.value.id;   //何列目か(columnのid)
      childElt.value; //対象は何か(text?image?cell?twisty?)
       
	}
}

フォルダペインに新しいフォルダを追加する方法 〜Thunderbird Extention②〜

今回はフォルダペインに新しいフォルダを追加する方法について。
まぁフォルダを右クリックしてコンテキストメニューを出してやれば、そのなかに"新しいフォルダ..."というメニューがあるので、手動でやりたいときはそれでいいのだが、それをjsから実行するにはどうすればいいのか?というお話。

実際にフォルダを追加する関数は

    var name = "追加したいファイル名";
    NewFolder(name, preselectedURI);

です。
1つ目の引数の値がファイル名。
2つ目の引数は追加するフォルダのURI



以下のコードは選択されたフォルダに"Test"という名前のフォルダを追加します。

function addFolder(){
    var preselectedFolder = GetFirstSelectedMsgFolder();  //ここが追加したいフォルダ
    var dualUseFolders = true;
    var server = null;
    var destinationFolder = null;

    if (preselectedFolder)
        {
        try {
            server = preselectedFolder.server;
            if (server)
            {
                destinationFolder = getDestinationFolder(preselectedFolder, server);

                var imapServer =
                    server.QueryInterface(Components.interfaces.nsIImapIncomingServer);
                if (imapServer)
                    dualUseFolders = imapServer.dualUseFolders;
            }
        } catch (e) {
            dump ("Exception: dualUseFolders = true\n");
        }
    }
    var preselectedFolderResource = destinationFolder.QueryInterface(Components.interfaces.nsIRDFResource);
    if (preselectedFolderResource)
       preselectedURI = preselectedFolderResource.Value;

    NewFolder("Test", preselectedURI);  //Testという名前のフォルダを追加
}


ちなみに、あるフォルダの中で同一名のフォルダの存在は許されないので、二度上記のコードを実行すると別名にしてくださいと怒られますw

自作のヘッダの値をメールツリーの追加カラムに反映させる方法 〜Thunderbird Extention①〜

Thunderbirdのアドオン作成において、メールのヘッダにアドオン用のヘッダを追加したい場合があると思う。
そこで詰まるのは、カスタムヘッダを追加して、その値をツリーに反映させる方法である。

その方法(と思われるもの)はMDCで紹介されている。
https://developer.mozilla.org/en/Extensions/Thunderbird/customDBHeaders_Preference


しかし、この通りにコードを書いても自作のヘッダの値は読み取れなかった。

getCellText: function(row, col) {
   //get the messages header so that we can extract the 'X-Superfluous' field
    var key = gDBView.getKeyAt(row);
    var hdr = gDBView.db.GetMsgHdrForKey(key);
    var retval = hdr.getStringProperty("x-superfluous");
    dump("x-superfluous: " + retval + "\n");
    return retval;
   },

hdr.getStringProperty("x-superfluous");

でプロパティを取得できていないのだ。

なぜ取得できないのかを、延々と考えていたが結局わからず、他にも同じところで詰まっている人がいないか探してみた。


http://groups.google.co.jp/group/mozilla.dev.extensions/browse_thread/thread/3ed8c0e6c6cc5431
http://forums.mozillazine.org/viewtopic.php?t=286938
http://forums.mozillazine.org/viewtopic.php?f=19&t=472969&start=0
などが見つかり、ようやく解決した。


どうやら、nsIMsgDBHdrインタフェースのgetStringProperty("ヘッダ名")メソッドでは、元々用意されているであろうヘッダ(reply-toとかReferencesとか)の値しか取得できないらしいのだ。
どうやらnsIMimeHeadersインタフェースのメソッドを使う必要があるみたいだ。
でもこのnsIMimeHeadersの詳細が良く分からず、コピペになってしまったw


以下、messenger.xulにオーバレイしているxulファイルがインクルードしているjsファイルの中身
ヘッダ名:"X-xxx"
追加カラム名:"xxxCol"

var columnHandler = {
   getCellText: function(row, col) {
   //get the messages header so that we can extract the 'X-xxx' field
    var key = gDBView.getKeyAt(row);    //その行(row)のメッセージのkeyを取得
    var index = gDBView.findIndexFromKey(key,false);    //取得したkeyからそのメッセージのindexを取得
    var uri = gDBView.getURIForViewIndex(index);    //取得したindexからMessageURIを取得
    var headers = mfGetHeaders(uri);    //指定したMessageURIのヘッダ一覧を取得
    if (headers == null) return "";
    var retval = headers.extractHeader("X-xxx",false);    //取得したヘッダ一覧から"X-xxx"ヘッダの値を取得
    return retval;
   },

   getSortStringForRow: function(hdr) {
    return headers.extractHeader("X-xxx",false);
   },
   isString:            function() {return true;},
   getCellProperties:   function(row, col, props){},
   getImageSrc:         function(row, col) {return null;},
   getSortLongForRow:   function(hdr) {return 0;}
}

function addCustomColumnHandler() {
  gDBView.addColumnHandler("xxxCol",columnHandler);
}

var CreateDbObserver = {
  // Components.interfaces.nsIObserver
observer: function(aMsgFolder, aTopic, aData)
    {
       addCustomColumnHandler();
    }
}

function doOnceLoaded(){
  var ObserverService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  ObserverService.addObserver(CreateDbObserver, "MsgCreateDBView", false);
  window.document.getElementById('folderTree').addEventListener("select",addCustomColumnHandler,false);
}

window.addEventListener("load",doOnceLoaded,false);

function mfGetHeaders(messageURI)
{
  //var messageURI = GetFirstSelectedMessage();
  var messageService = messenger.messageServiceFromURI(messageURI);
  var messageStream = Components.classes["@mozilla.org/network/sync-stream-listener;1"].createInstance()
                      .QueryInterface(Components.interfaces.nsIInputStream);
  var inputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance()
                    .QueryInterface(Components.interfaces.nsIScriptableInputStream);
  inputStream.init(messageStream);
  try {
    messageService.streamMessage(messageURI,messageStream, msgWindow, null, false, null);
  } catch (ex) {
    mfDump("Could not stream message '" + messageURI + "'.");
    return null;
  }

  var content = "";
  inputStream.available();
  while (inputStream.available()) {
    content = content + inputStream.read(512);
    var p = content.indexOf("\r\n\r\n");
    var p1 = content.indexOf("\r\r");
    var p2 = content.indexOf("\n\n");
    if (p > 0) {
      content = content.substring(0, p);
      break;
    }
    if (p1 > 0) {
      content = content.substring(0, p1);
      break;
    }
    if (p2 > 0) {
      content = content.substring(0, p2);
      break;
    }
    if (content.length > 512 * 8)
    {
      mfDump("Could not find end-of-headers line.");
      return null;
    }
  }
  content = content + "\r\n";

  var headers = Components.classes["@mozilla.org/messenger/mimeheaders;1"].createInstance()
                .QueryInterface(Components.interfaces.nsIMimeHeaders);
  headers.initialize(content, content.length);
  return headers;
}

これを実装するために、何日悩んだことかw
でも、MDCのページの画像を見る限り、getStringProperty("ヘッダ名")でカスタムヘッダの値は取得できてるようにしか見えない…
詳細分かる人いたら教えてくださいm(_ _)m

greasemonkeyでMyYahoo!の広告を消してみた

私はFireFoxを使っており、ホームページをYahoo!My Yahoo!にしているのだが、
最近My Yahoo!のβバージョンが公開された。
このバージョンではiGoogleのようにトピックスやRSSをブロックで表示して、
そのブロックの位置を自由に変えたり、表示方法をカスタマイズできたりするのだが、
右上に「PR」と書かれたブロックに広告が表示されている。
この広告は他のブロックと違い移動させたり、非表示にしたりは仕様上出来ない模様なので、
greasemonkeyで非表示にしてみた。

// ==UserScript==
// @name           MyYahoo
// @namespace      MyYahoo
// @include        http://cm.my.yahoo.co.jp/
// ==/UserScript==

var myYads = document.getElementById("myyads");
myYads.setAttribute("style","display:none");

こんな感じ

↓↓↓↓↓↓


自分で非表示にするのは問題ないよね?