Документация HotXLS

Разреженная геометрия структуры

Модуль lxOutline предоставляет нейтральные к движкам геометрию и планирование изменений для структур строк и столбцов
Он хранит только материализованные сегменты, распознаёт итоговые узлы по соседним переходам уровней структуры и создаёт сжатые изменения состояния для макетов с итогом после и итогом до, не выделяя запись для каждой координаты листа

Основные типы

TXLSOutlineAxis = (xoaRows, xoaColumns);

TXLSOutlineChildMode = (xocPreserve, xocCollapse, xocExpand);

TXLSOutlineMutationPlan = class
  constructor Create(AAxis: TXLSOutlineAxis);
  procedure Clear;
  property Axis: TXLSOutlineAxis;
  property Count: Integer;
  property Changes[Index: Integer]: TXLSOutlineStateChange;
end;

TXLSOutlineGeometry = class
  constructor Create(AAxis: TXLSOutlineAxis;
    ASummaryAfter: Boolean);
  procedure Clear;
  property Axis: TXLSOutlineAxis;
  property SpanCount: Integer;
  procedure AddSpan(AFirstIndex, ALastIndex, ALevel: Integer;
    AHidden, ACollapsed: Boolean);
  function TryGetNode(ANodeIndex: Integer;
    out ANode: TXLSOutlineNode): Boolean;
  function TryBuildNodeCollapsePlan(ANodeIndex: Integer;
    ACollapsed: Boolean; AChildMode: TXLSOutlineChildMode;
    APlan: TXLSOutlineMutationPlan): Boolean;
  procedure BuildDisplayLevelPlan(ADisplayLevel: Integer;
    AChildMode: TXLSOutlineChildMode;
    APlan: TXLSOutlineMutationPlan);
end;
Индексы строк и столбцов имеют нумерацию от единицы, уровни структуры неотрицательны, а сегменты должны добавляться в строго возрастающем порядке без перекрытия
Соседние сегменты с одинаковыми уровнем, состоянием скрытия и свёрнутости объединяются автоматически; пропущенные индексы имеют неявный нулевой уровень, видимое состояние и не имеют маркера свёртывания
Оба класса помнят свой Axis с момента конструирования, Clear опустошает план или геометрию для повторного использования без перераспределения внутренних буферов, а SpanCount сообщает, сколько объединённых сегментов геометрия удерживает в данный момент

Семантика узлов

NodeIndexФизическая итоговая строка или столбец, запрошенные вызывающим кодом
FirstDetailIndex / LastDetailIndexНепрерывный диапазон детализации, чей уровень глубже итогового элемента
SummaryLevelУровень структуры, сохранённый на итоговом элементе, или ноль, когда этот элемент не материализован
LevelУровень группы, представляемый узлом, равный SummaryLevel + 1
SummaryHiddenСостояние скрытия, сохранённое на итоговом элементе
CollapsedЯвный маркер свёртывания, сохранённый на итоговом элементе
SummaryAfterTrue, когда детали предшествуют итоговому элементу, false, когда детали следуют за ним
Вложенные группы остаются независимыми, поскольку каждый запрос останавливается на первом соседнем сегменте, чей уровень не глубже выбранного итогового элемента
Разрыв также завершает диапазон детализации, поэтому разреженные метаданные не могут случайно объединить неиспользуемые координаты в одну группу

Планы изменений

План изменений содержит упорядоченные диапазоны с нумерацией от единицы и маску полей, указывающую, изменяет ли каждый диапазон состояние скрытия, состояние свёрнутости или и то и другое; соседние эквивалентные изменения объединяются автоматически
xocPreserveИзменяет выбранный узел, удерживая маркеры свёртывания потомков, — это поведение по умолчанию для вложенных групп
xocCollapseПомечает узлы потомков свёрнутыми, когда они находятся внутри выбранного узла или скрыты ниже запрошенного отображаемого уровня
xocExpandСнимает маркеры свёртывания потомков, когда они находятся внутри выбранного узла или скрыты ниже запрошенного отображаемого уровня
Развёртывание родителя с xocPreserve открывает непосредственные детали, тогда как детали, принадлежащие свёрнутым потомкам, остаются скрытыми; развёртывание потомка внутри свёрнутого предка не раскрывает содержимое через этого предка
Отображаемые уровни имеют нумерацию от единицы: уровень 1 сворачивает каждую группу верхнего уровня, а каждое большее значение открывает один дополнительный уровень структуры, устанавливая соответствующие маркеры граничных узлов
Построение того же запрошенного состояния из геометрии, которая его уже содержит, даёт пустой план, а запрос несуществующего узла возвращает false с пустым планом
Операции над узлами оставляют независимое состояние скрытия выбранного итогового элемента неизменным, а планы отображаемых уровней не делают снова видимыми элементы нулевого уровня, скрытые вне группы структуры

Адаптеры листов

function TryGetOutlineNode(AAxis: TXLSOutlineAxis;
  ANodeIndex: Integer; out ANode: TXLSOutlineNode): Boolean;
function SetOutlineNodeCollapsed(AAxis: TXLSOutlineAxis;
  ANodeIndex: Integer; ACollapsed: Boolean;
  AChildMode: TXLSOutlineChildMode = xocPreserve): Boolean;
procedure SetOutlineDisplayLevel(AAxis: TXLSOutlineAxis;
  ADisplayLevel: Integer;
  AChildMode: TXLSOutlineChildMode = xocPreserve);
TXLSWorksheet и TXLSXWorksheet открывают одни и те же три метода, поэтому вызывающий код может запрашивать или изменять итоговый узел строки или столбца с нумерацией от единицы без ручного построения геометрии
Классический адаптер читает только выделенные блоки строк и назначенные метаданные столбцов, а адаптер XLSX объединяет свои разреженные списки уровней структуры, скрытия и свёрнутости перед применением одного сжатого плана изменений в одной транзакции записи
Группы строк и столбцов OpenDocument удерживают своё исходное вложенное состояние table:display; прямые изменения метаданных и структурные изменения строк или столбцов безопасно проецируют это состояние на логический итоговый узел, а преобразование в XLSX записывает маркер свёртывания на итоговом элементе XLSX, а не на каждом члене группы
Существующие методы TXLSXWorksheet.ToggleRowGrouped и ToggleColGrouped остаются доступны как оболочки совместимости; их аргумент — первая строка или столбец детализации, а оболочка разрешает учитывающий направление итоговый узел перед переключением

Пример для Delphi

Geometry := TXLSOutlineGeometry.Create(xoaRows, True);
Plan := TXLSOutlineMutationPlan.Create(xoaRows);
try
  Geometry.AddSpan(2, 4, 1, False, False);
  Geometry.AddSpan(5, 5, 0, False, False);

  if Geometry.TryGetNode(5, Node) then
    UseOutlineNode(Node.FirstDetailIndex,
      Node.LastDetailIndex, Node.Collapsed);

  if Geometry.TryBuildNodeCollapsePlan(5, True,
    xocPreserve, Plan) then
    ApplyOutlineChanges(Plan);
finally
  Plan.Free;
  Geometry.Free;
end;

Пример для C++Builder

Lxoutline::TXLSOutlineGeometry *geometry =
  new Lxoutline::TXLSOutlineGeometry(Lxoutline::xoaColumns, false);
try {
  geometry->AddSpan(3, 3, 0, false, true);
  geometry->AddSpan(4, 7, 1, true, false);

  Lxoutline::TXLSOutlineNode node;
  if (geometry->TryGetNode(3, node))
    UseOutlineNode(node.FirstDetailIndex, node.LastDetailIndex,
      node.Collapsed);
}
__finally {
  delete geometry;
}

Производительность и область применения

Поиск узла использует двоичный поиск, за которым следуют только соседние материализованные сегменты, пересекаемые выбранной группой, что даёт работу O(log n + k) для n сегментов и k посещённых сегментов
Массовое планирование изменений находит каждый материализованный узел линейным проходом с монотонным стеком, объединяет интервалы видимости свёрнутых состояний и создаёт сжатые изменения диапазонов, не посещая неиспользуемые координаты
Построитель принимает последнюю строку листа XLSX, удерживая только переданные сегменты, поэтому высокая координата не подразумевает выделение или сканирование на миллион записей
Регрессионный контроль адаптера листов выполняет те же 32,768 запросов узлов и 2,048 изменений свёртывания или развёртывания по шести материализованным записям строк около строки 8 и строки 1,048,576, требует нулевой материализации ячеек и ограничивает стоимость высоких координат относительно базовой линии низких координат
TXLSOutlineGeometry никогда не записывает данные книги напрямую; адаптеры движков проверяют и применяют возвращённый план, позволяя анализу геометрии и изменению состояния оставаться раздельными

См. также

Дополнительные члены классического XLS API
Расширенные члены API XLSX
Дополнительные члены API библиотеки