tagezi_ has quit [Quit: No Ping reply in 180 seconds.]
tagezi has joined #libreoffice-ru
kompi has joined #libreoffice-ru
<kompi>
утра
<kompi>
mikekaganski: то, что я вчера успел почитать про выделение в Либре и макросы мне совершенно не понравилось=(
<mikekaganski>
:)
<mikekaganski>
сделаем
<kompi>
я не сомневаюсь
<kompi>
mikekaganski: а еще мне приснилось, что либра начинает падать, после изменения всех формул в документе, потому что начинает жрать память засовывая все объекты в ОЗУ и не очищая ОЗУ после завершения операции=(
<mikekaganski>
:))
<mikekaganski>
Ну что, сделаем выделение?
<mikekaganski>
для начала давай определимся с принципом. Возможны два варианта: 1. если что-то выделено в документе, работа идёт в выделенном, иначе везде; 2. Если есть выделение, то можно нажать галочку в диалоге
<kompi>
2 вариант, в первом может быть что-то выделено случайно или забыл юзер или мышой случайно двинул или еще что
<mikekaganski>
Ок. Значит, нужно работать с диалогом.
<kompi>
а может сделать две кнопки? "Форматировать все" и "Форматировать в выделенном диапазоне"?
<mikekaganski>
Без разницы, оба варианта нормальные
<mikekaganski>
выбирай, и приступим
<kompi>
мне кажется вариант с двумя кнопками проще, просто откопировать процедуру, переименовать и добавить собственно ловлю выделения
<kompi>
давай две кнопки
<mikekaganski>
Если ты выбираешь, что проще, ты ошибаешься - одинаково. И мы не будем ничего копировать
<mikekaganski>
но мне вариант с двумя кнопками тоже нравится больше
<mikekaganski>
давай на нём и остановимся.
<kompi>
ок
<mikekaganski>
И теперь то, что я давно хотел, но теперь появился повод: для того, чтобы сделать хорошо с двумя кнопками, мы избавимся от глобальной переменной oDialog1, и изменим Formatting
<kompi>
напомни мне про Option....чего-то там, чтобы переменные явно задавать всегда
<mikekaganski>
Option Explicit
<kompi>
хорошо (вот он рефакторинг)
<mikekaganski>
в самом начале
<kompi>
в каждой процедуре?
<kompi>
или всего листинга?
<mikekaganski>
нет, в самом начале файла
<mikekaganski>
да
<kompi>
доне
<mikekaganski>
прогони программу; для каждой ошибки проверь, что в нужном месте есть Dim
<kompi>
(про "давно хотел" мне понравилось)
<mikekaganski>
Ну, ты же не думаешь, что я с чистого листа с тобой работаю: я всё это уже прогнал :)
<kompi>
Doc=ThisComponent - это объект или строка?
<mikekaganski>
Это объект
<mikekaganski>
Dim oDoc As Object (я бы сделал oDoc вместо Doc)
<mikekaganski>
но это вкусовщина
<kompi>
Nobj=Doc.DrawPage.Count-1
<mikekaganski>
dim nObj As Long
<kompi>
mikekaganski: i для цикла как определять?
<mikekaganski>
Перед циклом Dim i As Long
<kompi>
доне
<mikekaganski>
прекрасно
<kompi>
олл доне
<mikekaganski>
Теперь давай уберём oDialog1
<mikekaganski>
Он у тебя устанавливается в DialogFormattingShow
<kompi>
из начала листинга?
<mikekaganski>
и нужен для того, чтобы Formatting знал, откуда брать элементы диалога и их значение
<kompi>
угу
<kompi>
чем он плох?
<mikekaganski>
Но на самом деле это не нужно. Formatting вызывается, когда пользователь нажал на кнопку диалога; в этом событии есть возможность узнать, что за диалог активен
<mikekaganski>
Любая глобальная переменная - плохо. Нужно стараться без них обходиться. Возможны варианты ошибок пользователя
<mikekaganski>
и тогда глобальные переменные могут перетереться, или конфликтовать
<mikekaganski>
использовать их нужно только если нет возможности обойтись без них
<mikekaganski>
так вот
<mikekaganski>
твой Formatting озаглавлен просто: Sub Formatting .... End Sub
<mikekaganski>
Без каких-либо аргументов, передаваемых в него
<kompi>
да
<mikekaganski>
Он у тебя назначен кнопке форматирования в качестве обработчика нажатия
<kompi>
да
<mikekaganski>
так вот, Либра при нажатии передаёт туда специальный объект-событие, а ты его просто игнорируешь
<kompi>
ЛИбра мне ничего не говорил
<mikekaganski>
в этом объекте есть полезная информация, в частности - источник - объект-кнопка
<mikekaganski>
ну и не долен говорить, он уважает твоё решение
<mikekaganski>
"Ну что же, не нужен kompi объект - не буду настаивать" :))
<kompi>
ок
<mikekaganski>
Сейчас мы разделим обработку события (нажатия на кнопку) и работу по форматированию
<kompi>
я знаю чего не хватает IDE Basic в ЛИбре: возможности сворачивать процедуры и функции под плюсик
<mikekaganski>
для начала создадим маленькую процедуру: Sub OnFormattingClick(ByRef aMouseEvent)
<mikekaganski>
Вот этот aMouseEvent и получит от ЛО данные о событии
<mikekaganski>
В нём есть свойство Source - объект-кнопка
<mikekaganski>
а у объекта-кнопки есть свойство Context - это диалог (тот самый объект, который пока что ты хранишь в глобальной oDialog1)
<mikekaganski>
Поэтому достать этот объект в этой процедуре можно так: aMouseEvent.Source.Context
<kompi>
вот она вся прелесть ООП
<mikekaganski>
Теперь нужно передать его в твой Formatting
<mikekaganski>
Для этого поправим Formatting так: Sub Formatting(ByRef oDialog)
<kompi>
доне
<mikekaganski>
Теперь внутри Formatting заменим все oDialog1 на oDialog (не нравится мне эта единица :))
<kompi>
доне
<mikekaganski>
Функция OnFormattingClick должна пока что выполнять всего одно действие: вызывать Formatting, передавая туда этот диалог
<mikekaganski>
Вот так: Formatting(aMouseEvent.Source.Context)
<mikekaganski>
Это единственная команда в OnFormattingClick
<kompi>
не понял
<mikekaganski>
Sub OnFormattingClick(ByRef aMouseEvent)
<mikekaganski>
Там, где ты создал OnFormattingClick, скопируй эту маленькую функцию рядом, и назови её Sub OnSelectionFormattingClick(ByRef aMouseEvent)
<mikekaganski>
пока что они делают одно и то же
<mikekaganski>
Назначь эту новую функцию новой кнопке
<kompi>
доне
<mikekaganski>
ок. Теперь самое главное - работа с выделением
<kompi>
угу
<mikekaganski>
Для того, чтобы сделать твою главную функцию - Formatting - универсальной, мы должны сделать так, чтобы она могла работать в обоих случаях, просто для разных объектов
<kompi>
ты уверен, что это лучше, чем две процедуры рядом?
<mikekaganski>
Этого можно дбиться, если мы в неё передадим кким-то образом нечто, что сможет сказать, попадает этот объект в обрабатываемый диапазон или нет
<mikekaganski>
однозначно
<kompi>
погоди
<mikekaganski>
имея две дублирующиеся функции, ты гарантированно нарываешься на баги, когда потом в одной поправил, во второй забыл
<kompi>
хм
<kompi>
ну ок, звучит разумно...
<kompi>
ладно, го далее
<mikekaganski>
например, в качестве хотелки у тебя есть "обрабатывать больше свойств функций"
<mikekaganski>
так тебе придётся это делать в двух местах
<mikekaganski>
го
<mikekaganski>
предлагаю передавать в Formatting объект-выделение, который может быть пустым, и ввести новую функцию, которая сможет сказать нам, входит ли любой данный объект в это выделение
<mikekaganski>
Это один из возможных вариантов, есть другие, просто этот проще вписывается в твою уже имеющуюся структуру
<mikekaganski>
Итак, сейчас мы немного изменим Formatting ещё раз: Sub Formatting(ByRef oDialog, ByRef oSel)
<mikekaganski>
этот oSel и будет объектом-выделением
<kompi>
тыц тыц тыц...
<mikekaganski>
Мы придумаем новую функцию IsInSelection - позже. А пока изменим условие, которое говорит нам, обрабатывать очередной объект в цикле или нет
<mikekaganski>
If (Obj.supportsService("com.sun.star.text.TextEmbeddedObject")) then
<mikekaganski>
Это у тебя сейчас так
<mikekaganski>
ну, или почти так
<kompi>
угу
<mikekaganski>
То есть каждый объект у тебя проверяется (процедура принимает решение, возиться с ним дельше или нет)
<mikekaganski>
так мы добавим ещё условие
<mikekaganski>
If (IsInSelection(Obj, oSel) And Obj.supportsService("com.sun.star.text.TextEmbeddedObject")) then
<mikekaganski>
То есть обрабатывать дальше будем только если этот объект нужного типа, и при этом входит в выделение
<mikekaganski>
как я уже сказал, IsInSelection - это пока воображаемая функция, которую мы сделаем реальной - начнём прямо сейчас
<kompi>
погоди
<mikekaganski>
годю
<kompi>
я чуть не уловил
<kompi>
мне изменить существуюшее условие или добавить новое?
<mikekaganski>
изменить
<mikekaganski>
я добавил условие в существующую строчку - посмотри на неё внимательно
<mikekaganski>
сравни до и после
<kompi>
я вижу
<mikekaganski>
далее?
<kompi>
ты просто сформулировал "добавим", это меня смутило
<kompi>
да, го
<mikekaganski>
Function IsInSelection(ByRef oObj, ByRef oSel) ... End Function
<mikekaganski>
Эта функция принимает объект (например, формулу) и объект-выделение, и должна нам сказать, входит первый во второй или нет (т.е., работать дальше или нет)
<mikekaganski>
я имею ввиду, работать дальше с этим объектом, или игнорировать его и перейти к следующемы
<mikekaganski>
пока что заставим эту функцию всегда говорить "да, работать" - это будет временная заглушка
<kompi>
хм
<mikekaganski>
Единственным действием пока что пропишем ей IsInSelection = true
<mikekaganski>
Получится вот что:
<mikekaganski>
Function IsInSelection(ByRef oObj, ByRef oSel)
<mikekaganski>
IsInSelection = екгу
<mikekaganski>
End Function
<mikekaganski>
true
<mikekaganski>
сорри
<kompi>
переменная IsInSelection это?
<mikekaganski>
Это имя функции
<mikekaganski>
Когда внутри функции мы присваиваем что-то самой функции - мы говорим, какой будет результат у функции
<kompi>
то есть ее не надо объявлять, как переменную? оно внутри себя ссылается на сеяб же?
<mikekaganski>
Да
<kompi>
ясно
<mikekaganski>
Чего мы пока что добились? Во-первых, что ничего не работает
<kompi>
подсветки имен процедур и фнкций тоже не хватает
<mikekaganski>
во-вторых, что теперь нам нужно что-то передавать в Formatting, и это что-то будет разным в случае одной и другой кнопок
<mikekaganski>
И теперь мы поработаем с тем, как же получить выделение документа
<mikekaganski>
У документа есть свойство - CurrentSelection
<kompi>
ага!
<kompi>
я ж говорил вчера, что пепяка есть
<mikekaganski>
Этот объект может содержать несколько выделенных диапазонов текста (например, когда ты делаешь выделение с Ctrl)
<kompi>
а если не текста?
<mikekaganski>
а может содержать один графический объект (если ты щёлкнул по формуле, и она сейчас выделена с помощью ручек в документе)
<kompi>
погоди
<kompi>
почему ОДИН объект
<mikekaganski>
и даже несколько графических дкументов, выделенных через Ctrl
<mikekaganski>
Но формулы не выделяются по нескольку, так что нам пока последний вариант не нужен
<mikekaganski>
Если выделения нет, объект CurrentSelection всё равно есть, и он показывает единственный выделенный диапазон текста - который начинается на курсоре, и заканчивается тоже на курсоре
<mikekaganski>
то есть имеет нулевую длину
<kompi>
подожди
<kompi>
ты сейчас рассматриваешь только документ Writer
<mikekaganski>
жду
<kompi>
а Draw?
<kompi>
в Draw формулы можно выделить рамочкой и они прекрасно выделяются
<mikekaganski>
А почему ты не работаешь с Calc?
<mikekaganski>
там тоже можно вставить формулу
<kompi>
давай тогда определимся, что ни в каких иных модулях это работать не будет, так получается?
<mikekaganski>
А у тебя оно работало в Draw?
<kompi>
я вот сейчас сунулся проверить, а оно же у нас испорчено пока
<kompi>
а у тебя не работало?
<mikekaganski>
нет
<kompi>
хм
<mikekaganski>
но ты можешь пока проверить
<mikekaganski>
в твоих функциях
<mikekaganski>
OnFormattingClick
<kompi>
текстэмбеддинг объект
<mikekaganski>
исправь Formatting(aMouseEvent.Source.Context) на Formatting(aMouseEvent.Source.Context, Nothing)
<kompi>
то есть это объект вставленный в текст, а это Вритер, так получается?
<mikekaganski>
там раньше проблема вылезет - в Draw нет DrawPage :)
<mikekaganski>
но раз ты заговорил про другие модули - это гут
<mikekaganski>
давай тогда пересмотрим наш подход в пользу более универсального
<mikekaganski>
это, правда, потребует бОльших модификаций (в т.ч. в Formatting), но зато позволит расшириться впоследствии на другие модули
<mikekaganski>
и пока мы не сделали много, сейчас самое время для такого решения
<kompi>
да, давай универсалить
<kompi>
идея была, что на плакатах также могут быть формулы и их также нужно будет подгонять под формат листа или типа того
<mikekaganski>
прекрасно. Тогда давай договоримся так: в Formatting будем просто передавать уже подготовленный список объектов. И этим мы займёмся в другом месте, а Formatting не будет уже перебирать объекты, а будет работать уже с отобранными
<kompi>
нет проблем
<mikekaganski>
тогда её объявление станет таким: Sub Formatting(ByRef oDialog,ByRef vFormulaObjects)
<kompi>
ага
<mikekaganski>
второй параметр - это массив (вектор) объектов под обработку. Если мы захотим обработать весь документ - мы должны будем подготовить массив всех объектов; если только выделение - значит, только выделение
<kompi>
значит, только объекты, которые попали в выделение
<kompi>
ок
<mikekaganski>
На долю Formatting останется только проверить, что это формула, и применить форматирование
<kompi>
логично =)
<mikekaganski>
Так, чтобы мне работать с твоим кодом, отправь твою Formatting в pastebin
<mikekaganski>
Здесь мы сначала объявляем объект oDialog и считываем его из объекта-события, переменную-документ - из ThisComponent, это всё уже было
<kompi>
да
<mikekaganski>
самое главное здесь - вызов Formatting(oDialog, GetObjectsFromDoc(oDoc, Nothing))
<mikekaganski>
мы тут используем пока что ненаписанную GetObjectsFromDoc
<kompi>
db;e
<kompi>
вижу
<mikekaganski>
Она должна взять две вещи: документ и выделение, и вернуть список объектов
<mikekaganski>
сейчас её и начнём
<mikekaganski>
Она тоже будет делать всё не сама, а с помощью других функций
<mikekaganski>
потому что документы бывают разные: Writer, Draw, Calc
<kompi>
я вот думаю, Импресс надо ли?
<mikekaganski>
Так что задачей GetObjectsFromDoc будет просто определить, что это за документ, и в зависимости от этого вызвать специализированную функцию
<mikekaganski>
а Draw и Impress одинаковы
<kompi>
месторасположение процедур относительно друг друга в листинге имеет значение?
<mikekaganski>
нет
<kompi>
ок
<mikekaganski>
Итак: Function GetObjectsFromDoc(ByRef oDoc, ByRef oSel) ... End Function
<mikekaganski>
Начнём с самого минимума: пусть она для начала возвращает пустой массив (пока что она ещё не умеет работать НИ С КАКИМ документом)
<mikekaganski>
Для этоо вначале создадим переменную - пустой массив, и вернём её, вот так:
<mikekaganski>
Dim vObjects() As Object
<mikekaganski>
GetObjectsFromDoc = vObjects
<kompi>
ок
<mikekaganski>
Создали пустой массив, вернули его. Всё. После этого всё должно работать, но ничего не форматировать (по крайней мере, если я ничего не забыл тебе сказать)
<mikekaganski>
давай проверим на этом этапе
<kompi>
если имя переменной при объявлении имеет скобки, это массив?
<mikekaganski>
да
<kompi>
For i=LBound(vObjects) to UBound(vObjects) - переменаая не определена
<mikekaganski>
kompi: лучше скриншот (непонятно, где это)