О пользовательских списках сортировки

Автор eeigor, 18 июня 2021, 09:59

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

eeigor

В Excel, к примеру, 5 встроенных списков сортировки удалить нельзя, а дальше, свои, можно.
В LO Calc не пробовал удалять. Можно, конечно сохранить, потом восстановить...
Есть ли здесь подобное ограничение?
Вопрос, так сказать, «на ходу», когда нет ноутбука под рукой...
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

sokol92

В LO интерактивно (параметры LibreOffice Calc / Списки сортировки) можно внести любые изменения в списки сортировки.
Несложно это сделать и макросом:

Sub TestSortList
 Dim v, list, n As Long
 GlobalScope.BasicLibraries.LoadLibrary("Tools")
 v= GetRegistryKeyContent("org.openoffice.Office.Calc/SortList", True)
 list=v.list
 n=Ubound(list)
 ReDim Preserve list(n+1)
 list(n+1)="1,2,3,4"
 v.list=list
 v.commitChanges
End Sub


Однако, изменения, внесенные макросом, интерактивная часть "не видит" до перезагрузки LO. Мы аналогичную ситуацию обсуждали в этой теме, по итогам которой Михаил Каганский написал tdf#132145.
Владимир.

eeigor

@sokol92, есть такая проблема с обновлением...
Однако с данным параметром, и рядом других, проблемы нет, поскольку он доступен через "com.sun.star.sheet.GlobalSheetSettings". "ExpandReferences", кстати, тоже. Иначе было бы тоскливо... :)
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

sokol92

#3
Цитата: eeigor от 18 июня 2021, 16:23с данным параметром, и рядом других, проблемы нет

Эксперимент показывает, что проблема есть.
Соединяем два ранее опубликованных макроса:

Sub TestSortList2
 Dim v, list, n As Long
 GlobalScope.BasicLibraries.LoadLibrary("Tools")
 v= GetRegistryKeyContent("org.openoffice.Office.Calc/SortList", True)
 list=v.list
 n=Ubound(list)
 ReDim Preserve list(n+1)
 list(n+1)="F2,F1"
 v.list=list
 v.commitChanges
 
 Dim oDoc, oRange
 Dim oSortFields(0) as new com.sun.star.table.TableSortField
 Dim oSortDesc(3)   as new com.sun.star.beans.PropertyValue
 
 oDoc=StarDesktop.loadComponentFromURL("private:factory/scalc", "_blank", 0, Array())   ' новая книга Calc
 oRange=oDoc.Sheets(0).getCellRangeByName("A1:A2")   ' диапазон для сортировки
 oRange.setDataArray Array(Array("F1"), Array("F2")) ' присвоили значения: F1, F2
 
 oSortFields(0).Field = 0                 ' столбец A              
 oSortFields(0).IsAscending = True        ' по возрастанию
 oSortDesc(0).Name = "SortFields"        
 oSortDesc(0).Value = oSortFields()       ' поля сортировки
 oSortDesc(1).Name = "ContainsHeader"
 oSortDesc(1).Value = False               ' нет заголовка столбцов
 oSortDesc(2).Name = "IsUserListEnabled"
 oSortDesc(2).Value = True                ' сортировка по встроенному пользовательскому списку
 oSortDesc(3).Name = "UserListIndex"
 oSortDesc(3).Value = n+1                 ' номер нового пользовательского списка (F2,F1)

 oRange.Sort oSortDesc                    ' сортируем
End Sub



После сортировки в ячейках A1:A2 содержатся строки "F1", "F2", а согласно новому пользовательскому списку должно быть наоборот.

После экспериментов нужно вновь открыть LO и удалить "экспериментальные" списки сортировки.  ;)
Владимир.

eeigor

#4
Владимир, вы меня "не слышите".

Проблема начинается отсюда:
v = GetRegistryKeyContent("org.openoffice.Office.Calc/SortList", True)
И этот метод не работает:
v.commitChanges
И хотя реестр перезаписывается, повторное считывание обновленного параметра не происходит. Нужен рестарт.

Проблемы не будет, если работать с другим объектом (GlobalSheetSettings), минуя реестр. Реестр будет обновлён без нашей помощи немедленно.

Dim aUserLists$(), ListArray, sList$, nEnd%

ListArray = Array("пункт1", "пункт2", "пункт2")
sList = Join(ListArray, ",")

Dim aUserLists$()
oSettings = createUnoService("com.sun.star.sheet.GlobalSheetSettings")
aUserLists$ = oSettings.getPropertyValue("UserLists")

nEnd = UBound(aUserLists) + 1
ReDim Preserve aUserLists(nEnd)
aUserLists(nEnd) = sList
oSettings.setPropertyValue("UserLists", aUserLists)

Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

sokol92

Да, при корректировке пользовательских списков через GlobalSheetSettings метод Sort "видит" изменения сразу же.
Владимир.

eeigor

#6
К сожалению, не всё можно делать через этот объект. Однако, то, что мне в первую очередь было нужно - практически сразу - там есть:
свойство ExpandReferences.
Это свойство мы "тогда" и обсуждали с @mikekaganski, и был написан баг. Но решение пока только через GlobalSheetSettings.
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

eeigor

#7
@sokol92, если полей сортировки несколько, и первое, например, сортируем по пользовательскому списку, а другие стандартным образом (по возрастанию или по убыванию), то как это задать другие поля?

См. здесь
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

sokol92

 Я не знаю правила сортировки по пользовательским спискам в случае, если значение ячейки списку не принадлежит - надо исследовать (или спросить у Михаила  :) ).

В любом случае есть трюк - сортируем сначала по второму и остальным полям (без пользовательского списка), а затем по первому (со списком). Calc (как и Excel) при сортировке строк внутри каждой группы строк с одинаковым множеством ключей сортировки сохраняет первоначальный порядок строк. Этот же трюк помогает, когда число ключей сортировки больше максимально допускаемого методами UNO (для Calc - 3, по моему).
Владимир.

eeigor

#9
Да, это знаю.
Ссылки: тут и вот тут.

Метод диспетчера .uno:DataSort имеет аргументы:
ByRows
HasHeader
CaseSensitive
NaturalSort
IncludeAttribs
UserDefIndex

Col1
Ascending1
Col2
Ascending2
Col3
Ascending3

IncludeComments
IncludeImages

UserDefIndex соответствует свойству TableSortDescriptor UserListIndex.
Действительно, не ясно: с каким полем, в данном случае, будет связан пользовательский список сортировки.

Может, кто-то пояснит... Во всяком случае, пользовательский список связывается с некоторым полем каким-то "эмпирическим" путём, ибо явного указания мы не делаем. Искусственный интеллект?  :)  Возможно, это всегда первое поле, а может нет. Кто знает... Не доделали.

На базе примера отсюда.

UPD:
А как в Excel? Там всё прозрачно. Одно из трёх (скриншот 3).
В LO Calc выбор значения "По возрастанию" или "По убыванию" мне удалось скомбинировать с пользовательским списком.
Есть ли логика в сортировке с использованием пользовательского списка "задом наперёд"?
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

eeigor

#10
Цитата: sokol92 от 19 июня 2021, 20:23если значение ячейки списку не принадлежит - надо исследовать
Сначала согласно выбранному списку сортировки, а потом всё остальное в конец по алфавиту и, в зависимости от заданного порядка следования (см. мои наблюдения выше), по возрастанию или по убыванию.

UPD:
В руководстве присутствует неоднозначность:
«Custom sort order – select this option and then select the custom sort order that you want to apply. The available selections are defined as "fill series" in Tools > Options > LibreOffice Calc > Sort Lists. See "Defining a fill series" on page 56».

К чему это? Ведь полей сортировки для последовательного выбора – три. Поставил поле с пользовательской сортировкой на второе место – тоже отсортировало.
Такая же неоднозначность присутствует и в методах программирования.
В ссылках выше «проблему» решают последовательной сортировкой по одному столбцу в направлении справа налево в цикле. Один сортируемый столбец со своим набором параметров за один проход.
Но в Excel у диапазона есть объект Sort, а в коллекцию SortFields методом Add можно добавить столбцы по одному и вызвать метод Apply для применения сложной сортировки.
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

sokol92

Тесты у нас заготовлены.

Выводы:
1. Пользовательский список (если установлен) применяется к каждому ключу сортировки.
2. Сначала сортируются значения из пользовательского списка, а затем остальные значения (как и написано в #9).

Интерактивная часть Calc позволяет сортировать по количеству полей, большему 3.
При сортировке макросом при числе полей большем трех, целесоообразно это сделать за несколько шагов, сортируя в каждом шаге по 3 поля (в последнем шаге может быть меньше). Например, для 8 полей на первом шаге сортируем по полям 6,7,8, на втором 3,4,5; на третьем по полям 1,2.

Sub TestSortList3
  Dim v, list, n As Long, oSettings

  oSettings = createUnoService("com.sun.star.sheet.GlobalSheetSettings")
  list=oSettings.getPropertyValue("UserLists")
  n=Ubound(list)
  ReDim Preserve list(n+1)
  list(n+1)="F2,F1"   ' список сортировки F2, F1
  oSettings.setPropertyValue "UserLists", list

  Dim oDoc, oRange
  Dim oSortFields(1) as new com.sun.star.table.TableSortField
  Dim oSortDesc(3)   as new com.sun.star.beans.PropertyValue
 
  oDoc=StarDesktop.loadComponentFromURL("private:factory/scalc", "_blank", 0, Array())   ' новая книга Calc
  oRange=oDoc.Sheets(0).getCellRangeByName("A1:B4")   ' диапазон для сортировки
 
  ' Заносим в столбцы A и B F02,F01,F1,F2
  oRange.setDataArray Array(Array("F02", "F02"), Array("F01", "F01"), Array("F1", "F1"), Array("F2", "F2"))
 
  oSortFields(0).Field = 0                 ' столбец A             
  oSortFields(0).IsAscending = True        ' по возрастанию
  oSortFields(1).Field = 1                 ' столбец B             
  oSortFields(1).IsAscending = True        ' по возрастанию
  oSortDesc(0).Name = "SortFields"         
  oSortDesc(0).Value = oSortFields()       ' поля сортировки
  oSortDesc(1).Name = "ContainsHeader"
  oSortDesc(1).Value = False               ' нет заголовка столбцов
  oSortDesc(2).Name = "IsUserListEnabled"
  oSortDesc(2).Value = True                ' сортировка по встроенному пользовательскому списку
  oSortDesc(3).Name = "UserListIndex"
  oSortDesc(3).Value = n+1                 ' номер нового пользовательского списка (F2,F1)
  oRange.Sort oSortDesc                    ' сортируем
End Sub
Владимир.

eeigor

Да, к каждому ключу.
Добавил одно из значений из пользовательского списка во второй столбец с иной информацией, и запись с новым значением поднялась вверх.
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

eeigor

#13
Ну вот и случилось: на win-компьютере вдруг отключился весь MS Office из-за проблемы с лицензией (работал несколько лет). Хорошо, что есть LO. :)

Цитата: eeigor от 18 июня 2021, 09:59В Excel, к примеру, 5 встроенных списков сортировки удалить нельзя, а дальше, свои, можно.
Ответ по теме: в LO Calc, в отличие от Excel, можно удалить все списки сортировки, нет понятия "встроенных" списков.

Остался один вопрос, который не могу протестировать (не на чём):
https://docs.microsoft.com/en-us/office/vba/api/excel.application.addcustomlist
По ссылке выше
expression.AddCustomList (ListArray, ByRow)
аргумент ByRow управляет загрузкой одного списка из нескольких строк/столбцов с проходом соответственно слева направо и сверху вниз или сверху вниз и слева направо или же речь идёт об одновременном импорте нескольких списков в зависимости от количества строк/столбцов входного диапазона за один приём? Из описания неясно. Хотя имя метода свидетельствует о добавлении списка (не списков).

У кого есть под рукой Excel + VBA (минимум кода), подскажите...
Application.AddCustomList Range("A1:B2"), ByRow:=False  'Аргумент ByRow можно опустить. ListArray зд. диапазон (!)
где в указанный диапазон введите что-нибудь: <а, б, в, г>, например, а лист сделайте активным. И сколько списков будет загружено: один или два?


Штатный метод LO Calc Copy list from / Copy загружает несколько списков сразу.
Нужно мне для завершения восстановления отсутствующей функциональности (динамическая сортировка, более 3-х столбцов и т.д. и т.п.) в LO Calc.

Она вся (отсутствующая) здесь, в примере ниже (методы Excel Application).
Sub SortRange()
   Dim nIndex&
   Application.AddCustomList ListArray:=Worksheets("1").[U4:U9]
   nIndex = Application.GetCustomListNum(Worksheets("1").Range("U4:U9").Value)
   Range("B5:K400").Sort Key1:=Range("B5"), Order1:=xlAscending _
    , Key2:=Range("C5"), Order2:=xlAscending, Header:=xlNo _
    , Orientation:=xlSortColumns, OrderCustom:=nIndex + 1  'custom list array is one based
   Application.DeleteCustomList nIndex
End Sub

+ GetCustomListContents, CustomListCount
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

sokol92

#14
В Excel метод AddCustomList добавляет списки из массива строк (один список) или прямоугольного диапазона ячеек (один или несколько списков).
При добавлении списков (списка) из диапазона ячеек параметром ByRow нужно указать, как расположены списки: по строкам или столбцам. Если параметр ByRow не указан, то в документации формулируется алгоритм, как Excel будет "угадывать" расположение списков (по строкам или столбцам). Разумеется, всегда лучше явно указать параметр.

Пример обращения к методам излишне запутан. Номер, который будет присвоен добавляемому списку можно определить заранее с помощью метода Application.CustomListCount.
Владимир.