com.hcl.domino.jna.data.JNADominoCollectionPosition Maven / Gradle / Ivy
/*
* ==========================================================================
* Copyright (C) 2019-2022 HCL America, Inc. ( http://www.hcl.com/ )
* All rights reserved.
* ==========================================================================
* Licensed under the Apache License, Version 2.0 (the "License"). You may
* not use this file except in compliance with the License. You may obtain a
* copy of the License at .
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
* ==========================================================================
*/
package com.hcl.domino.jna.data;
import java.text.MessageFormat;
import java.util.Arrays;
import com.hcl.domino.data.IAdaptable;
import com.hcl.domino.jna.internal.structs.NotesCollectionPositionStruct;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
/**
* This structure is used to specify the hierarchical, index position of an item (or category)
* within a View(collection).
*
* Level = (number of levels in tumbler - 1)
*
* Tumbler is an array of ordinal ranks within the view; with the first (0) entry referring to the top level.
*
* For example, consider the following non-Domino Outline Scheme :
*
* I. First Main Category
* A. First sub-category under I
* B. Second sub-category under I
* II. Second Main Category
* A. First sub-category under II
* 1. First item under II.A
* 2. Second item under II.A
* B. Second sub-category under II
* C. Third sub-category under II
* III. Third Main Category
*
* With this example, [2; II.A.2] refers to the "Second item under II.A."
* Similarly, [0; III] refers to the "Third Main Category."
*
* Finally, it should be noted that [2; I.B.1], [1; I.C], and [3; II.A.1] are all NOT valid positions.
*
* [2; I.B.1] because the "Second sub-category under I" has no items.
* [1; I.C] because there is no "Third sub-category under I", and
* [3; II.A.1] because the value of Level (3) shows four levels should be represented
* in the Tumbler and there are only three.
*
* @author Karsten Lehmann
*/
public class JNADominoCollectionPosition implements IAdaptable {
/** # levels -1 in tumbler */
private int level;
/**
* MINIMUM level that this position is allowed to be nagivated to. This is
* useful to navigate a subtree using all navigator codes. This field is
* IGNORED unless the NAVIGATE_MINLEVEL flag is enabled (for backward
* compatibility)
*/
private int minLevel;
/**
* MAXIMUM level that this position is allowed to be nagivated to. This is
* useful to navigate a subtree using all navigator codes. This field is
* IGNORED unless the NAVIGATE_MAXLEVEL flag is enabled (for backward
* compatibility)
*/
private int maxLevel;
/**
* Current tumbler (1.2.3, etc)
* C type : DWORD[32]
*/
private int[] tumbler = new int[32];
private String toString;
private NotesCollectionPositionStruct struct;
public JNADominoCollectionPosition(IAdaptable adaptable) {
NotesCollectionPositionStruct struct = adaptable.getAdapter(NotesCollectionPositionStruct.class);
if (struct!=null) {
this.struct = struct;
this.level = struct.Level;
this.minLevel = struct.MinLevel;
this.maxLevel = struct.MaxLevel;
this.tumbler = struct.Tumbler;
return;
}
Pointer p = adaptable.getAdapter(Pointer.class);
if (p!=null) {
this.struct = NotesCollectionPositionStruct.newInstance(p);
this.level = this.struct.Level;
this.minLevel = this.struct.MinLevel;
this.maxLevel = this.struct.MaxLevel;
this.tumbler = this.struct.Tumbler;
return;
}
throw new IllegalArgumentException("Constructor argument cannot provide a supported datatype");
}
/**
* Creates a new instance
*
* @param tumbler array with position information [index level0, index level1, ...], e.g. [1,2,3], up to 32 entries
*/
public JNADominoCollectionPosition(int[] tumbler) {
this(computeLevel(tumbler), 0, 0, tumbler);
}
private static int computeLevel(int[] tumbler) {
if (tumbler[0]==0) {
return 0;
}
for (int i=1; i32) {
throw new IllegalArgumentException(MessageFormat.format("Tumbler array exceeds the maximum size ({0} > 32)", tumbler.length));
}
this.tumbler = new int[32];
for (int i=0; i
*
* Please note that we also support an advanced syntax in contrast to IBM's API in order
* to specify the min/max level parameters: "1.2.3|0-2" for minlevel=0, maxlevel=2. These
* levels can be used to limit reading entries in a categorized view to specified depths.
*
* @param posStr position string
*/
public JNADominoCollectionPosition(String posStr) {
int iPos = posStr.indexOf("|"); //$NON-NLS-1$
if (iPos!=-1) {
//optional addition to the classic position string: |minlevel-maxlevel
String minMaxStr = posStr.substring(iPos+1);
posStr = posStr.substring(0, iPos);
iPos = minMaxStr.indexOf("-"); //$NON-NLS-1$
if (iPos!=-1) {
minLevel = Byte.parseByte(minMaxStr.substring(0, iPos));
maxLevel = Byte.parseByte(minMaxStr.substring(iPos+1));
}
}
tumbler = new int[32];
if (posStr==null || posStr.length()==0 || "0".equals(posStr)) { //$NON-NLS-1$
level = 0;
tumbler[0] = 0;
this.toString = "0"; //$NON-NLS-1$
}
else {
String[] parts = posStr.split("\\."); //$NON-NLS-1$
level = (short) (parts.length-1);
for (int i=0; i T getAdapter(Class clazz) {
if (clazz == NotesCollectionPositionStruct.class || clazz == Structure.class) {
if (this.struct==null) {
this.struct = NotesCollectionPositionStruct.newInstance();
this.struct.Level = (short) (this.level & 0xffff);
this.struct.MinLevel = (byte) (this.minLevel & 0xff);
this.struct.MaxLevel = (byte) (this.maxLevel & 0xff);
this.struct.Tumbler = this.tumbler.clone();
this.struct.write();
}
return (T) this.struct;
}
return null;
}
/**
* # levels -1 in tumbler
*
* @return levels
*/
public int getLevel() {
if (this.struct!=null) {
//get current struct value, is changed by NIFReadEntries
this.level = this.struct.Level & 0xffff;
}
return this.level;
}
/**
* MINIMUM level that this position is allowed to be nagivated to. This is
* useful to navigate a subtree using all navigator codes. This field is
* IGNORED unless the NAVIGATE_MINLEVEL flag is enabled (for backward
* compatibility)
*
* @return min level
*/
public int getMinLevel() {
if (this.struct!=null) {
//get current struct value, is changed by NIFReadEntries
this.minLevel = (this.struct.MinLevel & 0xffff);
}
return this.minLevel;
}
/**
* Sets the MINIMUM level that this position is allowed to be nagivated to. This is
* useful to navigate a subtree using all navigator codes. This field is
* IGNORED unless the NAVIGATE_MINLEVEL flag is enabled (for backward
* compatibility)
*
* @param level min level
*/
public void setMinLevel(int level) {
this.minLevel = level;
if (this.struct!=null) {
this.struct.MinLevel = (byte) (level & 0xff);
this.struct.write();
}
}
/**
* MAXIMUM level that this position is allowed to be navigated to. This is
* useful to navigate a subtree using all navigator codes.
*
* @return max level
*/
public int getMaxLevel() {
if (this.struct!=null) {
//get current struct value, is changed by NIFReadEntries
this.maxLevel = (this.struct.MaxLevel & 0xffff);
}
return this.maxLevel;
}
/**
* Sets the MAXIMUM level that this position is allowed to be navigated to. This is
* useful to navigate a subtree using all navigator codes.
*
* @param level max level
*/
public void setMaxLevel(int level) {
this.maxLevel = level;
if (this.struct!=null) {
this.struct.MaxLevel = (byte) (level & 0xff);
this.struct.write();
}
}
/**
* Returns the index position at each view level
*
* @param level 0 for first level
* @return position starting with 1 if not restricted by reader fields
*/
public int getTumbler(int level) {
if (this.struct!=null) {
//get current struct value, is changed by NIFReadEntries
this.tumbler = this.struct.Tumbler;
}
return this.tumbler[level];
}
/**
* Converts the position object to a position string like "1.2.3".
*
* Please note that we also support an advanced syntax in contrast to IBM's API in order
* to specify the min/max level parameters: "1.2.3|0-2" for minlevel=0, maxlevel=2. These
* levels can be used to limit reading entries in a categorized view to specified depths.
*
* This method will returns a string with the advanced syntax if MinLevel or MaxLevel is not 0.
*
* @return position string
*/
@Override
public String toString() {
boolean recalc;
//cache if cached value needs to be recalculated
if (this.toString==null) {
recalc = true;
}
else if (this.struct!=null && (this.level != this.struct.Level ||
this.minLevel != this.struct.MinLevel ||
this.maxLevel != this.struct.MaxLevel ||
!Arrays.equals(this.tumbler, this.struct.Tumbler))) {
recalc = true;
}
else {
recalc = false;
}
if (recalc) {
int level = this.getLevel();
int minLevel = this.getMinLevel();
int maxLevel = this.getMaxLevel();
StringBuilder sb = new StringBuilder();
for (int i=0; i<=level; i++) {
if (sb.length() > 0) {
sb.append('.');
}
sb.append(this.getTumbler(i));
}
if (minLevel!=0 || maxLevel!=0) {
sb.append("|").append(minLevel).append("-").append(maxLevel); //$NON-NLS-1$ //$NON-NLS-2$
}
toString = sb.toString();
}
return toString;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy