Добавление повторно объекта через insertTextContent(...)

Автор 0xJah, 19 декабря 2013, 12:35

0 Пользователи и 1 гость просматривают эту тему.

0xJah

Добрый день.
Хочу добавлять одно и тоже текстовое поле в разные места текстового документа.
Имеется функция:
def addNewField(document, name, value):
userField = document.createInstance("com.sun.star.text.fieldmaster.User")
userField.setPropertyValue("Name", name)
userField.setPropertyValue("Content", value)
textField = document.createInstance("com.sun.star.text.textfield.User")
textField.attachTextFieldMaster(userField)
document.Text.insertTextContent(document.Text.createTextCursor().getStart(), textField, 0)
document.Text.insertTextContent(document.Text.createTextCursor().getEnd(), textField, 0)


Поле вставляется в начале текста, а вот в конце не вставляется, возникает какая-то ошибка. Ни как не удается повторно вставить одно и тоже поле, в документации ни где не нашел упоминаний о данном моменте.
Не может же быть, что нету метода обойти эту проблему.

JohnSUN

А что за ошибка?

Есть у меня смутное подозрение... Попробуй вычислить document.Text.createTextCursor() один раз, сохрани в переменную и используй её в обоих insertTextContent. Могу ошибаться, но может получиться, что второй createTextCursor относится не ко всему тексту документа, а к тексту только что вставленного поля. (Если ерунду написал - будь  снисходителен: температура у меня, соображаю туго, а помочь хочется)
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

0xJah

ЦитироватьА что за ошибка?
А вот не знаю, я запускаю скрипт как макрос и просто на повторном вызове insertTextContent макрос прекращает выполняться без вывода текста ошибки (что очень не удобно конечно).

ЦитироватьЕсть у меня смутное подозрение... Попробуй вычислить document.Text.createTextCursor() один раз, сохрани в переменную и используй её в обоих insertTextContent. Могу ошибаться, но может получиться, что второй createTextCursor относится не ко всему тексту документа, а к тексту только что вставленного поля. (Если ерунду написал - будь  снисходителен: температура у меня, соображаю туго, а помочь хочется)
Да не, я уже второй день мучаюсь с этой проблемой, пробовал по всякому, но дело не в курсоре. Вот например такой код не сработал:
Цитироватьdef addNewField(document, name, value):
   userField = document.createInstance("com.sun.star.text.fieldmaster.User")
   userField.setPropertyValue("Name", name)
   userField.setPropertyValue("Content", value)
   textField = document.createInstance("com.sun.star.text.textfield.User")
   textField.attachTextFieldMaster(userField)
   cur = document.Text.createTextCursor()
   document.Text.insertTextContent(cur.getStart(), textField, 0)
   document.Text.insertTextContent(cur.getEnd(), textField, 0)
Или даже если один и тот же курсор передавать, то все равно при повторном вызове insertTextContent ошибка.

Если у меня такое предположение:
Если посмотреть в xml код документа, то вначале все поля описываются в отдельном блоке, а потом уже среди текста документа просто вставлены теги ранее описанных полей. Так вот думается мне, что при вызове insertTextContent он в обязательном порядке объявляет поле, а так как оно ранее уже объявлено и случается ошибка.
Может подскажите как работать с xml содержимым документа? И таким костыльным методом обойду эту проблему.

JohnSUN

А давай зайдём с другой стороны: расскажи не про проблему, а про задачу - ты чего вообще замутить хочешь? Формирование документа по шаблону и данным из внешнего источника? Тогда почему через вставку полей, а не, скажем через поиск/замену заранее вставленных тэгов на нужные значения? Или  как недавно Helen описывала -выдрать из шаблона content.xml, заменить данные прямо в нём, затолкать обратно в ZIP и открыть результат в  новом экране для просмотра
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

0xJah

ЦитироватьА давай зайдём с другой стороны: расскажи не про проблему, а про задачу - ты чего вообще замутить хочешь? Формирование документа по шаблону и данным из внешнего источника?
Прям в точку. Написал некий движок, который на вход получает odt файл, парсит content.xml и заменяет теги расставленные в шаблоне на информацию из БД.
Сейчас же пишу макрос с помощью которого, можно легко формировать шаблоны и сразу указывать из какого поля в базе нужно подставлять значение какому тегу.
Имя поля хочу генерировать примерно таким образом: имяТаблицы_схема_колонка. Решил использовать поля, т.к. описанные только, что мною связи базы с тегами хочу скрыть от глаз пользователя, ну просто из соображений, чтобы не перегружать документ лишней информацией. Т.е. в моем случае поле это и есть тег, который за собой еще скрывает и информацию описывающую связь с БД.

ЦитироватьИли  как недавно Helen описывала -выдрать из шаблона content.xml, заменить данные прямо в нём, затолкать обратно в ZIP и открыть результат в  новом экране для просмотра
Этот вариант у меня уже в голове давно, но он костыльный и я его буду рассматривать в самом крайнем случае. Перезагружать документ при каждой вставке тега не есть гуд! По этому ищу пока решения которые можно реализовать с использованием API OOo.

JohnSUN

Хорошая задача, вкусная  ;D Сам бы охотно занялся реализацией! Если бы в своё время не потратил пару дней на знакомство со встроенными инструментами офиса - двумя редакторами отчетов для Base, циркулярным письмом и "драг-н-дропным" способом набрасывания полей прямо из таблиц (запросов) БД в текстовый документ.
Жаль, но сейчас просто под рукой нет инструмента, чтобы нарисовать анимированную гифку - было бы нагляднее. Попробую описать словами.
Попробуй так:
1. Убедись, что нужная база данных зарегистрирована в офисе (открой шаблон будущего документа, нажми F4 - Источники данных - если нужная база есть в списке в левой части браузера, значит зарегистрирована нормально)
2. Разверни содержимое нужной таблицы/запроса
3. Зацепи мышкой заголовок нужной колонки (в таблице в правой части браузера), перетащи в нужное место документа и брось - офис вставит поле из категории База данных-Поля слияния. (То же самое можно сделать через Ctrl+F2 или через кнопку с панели управления "Данные в текст").Переключаешь поля между отображением База.Таблица.Поле и значениями - как обычно, через Ctrl+F9
4. Теперь выделяешь нужную запись в таблице и жмёшь "Данные в поля"

Можно было бы щелкнуть Циркулярное письмо и большую часть черновой работы выполнить через Мастера.

Я не "агитирую за советскую Власть", просто предлагаю попробовать.
Сам посуди, если в целом механизм окажется более-менее приемлемым, то твоя работа над движком должна сильно упроститься
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

ALexey7ov

#6
Я сам раньше не знал о таком свойcтве тектового поля, что каждый экземпляр надо вставлять отдельно, т.е., создать экземпляр, вставить его в документ и т.д. с новыми экз. Т.к. раньше вставлял только по 1 полю. Для текстовых таблиц не проверял повторную вставку и для других textContent объектов.
Вот код оформленый для процедуры:

sub insTF
Rem Макрос написан Alexey7ov для 0xJah 25/12/13,
Rem стр.: http://forumooo.ru/index.php/topic,3844.0.html
dim i as integer
dim tdoc as object
dim usF as object
dim txtF(1) as object
dim tCursS as object
dim tCursE as object
dim tCurs as object
tdoc=thiscomponent
tCursS=tdoc.Text().getStart()
tCursE=tdoc.Text().getEnd()
usF=tdoc.createInstance("com.sun.star.text.fieldmaster.User") ' Создание в документе пользовательского поля
usF.Name="Al": usF.Content="Alexey7ov"
for i=0 to 1
 txtF(i)=tdoc.createInstance("com.sun.star.text.textfield.User")
 txtF(i).attachTextFieldMaster(usF) ' Создаёт ссылку на главное поле
 tCurs=iif(i=0,tCursS,tCursE)
 tdoc.Text.insertTextContent(tCurs,txtF(i),0)
next
end sub

0xJah

Цитата: ALexey7ov от 25 декабря 2013, 13:01
Я сам раньше не знал о таком свойcтве тектового поля, что каждый экземпляр надо вставлять отдельно, т.е., создать экземпляр, вставить его в документ и т.д. с новыми экз. Т.к. раньше вставлял только по 1 полю. Для текстовых таблиц не проверял повторную вставку и для других textContent объектов.
Вот код оформленый для процедуры:

sub insTF
Rem Макрос написан Alexey7ov для 0xJah 25/12/13,
Rem стр.: http://forumooo.ru/index.php/topic,3844.0.html
dim i as integer
dim tdoc as object
dim usF as object
dim txtF(1) as object
dim tCursS as object
dim tCursE as object
dim tCurs as object
tdoc=thiscomponent
tCursS=tdoc.Text().getStart()
tCursE=tdoc.Text().getEnd()
usF=tdoc.createInstance("com.sun.star.text.fieldmaster.User") ' Создание в документе пользовательского поля
usF.Name="Al": usF.Content="Alexey7ov"
for i=0 to 1
  txtF(i)=tdoc.createInstance("com.sun.star.text.textfield.User")
  txtF(i).attachTextFieldMaster(usF) ' Создаёт ссылку на главное поле
  tCurs=iif(i=0,tCursS,tCursE)
  tdoc.Text.insertTextContent(tCurs,txtF(i),0)
next
end sub

Alexey7ov, премного Вам благодарен! Код действительно рабочий, пробовал подобное, но вот было небольшое отличие которое и сбило меня с верного пути.
А я уже костыль прикрутить успел к своему коду, добавлял к имени поля рандомно сгенерированную приставку и имя получалось уникальное, но сейчас переделал код по Вашему примеру, а то стыдно иметь такое творение.