Extract comments of specific annotation of a PDF using iText - annotations

using iText I am able to get a list of annotations of a PDF. It seems that even replies are annotations themselves.
Extracting them, I look at the contents of the PdfDictionary using this
Set<PdfName> keys = annot.getKeys();
for (PdfName key : keys) {
System.out.println(key + "," + dictionary.get(key));
}
However, I cannot pinpoint which PdfName I need to use in order to identify replies belong to that certain annotation.

Please take a look at the official documentation, more specifically at the answer to the example How to add an "In Reply To" annotation?
In this answer, I explain how to add an "In reply to" to an existing annotation. Let's open the resulting PDF and let's take a look inside:
As you can see, the annotation with the content "Hello PDF" is stored in an object with number 1. It is an annotation in reply to (IRT) the annotation with object number 2.
In answer to your question: you need to look at the key with value PdfName.IRT and this will give you the object number of the annotation to which the current number is a reply.

Related

Word VSTO - Why paraId is sometimes missing

I'm retrieving paragraph stylenames from openXML and using paraID property to get the right one.
During testing i noticed that depending on the word document the attribute might not be present on any of the paragraphs.
I do know that this is a internal runtime paragraph id for Word.
So the question is: What generates the paraId properties on the paragraphs, can't seem to figure this out.
ps. I don't want to use get_style() since that is waay too slooooow...
edit: added code example
This is in some documents "0" and in some documents a valid hex id
string sParaId = range.Paragraphs.First.ParaID.ToString("x").ToUpper();
This open xml document sometimes have valid w14:paraId-attribute and sometimes it is missing:
activeDocument = Globals.ThisAddIn.Application.ActiveDocument;
wordXML = XElement.Parse(activeDocument.WordOpenXML);
... I would like to get the styleName something like this from the WordOpenXML but for now it seems i might go for some other option since I don't know when paraId is added in the XML.
paraEl = ooXMLElementList.Descendants().Where(x => x.Name.LocalName ==
"p").FirstOrDefault(x => x.Attribute(w14 + "paraId")?.Value == sParaId);
styleName = paraEl.Descendants().FirstOrDefault(x => x.Name.LocalName ==
"pStyle") != null ? paraEl.Descendants().FirstOrDefault(x =>
x.Name.LocalName == "pStyle").Attribute(w + "val").Value : "Normal";
From the Word Language Reference for Paragraph.ID:
Returns or sets the identifying label for the specified object when
the current document is saved as a Web page.
Since the document is not saved as HTML the property has no meaning.
The ParaId property is not exposed for developers to use. It's not visible in the VBA object model, but due to the way the PIA (primary interop assemblies) are generated the .NET developer will see it. From the language reference:
Reserved for internal use.
Not sure what it is you're really trying to do, but you can use Word's Range.Find capability to search formatting (styles).

Word 2010 can Field added via QuickParts be given an ID and later referenced in document.Fields collection

I need to add a few fields to a Word 2010 DOTX template which are to be populated automatically with custom content at "run time" when the document is opened in a C# program using Word Interop services. I don't see any way to assign a unique name to "Ask" or "Fill-In" fields when adding them to the template via the QuickParts ribbon-menu option.
When I iterate the document.Fields collection in the C# program, I must know which field I'm referencing, so it can be assigned the correct value.
It seems things have changed between previous versions of Word and Word 2010. So, if you answer please make sure your answer applies to 2010. Don't assume that what used to work in previous versions works in 2010. Much appreciated, since I rarely work with Word and feel like a dolt when trying to figure out the ribbon menuing in 2010.
You are correct in that fields don't necessarily have a built-in way to uniquely distinguish themselves from other field instances (other than its index in the Fields collection). However, you can use the Field.Type property to test for wdFieldAsk or wdFieldFillIn . If this is not narrow enough to ID then you will need to parse your own unique identifier from the Field.Code. For example, you can construct your FILLIN field as:
{ FILLIN "Hello, World!" MYIDENTIFER }
when you iterate through your document.Fields collection just have a test for the identifier being in the string. EDIT: example:
For Each fld In ActiveDocument.Fields
If InStr("CARMODEL", fld.Code) <> 0 Then
''this is the carmodel field
End If
Next
Another alternative - seek your specific field with a Find.Text for "^d MYIDENTIFIER" (where ^d is expression for 'field code')
Let me know if this helps and expand on your question if any gaps.

Get statuscode text in C#

I'm using a plugin and want to perform an action based on the records statuscode value. I've seen online that you can use entity.FormattedValues["statuscode"] to get values from option sets but when try it I get an error saying "The given key was not present in the dictionary".
I know this can happen when the plugin cant find the change for the field you're looking for, but i've already checked that this does exist using entity.Contains("statuscode") and it passes by that fine but still hits this error.
Can anyone help me figure out why its failing?
Thanks
I've not seen the entity.FormattedValues before.
I usually use the entity.Attributes, e.g. entity.Attributes["statuscode"].
MSDN
Edit
Crm wraps many of the values in objects which hold additional information, in this case statuscode uses the OptionSetValue, so to get the value you need to:
((OptionSetValue)entity.Attributes["statuscode"]).Value
This will return a number, as this is the underlying value in Crm.
If you open up the customisation options in Crm, you will usually (some system fields are locked down) be able to see the label and value for each option.
If you need the label, you could either do some hardcoding based on the information in Crm.
Or you could retrieve it from the metadata services as described here.
To avoid your error, you need to check the collection you wish to use (rather than the Attributes collection):
if (entity.FormattedValues.Contains("statuscode")){
var myStatusCode = entity.FormattedValues["statuscode"];
}
However although the SDK fails to confirm this, I suspect that FormattedValues are only ever present for numeric or currency attributes. (Part-speculation on my part though).
entity.FormattedValues work only for string display value.
For example you have an optionset with display names as 1, 2, 3,
The above statement do not recognize these values because those are integers. If You have seen the exact defintion of formatted values in the below link
http://msdn.microsoft.com/en-in/library/microsoft.xrm.sdk.formattedvaluecollection.aspx
you will find this statement is valid for only string display values. If you try to use this statement with Integer values it will throw key not found in dictionary exception.
So try to avoid this statement for retrieving integer display name optionset in your code.
Try this
string Title = (bool)entity.Attributes.Contains("title") ? entity.FormattedValues["title"].ToString() : "";
When you are talking about Option set, you have value and label. What this will give you is the label. '?' will make sure that the null value is never passed.

Using changestamp in GoogleDocs (null changestamp)

I am trying to find the max changestamp so I can start using it. I tried the following:
URL url = "https://docs.google.com/feeds/default/private/changes?v=3"
ChangelogFeed foo = service.getFeed(url, ChangelogFeed.class);
LargestChangestamp stamp = foo.getLargestChangestamp();
stamp is always null.
Is this the way to get the largest changestamp, or do I need to set it first in order to use it?
The largest changestamp is also available in the user metadata feed. See the "docs:largestChangestamp" element within the response protocol tab here,
I'm not sure the java api exposes the largestChangestamp property directly yet - last time I checked it was hidden in the xmlBlob property, and I had to do an xml parse to grab it out.
This seems to be a bug in the API. I got the changestamps by getting the ChangelogEntrys from the ChangelogFeed:
List<ChangelogEntry> entries = foo.getEntries();
for (ChangelogEntry entry: entries) {
String blob = entry.getXmlBlob().getBlob();
System.out.println("Blob: " + blob);
}
The changestamp for an entry is contained in its blob.

How do I write a comment to a PropertiesConfiguration file?

Given one of these instances: org.apache.commons.configuration.PropertiesConfiguration I want to write a comment. How?
pc = new PropertiesConfiguration();
writeComment("this is a comment about the stuff below"); // HOW DO I WRITE THIS?
pc.addProperty("label0", myString);
writeComment("end of the stuff that needed a comment.");
Edit: I have a crude solution. Hopefully it can be improved upon.
Here's the best I could do. It leaves an extraneous line in the file.
pc = new PropertiesConfiguration();
writeComment(pc, "The following needed a comment so this is a comment.");
pc.addProperty(label0, stuff0);
writeComment(pc, "End of the stuff that needed a comment.");
...
private void writeComment(PropertiesConfiguration pc, String s)
{
String propertyName = String.format("%s%d", "comment", this.commentNumber++);
pc.getLayout().setComment(propertyName, s + " (" + propertyName + ")");
// make a dummy property
pc.addProperty(propertyName, ".");
// put in a dummy right-hand-side value so the = sign is not lonely
}
One of the problems with this approach is that the PropertiesConfiguration doc is a little vague about the layout. It does not explicitly say that the comment will appear above the dummy line so there seems to be the risk that PropertiesConfiguration is free to re-arrange the file on subsequent invocations. I have not even seen an guarantee that property line order is preserved so I cannot guarantee that the comment (and dummy line) will always be above the property that the comment applies to: property label0. Of course, I'm being a little paranoid here. However, the doc does say that layouts are not guaranteed to remain unmodified. Hopefully somebody can come up with something without the dummy line and a Java doc or website guarantee on the position of the comment relative to the property it is meant to comment on. Edit: You might wonder why I would create a dummy property instead of just attaching the comment to one of the properties that would already be in the file. The reason is because I want a comment to introduce a block of properties and changes (new ones, or a switch in the order) are possible. I don't want to create a maintenance problem. My comment should say "this is the section for data mining results" or "this is the section for the schedule" and I should never have to revisit this.
Comment like this?
# This is comment
The PropertiesConfiguration JavaDoc documents
Blank lines and lines starting with character '#' or '!' are skipped.
EDIT: Ok, you want to write the comment from code. Maybe - if you just need to write a property file - you can use the PropertiesConfiguration.PropertiesWriter and its writeComment method like this:
FileWriter writer = new FileWriter("test.properties");
PropertiesWriter propWriter = new PropertiesWriter(writer, ';');
propWriter.writeComment("Example properties");
propWriter.writeProperty("prop1","foo");
propWriter.writeProperty("prop2", "bar");
propWriter.close();
The property file will look like this:
# Example properties
prop1 = foo
prop2 = bar
Update
Summarized: The PropertiesConfiguration does not provide the functionality you are looking for.