Skip to content

Commit

Permalink
Added utility methods to find subforms contained in a form
Browse files Browse the repository at this point in the history
  • Loading branch information
klehmann committed Jan 11, 2021
1 parent 569fc38 commit 80cc4d4
Show file tree
Hide file tree
Showing 2 changed files with 254 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -3879,6 +3879,59 @@ compatibility, outputs it to disk at Save() time
public short CDRESOURCE_CLASS_PORTFOLIO = 21;
public short CDRESOURCE_CLASS_OUTLINE = 22;

/** Obsolete - Use class _VIEW or _FOLDER and flag _SIMPLE */
public short CDRESOURCE_CLASS_SIMPLEVIEW = 23;
/** design link only */
public short CDRESOURCE_CLASS_SUBFORM = 24;
/** design link only */
public short CDRESOURCE_CLASS_SHARED_FLD = 25;
/** design link only */
public short CDRESOURCE_CLASS_SCRIPTLIB = 26;
/** design link only */
public short CDRESOURCE_CLASS_DBSCRIPT = 27;
/** design link only */
public short CDRESOURCE_CLASS_SHARED_ACTIONS = 28;
/** design link only */
public short CDRESOURCE_CLASS_WEBSERVICE = 29;
/** design link only */
public short CDRESOURCE_CLASS_DATA_CONNECTION = 30;
public short CDRESOURCE_CLASS_SHARED_APPLET = 31;
public short CDRESOURCE_CLASS_EMBEDDED_VIEW = 32;
public short CDRESOURCE_CLASS_STYLE_SHEET = 33;
/** a file with the html flag, too */
public short CDRESOURCE_CLASS_HTMLFILE = 34;
/** a file that's a JSP */
public short CDRESOURCE_CLASS_JSP = 35;
public short CDRESOURCE_CLASS_SHAREDCOL = 36;
public short CDRESOURCE_CLASS_DB2ACCESSVIEW = 37;
/** LI 3925.04 */
public short CDRESOURCE_CLASS_COMPAPP = 38;
/** LI 3925.05 */
public short CDRESOURCE_CLASS_COMPDEF = 39;
/** LI 3261.05 */
public short CDRESOURCE_CLASS_MAILSETTINGS = 40;
/** LI 3261.05 */
public short CDRESOURCE_CLASS_CSSETTINGS = 41;
/** LI 3261.05 */
public short CDRESOURCE_CLASS_FORM_PREMIUM = 42;
public short CDRESOURCE_MAX_CLASS = CDRESOURCE_CLASS_FORM_PREMIUM;
/** design link only */
public short CDRESOURCE_CLASS_XSPPAGES = 43;
/** design link only */
public short CDRESOURCE_CLASS_XSPCCS = 44;
/** design link only */
public short CDRESOURCE_CLASS_STYLEKITS = 45;
/** design link only */
public short CDRESOURCE_CLASS_WSCONSUMERS = 46;
/** design link only */
public short CDRESOURCE_CLASS_COMPONENT = 47;
/** design link only */
public short CDRESOURCE_CLASS_JAVAFILES = 48;
/** design link only */
public short CDRESOURCE_CLASS_JAVAJARS = 49;
/** design link only */
public short CDRESOURCE_CLASS_CUSTOMELTS = 50;

public short KFM_access_GetIDFHFlags = 51;

/** File is password protected */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@
import com.mindoo.domino.jna.NotesNote;
import com.mindoo.domino.jna.constants.CDRecordType;
import com.mindoo.domino.jna.internal.FieldPropAdaptable;
import com.mindoo.domino.jna.internal.FormulaDecompiler;
import com.mindoo.domino.jna.internal.NotesConstants;
import com.mindoo.domino.jna.internal.structs.NotesTimeDateStruct;
import com.mindoo.domino.jna.internal.structs.compoundtext.NotesCDResourceStruct;
import com.mindoo.domino.jna.internal.structs.compoundtext.NotesCdHotspotBeginStruct;
import com.mindoo.domino.jna.richtext.IRichTextNavigator.RichTextNavPosition;
import com.mindoo.domino.jna.utils.NotesStringUtils;
import com.mindoo.domino.jna.utils.Pair;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;

/**
* Collection of useful methods to process richtext CD records
Expand Down Expand Up @@ -186,7 +192,6 @@ public static LinkedHashSet<String> collectAttachmentNames(IRichTextNavigator rt
// } CDBEGINRECORD;
Memory beginDataBuf = rtNav.getCurrentRecordData();

int version = beginDataBuf.getShort(0);
int signature = beginDataBuf.share(2).getShort(0);

if (signature == NotesConstants.SIG_CD_V4HOTSPOTBEGIN) {
Expand Down Expand Up @@ -226,4 +231,199 @@ public static LinkedHashSet<String> collectAttachmentNames(IRichTextNavigator rt

return attNames;
}

/**
* Traverses the richtext CD records (of a design element's $body item)
* and collects all contained named subforms (those not computed via formula)
* with the replica id of their database. Restores the
* current {@link RichTextNavPosition} in the richtext item if not
* null.
*
* @param rtNav richtext navigator
* @return pairs of [replicaid, named subform], replicaid is "0000000000000000" for the local DB
*/
public static List<Pair<String,String>> collectNamedSubforms(IRichTextNavigator rtNav) {
List<Pair<String,String>> subforms = new ArrayList<>();

if (rtNav==null) {
return subforms;
}

RichTextNavPosition oldPos = rtNav.getCurrentRecordPosition();

if (rtNav.gotoFirst()) {
boolean inBeginEnd = false;

do {
if (CDRecordType.BEGIN.getConstant() == rtNav.getCurrentRecordTypeAsShort()) {
inBeginEnd = true;
}
else if (CDRecordType.END.getConstant() == rtNav.getCurrentRecordTypeAsShort()) {
inBeginEnd = false;
}
else if (CDRecordType.HREF2.getConstant() == rtNav.getCurrentRecordTypeAsShort()) {
if (inBeginEnd) {
//found record of type SIG_CD_HREF2
Memory href2RecordWithHeader = rtNav.getCurrentRecordDataWithHeader();

NotesCDResourceStruct cdResourceStruct = NotesCDResourceStruct.newInstance(href2RecordWithHeader);
cdResourceStruct.read();

//search for additional CD records V4HOTSPOTBEGIN / V4HOTSPOTEND

RichTextNavPosition fieldPos = rtNav.getCurrentRecordPosition();

boolean hotspotBeginFound = false;
boolean hotspotEndFound = false;

if (rtNav.gotoNext()) {
do {
// check if we have reached the end of the field block
if (CDRecordType.V4HOTSPOTBEGIN.getConstant() == rtNav.getCurrentRecordTypeAsShort()) {
Memory v4HotspotbeginRecordWithHeader = rtNav.getCurrentRecordDataWithHeader();

NotesCdHotspotBeginStruct v4HotspotBegin = NotesCdHotspotBeginStruct.newInstance(v4HotspotbeginRecordWithHeader);
v4HotspotBegin.read();

if (v4HotspotBegin.Type == NotesConstants.HOTSPOTREC_TYPE_SUBFORM) {
hotspotBeginFound = true;
}
}
else if (CDRecordType.V4HOTSPOTEND.getConstant() == rtNav.getCurrentRecordTypeAsShort()) {
hotspotEndFound = true;
}
}
while (rtNav.gotoNext());
}

rtNav.restoreCurrentRecordPosition(fieldPos);

if (hotspotBeginFound && hotspotEndFound) {
// typedef struct {
// WSIG Header;
// DWORD Flags; /* one of CDRESOURCE_FLAGS_xxx */
// WORD Type; /* one of CDRESOURCE_TYPE_xxx */
// WORD ResourceClass; /* one of CDRESOURCE_CLASS_xxx */
// WORD Length1; /* meaning depends on Type */
// WORD ServerHintLength; /* length of the server hint */
// WORD FileHintLength; /* length of the file hint */
// BYTE Reserved[8];
/* Variable length follows:
* String of size ServerHintLength: hint as to resource's server
* String of size FileHintLength: hint as to resource's file
* - if CDRESOURCE_TYPE_URL :
* string of size Length1 - the URL.
* - if CDRESOURCE_TYPE_NOTELINK:
* if CDRESOURCE_FLAGS_NOTELINKINLINE is NOT set in Flags:
* WORD LinkID - index into $Links
* string of size Length1 - the anchor name (optional)
* if CDRESOURCE_FLAGS_NOTELINKINLINE is set in Flags:
* NOTELINK NoteLink
* string of size Length1 - the anchor name (optional)
* - if CDRESOURCE_TYPE_NAMEDELEMENT :
* TIMEDATE ReplicaID (zero if current db)
* string of size Length1 - the name of element
*/
// } CDRESOURCE;

if (cdResourceStruct.Type == NotesConstants.CDRESOURCE_TYPE_NAMEDELEMENT) {
if (cdResourceStruct.ResourceClass == NotesConstants.CDRESOURCE_CLASS_SUBFORM) {
NotesTimeDateStruct replicaId = NotesTimeDateStruct.newInstance(
href2RecordWithHeader
.share(cdResourceStruct.size()));
replicaId.read();
String replicaIdStr = NotesStringUtils.innardsToReplicaId(replicaId.Innards);

String subformName = NotesStringUtils.fromLMBCS(
href2RecordWithHeader
.share(cdResourceStruct.size() + NotesConstants.timeDateSize), // => TIMEDATE is replica id
cdResourceStruct.Length1);
subforms.add(new Pair<>(replicaIdStr, subformName));
}
}
}
}
}
}
while (rtNav.gotoNext());
}

if (oldPos!=null) {
rtNav.restoreCurrentRecordPosition(oldPos);
}

return subforms;
}

/**
* Traverses the richtext CD records (of a design element's $body item)
* and collects all formulas computing the name of a subform. Restores the
* current {@link RichTextNavPosition} in the richtext item if not
* null.
*
* @param rtNav richtext navigator
* @return subforms formulas
*/
public static List<String> collectSubformFormulas(IRichTextNavigator rtNav) {
List<String> subforms = new ArrayList<String>();

if (rtNav==null) {
return subforms;
}

RichTextNavPosition oldPos = rtNav.getCurrentRecordPosition();

if (rtNav.gotoFirst()) {
boolean inBeginEnd = false;

do {
if (CDRecordType.BEGIN.getConstant() == rtNav.getCurrentRecordTypeAsShort()) {
inBeginEnd = true;
}
else if (CDRecordType.END.getConstant() == rtNav.getCurrentRecordTypeAsShort()) {
inBeginEnd = false;
}
else if (CDRecordType.V4HOTSPOTBEGIN.getConstant() == rtNav.getCurrentRecordTypeAsShort()) {
if (inBeginEnd) {
// [V4HOTSPOTBEGIN]
// Record type: 65453 (V4HOTSPOTBEGIN)
// Total length: 76
// Header length: 4
// Data length: 72
//
// [ad ff 4c 00 0e 00 18 00] [..L.....]
// [00 00 40 00 40 00 00 00] [..@.@...]
// [32 00 05 00 01 00 78 00] [2.....x.]
// [01 00 00 00 0a 02 af 00] [........]
// [1e 00 12 00 01 00 08 00] [........]
// [53 75 62 66 6f 72 6d 32] [Subform2]
// [ae 00 0c 00 01 00 00 00] [........]
// [ae 00 04 00 b5 03 03 00] [........]
// [07 00 0c 00 05 00 09 30] [.......0]
// [53 30 45 00 ] [S0E. ]

Memory v4HotspotbeginRecordWithHeader = rtNav.getCurrentRecordDataWithHeader();

NotesCdHotspotBeginStruct v4HotspotBegin = NotesCdHotspotBeginStruct.newInstance(v4HotspotbeginRecordWithHeader);
v4HotspotBegin.read();

if (v4HotspotBegin.Type == NotesConstants.HOTSPOTREC_TYPE_SUBFORM) {
if ((v4HotspotBegin.Flags & NotesConstants.HOTSPOTREC_RUNFLAG_FORMULA) == NotesConstants.HOTSPOTREC_RUNFLAG_FORMULA) {
Pointer compiledFormulaPtr = v4HotspotbeginRecordWithHeader.share(12);
String formula = FormulaDecompiler.decompileFormula(compiledFormulaPtr);
subforms.add(formula);
}
}
}
}
}
while (rtNav.gotoNext());
}

if (oldPos!=null) {
rtNav.restoreCurrentRecordPosition(oldPos);
}

return subforms;
}
}

0 comments on commit 80cc4d4

Please sign in to comment.