Nano Hash - криптовалюты, майнинг, программирование

XUL/Thunderbird: возврат startEditing

Я играю с кодовой базой Thunderbird, цель состоит в том, чтобы внедрить встроенное редактирование контактов. Текущий код перехватывает событие Click в дереве XUL и, если это двойной щелчок (events.detail == 2), открывает редактор профиля. Я изменил его, чтобы начать редактирование текущего treeCell, и я добавил editable=true в соответствующий документ XUL. Обновленный код читает

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 помочь? Спасибо!


  • Дополнительный вопрос: кажется, что Thunderbird кэширует файлы сценариев: когда я создаю новый профиль, все изменения в файлах сценариев tb регистрируются правильно. Но тогда никакие дальнейшие изменения не применяются. Поэтому, если я внесу изменения в исходный код js после создания профиля, мне придется воссоздать новый, чтобы эти новые изменения были приняты во внимание. 27.10.2011

Ответы:


1

Я пытался сделать что-то подобное, и у меня такая же проблема.

Оболочка с исходным 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, но его можно изменить, чтобы просто создать оболочку.

22.03.2012
  • Спасибо, Дэвид. Не могли бы вы немного рассказать о том, как работает этот код? 23.03.2012
  • В основном это: 1. создать экземпляр исходного abview 2. найти все интерфейсы, реализованные abview 3. создать обертку abview: - определить его функцию QueryInterface, в случае, если интерфейс поддерживается, он должен вернуть оболочку, а не обернутый экземпляр - определить любые функции / свойства, которые вы хотите переопределить - другие функции/свойства будут использоваться из обернутого экземпляра (это достигается функцией generatePropertyProxy) 24.03.2012
  • generatePropertyProxy — самый сложный шаг, таким образом, он действует так же, как обернутый экземпляр был бы установлен в качестве прототипа оболочки, но он не ломается, как если бы использовался __proto__ 24.03.2012

  • 2

    Виджет <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() должен хранить новое значение для ячейки.

    27.10.2011
  • Спасибо большое=) Только один вопрос: что за жеманство в gAbResultsTree.treeBoxObject.view = gAbViewWrapper.QueryInterface(...)? Если QueryInterface что-то возвращает, то что делает вызов в gAbViewWrapper? 27.10.2011
  • Я пробовал этот метод, но я не могу заставить его работать. Кажется, что функция IsEditable в gAbViewWrapper никогда не вызывается:/ 27.10.2011
  • @Clément: метод называется isEditable() в JavaScript, а в C++ — только IsEditable(). Относительно QueryInterface() см. советы по JavaScript — использование возвращаемого значения не обязательно в JavaScript, вызов изменяет исходный объект. Вызов в gAbResultsTree гарантирует, что исходный объект реализует этот интерфейс - если это не так, то вызов вызовет исключение, и значение не будет возвращено. 27.10.2011
  • Извините, я сделал опечатку в своем комментарии. Я использовал isEditable в своем js-коде, но все равно не повезло. Я разместил свой abResultsPane.js на pastebin.com/jqbL3wHF . Не могли бы вы взглянуть? Я действительно не вижу, что я делаю неправильно :/ 28.10.2011
  • @Clément: Прежде всего, вам, очевидно, нужно объявить gAbViewWrapper (ниже var gAbView = null имело бы смысл). Вы не должны создавать новый экземпляр каждый раз, когда вызывается SetAbView(), только в первый раз — добавьте создание оболочки в блок if (!gAbView) выше. Наконец, alert() не определяется в компонентах XPCOM, используйте Components.utils.reportError() и проверьте консоль ошибок. 28.10.2011
  • Спасибо. Просто чтобы проверить, правильно ли я понимаю, это означает, что gAbResultsTree.treeBoxObject.view = gAbViewWrapper.QueryInterface(...) — это более короткий способ записи gAbResultsTree.treeBoxObject.view = gAbViewWrapper; gAbViewWrapper.QueryInterface(...), хорошо? 28.10.2011
  • @Clément: наоборот: gAbViewWrapper.QueryInterface(...); gAbResultsTree.treeBoxObject.view = gAbViewWrapper;. Но да. 28.10.2011
  • Извините, но у меня действительно проблемы с этим. Я обновил свой код (pastebin.com/FAiFNMiN), и прямой вызов gAbViewWrapper.isEditable работает отлично. Однако когда я вызываю gAbResultsTree.treeBoxObject.view.isEditable, я получаю ту же ошибку, что и раньше. То же самое, когда я вызываю startEditing. Есть идеи? Спасибо еще раз. 28.10.2011
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..