How add to a picture to previously created word document with poi - apache-poi

In my project, I'm creating word document (.docx) with apache poi. When the document created, project sending it to approvers via e-mail. I want to add a approver's signature picture to specific place to previously created word document, when the approver is approved the document. But I couldn't figure it out how to do it on previously created word document.
Can I add a picture to previously created word document or do i have to rebuilt it?
UPDATE
I tried this code part
FileInputStream docxFile=new FileInputStream(System.getProperty("jboss.server.data.dir")+"/corrolog/TestWS/"+strSO+" Test Workscope "+revision+".docx");
FileInputStream approverFile=new FileInputStream(approvers);
XWPFDocument doc = new XWPFDocument(docxFile);
List<XWPFParagraph> xwpfParagraphList = doc.getParagraphs();
for (XWPFParagraph xwpfParagraph : xwpfParagraphList) {
for (XWPFRun xwpfRun : xwpfParagraph.getRuns()) {
String text = xwpfRun.getText(0);
System.out.println(text);
if (text == "approved signature" && text.equals("approved signature")) {
text.replace("approved signature", "");
xwpfRun.setText(text);
xwpfRun.addPicture(approverFile, XWPFDocument.PICTURE_TYPE_PNG, "approved", Units.toEMU(130), Units.toEMU(55));
}
}
}
FileOutputStream out = new FileOutputStream(System.getProperty("jboss.server.data.dir")+"/corrolog/TestWS/"+strSO+" Test Workscope "+revision+" Approved.docx");
doc.write(out);
out.close();
But it doesn't add picture to XWPFRun.
SOLUTION
String approvers=v2500Service.getApproverSignatures(approver).get(0).getImagePath();
FileInputStream approverFile=new FileInputStream(approvers);)
XWPFDocument doc = new XWPFDocument(Files.newInputStream(Paths.get(System.getProperty("jboss.server.data.dir")+"/corrolog/TestWS/EV13077-04 Test Workscope Rev0.docx")));
Iterator<IBodyElement> iter = doc.getBodyElementsIterator();
while (iter.hasNext()) {
IBodyElement elem = iter.next();
if (elem instanceof XWPFTable) {
for(XWPFTableRow rows:((XWPFTable) elem).getRows())
{
for(XWPFTableCell cell:rows.getTableCells())
{
text=cell.getText();
System.out.println(text);
if(text.equals("approved signature"))
{
text.replace("approved signature", "");
cell.getParagraphArray(0).removeRun(0);
cell.getParagraphArray(0).createRun();
cell.getParagraphArray(0).getRuns().get(0).addPicture(approverFile, XWPFDocument.PICTURE_TYPE_PNG, "approved", Units.toEMU(130), Units.toEMU(55));
}
}
}
System.out.println(((XWPFTable) elem).getRow(0).getCell(0).getText());
}
}
It was about XWPFParagraph, it has to be iterate XWPFTable.

Related

Printing Duplicate Records from the Data View In Acumatica

I am trying to print all records of a data-view into a file using a for loop in my customization in Acumatica. Unfortunately I am ending up with printing the first record everytime resulting into duplication of records, Unable to track where I am going wrong....Please Assist
Here Goes my Code......
public class MayBankGIROProcess : PXGraph<MayBankGIROProcess>
{
public PXSelect<MayBankGIRO> Document; //This is my Data View
public PXAction<MayBankGiroFilter> createTextFile;
[PXUIField(DisplayName = "Create Text File")]
[PXButton()]
public virtual IEnumerable CreateTextFile(PXAdapter adapter)
{
List<string> myList = new List<string> { };
foreach (MayBankGIRO dacRecord in this.Document.Select()) //this is the loop which is taking the data records.
{
myList.Add(dacRecord.ReordType+ "|"+ dacRecord.CustomerReferenceNumber+ "|"+ dacRecord.ClientBatchID+ "|");
// The above line is printing only the first record of the data view everytime .
}
string filename = "DAWN" + ".txt";
Download(myList, filename);
return adapter.Get();
}
public static void Download(List<string> lines, string name) //method generating file
{
var bytes = default(byte[]);
using (MemoryStream stream = new MemoryStream())
{
StreamWriter sw = new StreamWriter(stream);
foreach (string line in lines)
{
sw.WriteLine(line);
}
stream.Position = 0;
bytes = stream.ToArray();
sw.Close();
};
PX.SM.FileInfo textDoc = new PX.SM.FileInfo(name, null, bytes);
if (textDoc != null)
{
throw new PXRedirectToFileException(textDoc, true);
}
else
{
PXTrace.WriteInformation("Could not generate file");
}
}
}
[Generated Text File with all duplicate Record][1]
[1]: https://i.stack.imgur.com/Kllmk.png
[Original Record from database][2]
[2]: https://i.stack.imgur.com/Rbr9k.png
This usually happens when the report is pulling from a SQL View DAC which doesn't have unique key defined. Add IsKey=True on DAC fields until the SQL view is pulling unique record and the error should go away.

Outlook : Conflict while saving contact

I am working on a project involving contact synchronization between Outlook and SharePoint. Though there is an out of the box solution provided for this by Microsoft, but it does not cater some specific requirements like custom column synchronization.
For this requirement we had to create an outlook add-in. This add-in handles ItemAdd and ItemChange event for the contact folder created as a result of the synchronization.
In the ItemChange event I check a flag in the Notes field and identify whether the change has been made from SharePoint or Outlook and accordingly update the contact item.
Here is the code for my ItemChange event.
void Items_ItemChange(object Item)
{
try
{
ContactItem ctItem = Item as Outlook.ContactItem;
string customFieldsAndFlag = ctItem.Body;
Dictionary<string, string> customColumnValueMapping = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(customFieldsAndFlag))
{
string[] flagAndFields = customFieldsAndFlag.Split(';');
if (flagAndFields.Length == 2)
{
//SharePoint to Outlook
if (flagAndFields[0] == "1")
{
foreach (string customColumnAndValue in flagAndFields[1].Split('|'))
{
string[] KeyAndValue = customColumnAndValue.Split('=');
if (KeyAndValue.Length == 2)
{
if (ctItem.UserProperties[KeyAndValue[0]] == null)
{
ctItem.UserProperties.Add(KeyAndValue[0], OlUserPropertyType.olText, true, OlUserPropertyType.olText);
ctItem.UserProperties[KeyAndValue[0]].Value = KeyAndValue[1];
}
else
{
ctItem.UserProperties[KeyAndValue[0]].Value = KeyAndValue[1];
}
}
}
ctItem.Body = "2;" + flagAndFields[1];
}
//Outlook to SharePoint
else
{
foreach (string customColumnAndValue in flagAndFields[1].Split('|'))
{
string[] KeyAndValue = customColumnAndValue.Split('=');
if (KeyAndValue.Length == 2)
{
if (ctItem.UserProperties[KeyAndValue[0]] != null && ctItem.UserProperties[KeyAndValue[0]].Value != null)
{
KeyAndValue[1] = ctItem.UserProperties[KeyAndValue[0]].Value.ToString();
}
customColumnValueMapping.Add(KeyAndValue[0], KeyAndValue[1]);
}
}
string newBody = string.Empty;
foreach (KeyValuePair<string, string> kvp in customColumnValueMapping)
{
newBody += kvp.Key + "=" + kvp.Value + "|";
}
if (newBody == flagAndFields[1])
{
return;
}
else
{
ctItem.Body = "0;" + newBody;
}
}
}
}
ctItem.Save();
}
catch(System.Exception ex)
{
// log the error always
Trace.TraceError("{0}: [class]:{1} [method]:{2}\n[message]:{4}\n[Stack]:\n{5}",
DateTime.Now, // when was the error happened
MethodInfo.GetCurrentMethod().DeclaringType.Name, // the class name
MethodInfo.GetCurrentMethod().Name, // the method name
ex.Message, // the error message
ex.StackTrace // the stack trace information
);
// now display a friendly error to the user
MessageBox.Show("There was an application error, you should save your work and restart Outlook.",
"TraceAndLog",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
Now the issue is, the contact item update works fine from outlook the first time. The contact gets updated properly, the add-in works fine and changes get reflected in SharePoint just fine. But when I try to edit the contact again using outlook, a pop-up comes up saying "Item cannot be changed because it was changed by another user or in another window. Do you want to make a copy in the default folder for the item?" and the oulook add-in stops working thereafter.
Can anyone please suggest a solution for this problem?
I cannot use ctItem.Close() as when I use this function, the synchronization process doesn't work and the changes don't get populated to SharePoint.

Add/Create new document in SharePoint document Library programmatically

I have created a new Document Library and set up custom content type with MS Word Document Template. When i click on Create new template it works fine. but i need to be able to add some logic on a button event where it will go into that library and create a new document, so that when i go into that library i will see a new document that has been created by that button event.
i tried doing it as i would do a regular list item, but i got the following error on item.update:
To add an item to a document library, use SPFileCollection.Add()
Now i did some research but everywhere i see the code for uploading a file to the document library but no where i can find how to add a new document using my template that is associated in that doc library.
please help and thanks.
public static void colFileMtod()
{
using (SPSite objsite = new SPSite("http://smi-dev.na.sysco.net/SyscoFinance/FSR/"))
{
using (SPWeb objWeb = objsite.OpenWeb())
{
SPFileCollection collFiles = objWeb.GetFolder("BPCPublishRecord").Files;
SPList lst = objWeb.Lists["BPCPublishRecordCopy"];
if (lst != null)
{
if (objWeb.Lists.Cast<SPList>().Any(list => list.Title.Equals("BPCPublishRecordCopy", StringComparison.OrdinalIgnoreCase)))
{
foreach (SPFile file in collFiles)
{
string strDestUrl = collFiles.Folder.Url + "/" + file.Name;
byte[] binFile = file.OpenBinary();
SPUser oUserAuthor = file.Author;
SPUser oUserModified = file.ModifiedBy;
System.DateTime dtCreated = file.TimeCreated;
System.DateTime dtModified = file.TimeLastModified;
SPFile oFileNew = collFiles.Add(strDestUrl, binFile, oUserAuthor, oUserModified, dtCreated, dtModified);
SPListItem oListItem = lst.AddItem();
oListItem = oFileNew.Item;
oListItem["Created"] = dtCreated;
oListItem["Modified"] = dtModified;
oListItem.Update();
objWeb.AllowUnsafeUpdates = true;
}
}
}
}
}
}

Dynamically add mergefields in existing docx-document

Is it possible to add mergefields to an existing .docx document without using interop, only handling with open SDK from CodeBehind?
Yes this is possible, I've created a little method below where you simply pass through the name you want to assign to the merge field and it creates it for you.
The code below is for creating a new document but it should be easy enough to use the method to append to an existing document, hope this helps you:
using System;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
using (WordprocessingDocument package = WordprocessingDocument.Create("D:\\ManualMergeFields.docx", WordprocessingDocumentType.Document))
{
package.AddMainDocumentPart();
Paragraph nameMergeField = CreateMergeField("Name");
Paragraph surnameMergeField = CreateMergeField("Surname");
Body body = new Body();
body.Append(nameMergeField);
body.Append(surnameMergeField);
package.MainDocumentPart.Document = new Document(new Body(body));
}
}
static Paragraph CreateMergeField(string name)
{
if (!String.IsNullOrEmpty(name))
{
string instructionText = String.Format(" MERGEFIELD {0} \\* MERGEFORMAT", name);
SimpleField simpleField1 = new SimpleField() { Instruction = instructionText };
Run run1 = new Run();
RunProperties runProperties1 = new RunProperties();
NoProof noProof1 = new NoProof();
runProperties1.Append(noProof1);
Text text1 = new Text();
text1.Text = String.Format("«{0}»", name);
run1.Append(runProperties1);
run1.Append(text1);
simpleField1.Append(run1);
Paragraph paragraph = new Paragraph();
paragraph.Append(new OpenXmlElement[] { simpleField1 });
return paragraph;
}
else return null;
}
}
}
You can download the Open Xml Productivity Tool from this url(if you do not already have it)http://www.microsoft.com/download/en/details.aspx?id=5124
This tool has a "Reflect Code" functionality.So you can manually create a merge field in an MS Word document and then open up the document with the Productivity Tool
and see a C# code sample on how to do this in code!It's very effective an I've used this exact tool to create the sample above.Good luck

SharePoint list attachments, how to overwrite them

Quick question about SharePoint....
I need to update an attachment on a list using the SharePoint sdk,but when ever I delete the old one, and add the new one, the new document is never added. Below is my code...
/* Delete the attachment first and create a new attachment.*/
string fileName = newAttachmentName.Substring(0, newAttachmentName.IndexOf("."));
//Delete Attachment
SPAttachmentCollection attachments = item.Attachments;
if (item.Attachments != null)
{
string oldfilename = attachments[0].ToString();
attachments.DeleteNow(oldfilename);
item.Update();
}
//AddAttachement(item, newAttachmentName, attachmentStream, true);
attachments.Add(newAttachmentName, contents);
////attachments[0] = filename;
item.Update();
Maybe this will be of any help:
Retrieving Attachments from SharePoint List Items
Below does NOT work:
SPAttachmentCollection attachments = listitem.Attachments;
foreach (SPFile file in attachments)
{
// Do something
}
Below DOES work:
SPFolder folder = web.Folders["Lists"].SubFolders[list.Title].SubFolders["Attachments"].SubFolders[listitem.ID.ToString()];
foreach (SPFile file in folder.Files)
{
// Something useful here
}
SPAttachmentCollection attachments1 = item.Attachments;
attachments1.Add(newAttachmentName, contents);
item.Update();``
where you overwriting your new file create new instance of Attachments( attachment1)

Resources