2011-10-27 20 views
0

我在玩雷鳥代碼庫,目的是實現內聯聯繫人編輯。當前代碼捕獲樹上的Click事件,如果它是雙擊(events.detail == 2),它將打開配置文件編輯器。我修改了它,以便開始編輯當前的treeCell,並且我確實將editable=true添加到了對應的XUL文件中。更新後的代碼讀取XUL/Thunderbird:startEditing return

var orow = {}, ocolumn = {}, opart = {}; 
gAbResultsTree.treeBoxObject.getCellAt(event.clientX, event.clientY, 
             orow, ocolumn, opart); 

var row = orow.value, column = ocolumn.value.index;   
if (row == -1) 
    return; 

if (event.detail == 2) 
    gAbResultsTree.startEditing(row, column); 

不幸的是,當代碼到達startEditing部分,它返回

Error: uncaught exception: [Exception... "Component returned failure code: 0x80004001 (NS_ERROR_NOT_IMPLEMENTED) [nsITreeView.isEditable]" nsresult: "0x80004001 (NS_ERROR_NOT_IMPLEMENTED)" location: "JS frame :: chrome://global/content/bindings/tree.xml :: startEditing :: line 337" data: no]

我幾乎失去了這裏。有更多XUL經驗的人可以幫忙嗎? 謝謝!

+0

方面的問題:雷鳥似乎緩存腳本文件:當我創建一個新的配置文件時,所有對tb腳本文件的更改都被正確註冊。但是沒有進一步的修改。因此,如果我在創建配置文件後對js源進行了修改,則必須重新創建一個用於這些新更改的新配置,以便將其考慮在內。 –

回答

2

我試圖做類似的事情,我也有同樣的問題。

原始abview設置爲__proto__的包裝函數覆蓋了函數,直到它被設置爲abResultsTree的視圖。

我終於找到了(我希望)一個優雅的解決方案。

function MyAbView() { 
    this.originalAbViewInstance = this.originalAbViewFactory.createInstance(null, Ci.nsIAbView); 

    if (!this.proxiesGenerated) { 
     // find out which interfaces are implemented by original instance, their property proxies will be generated later 
     for (var ifName in Ci) { 
      if (Ci[ifName] instanceof Ci.nsIJSID && this.originalAbViewInstance instanceof Ci[ifName]) { 
       MyAbView.prototype.supportedInterfaces.push(Ci[ifName]); 
      } 
     } 

     function generatePropertyProxy(name) { 
      Object.defineProperty(MyAbView.prototype, name, { 
       get: function() { 
        return this.originalAbViewInstance[name]; 
       }, 
       set: function(val) { 
        this.originalAbViewInstance[name] = val; 
       }, 
       enumerable: true 
      }); 
     } 

     for (var prop in this.originalAbViewInstance) { 
      if (this[prop] == undefined) { 
       generatePropertyProxy(prop); 
      } 
     } 

     MyAbView.prototype.proxiesGenerated = true; 
    } else { 
     for each (var interface in this.supportedInterfaces) { 
      this.originalAbViewInstance.QueryInterface(interface); 
     } 
    } 
} 

MyAbView.prototype = { 
    classID: null, 

    _xpcom_factory: { 
     createInstance: function(outer, iid) { 
      return new MyAbView().QueryInterface(iid); 
     } 
    }, 

    QueryInterface: function(aIID) { 
     for each (var interface in this.supportedInterfaces) { 
      if (interface.equals(aIID)) { 
       return this; 
      } 
     } 

     throw Components.results.NS_ERROR_NO_INTERFACE; 
    }, 

    originalAbViewFactory: null, 
    originalAbViewInstance: null, 

    proxiesGenerated: false, 
    supportedInterfaces: [], 

    // any overriden functions come here 
}; 

它被實現爲一個組件來替換原始的abview,但它可能被修改爲只創建一個包裝。

+0

謝謝大衛。你可以擴展一下這個代碼的工作原理嗎? –

+0

基本上是: 1.創建原始abview的實例 2.查找由abview實現的所有接口 3.創建abview包裝器: - 定義其「QueryInterface」函數,以防接口被支持時它必須返回包裝器,而不是包含的實例 - 定義要覆蓋的任何函數/屬性 - 將從包裝實例中使用其他函數/屬性(這是通過'generatePropertyProxy'函數實現的) –

+0

'generatePropertyProxy'是最棘手的一步,通過這種方式它與包裝實例類似的行爲將被設置爲包裝器的原型,但不會像使用__proto__一樣中斷 –

1

<tree>小部件使用nsITreeView對象來檢索或操作需要顯示的數據。有預定義的nsITreeView實現從DOM或RDF數據源讀取數據,但可以選擇使用他自己的樹視圖。 Thunderbird的地址簿中選擇了後者:

gAbView = Components.classes["@mozilla.org/addressbook/abview;1"] 
        .createInstance(Components.interfaces.nsIAbView); 

... 

gAbResultsTree.treeBoxObject.view = 
    gAbView.QueryInterface(Components.interfaces.nsITreeView); 

不幸的是你,有問題的部件是用C++實現的,該文件nsAbView.cpp英寸這意味着在不重新編譯Thunderbird的情況下更改它是不可能的。並且現有組件不執行編輯樹單元格所需的方法isEditable()setCellText()

如果您不想亂用C++,那麼您可以將該組件包裝在自己的對象中。事情是這樣的:

gAbView = Components.classes["@mozilla.org/addressbook/abview;1"] 
        .createInstance(Components.interfaces.nsIAbView); 
gAbViewWrapper = { 
    __proto__: gAbView, 
    QueryInterface: function(iid) 
    { 
    gAbView.QueryInterface(iid); 
    return this; 
    }, 
    isEditable: function(row, col) 
    { 
    // Do something here 
    }, 
    setCellText: function(row, col, value) 
    { 
    // Do something here 
    } 
}; 

... 

gAbResultsTree.treeBoxObject.view = 
    gAbViewWrapper.QueryInterface(Components.interfaces.nsITreeView); 

方法isEditable()應再次檢查這個特定的細胞是否可編輯 - 即使列可編輯,個別細胞沒有要。並且setCellText()應該存儲單元格的新值。

+0

非常感謝=)只有一個問題:在'gAbResultsTree.treeBoxObject.view = gAbViewWrapper.QueryInterface(...)'中有什麼作用?如果'QueryInterface'返回一些內容,那麼'gAbViewWrapper'中的調用是做什麼的? –

+0

我試過這種方法,但我無法讓它工作。看起來gAbViewWrapper中的IsEditable函數從未被調用過:/ –

+0

@Clément:該方法在JavaScript中被稱爲isEditable(),它在C++中只是IsEditable()。關於'QueryInterface()'參見[JavaScript技巧](https://developer.mozilla.org/en/JavaScript_Tips#XPConnect) - 在JavaScript中使用返回值不是必需的,該調用修改了原始對象。 'gAbResultsTree'中的調用可以確保原始對象實現此接口 - 如果不是,則調用將拋出異常並且不會返回任何值。 –