I'm trying to place a table at a bookmark in a word document using poi
the paragraph is found
CTP ctp = paragraph.getCTP();
// Get all bookmarks and loop through them
for( CTBookmark bookmark in ctp.getBookmarkStartList())
{
for(j = 0; j < viewScope.Bookmarks.length; j++)
{
if(bookmark.getName().equals(viewScope.Bookmarks[j]))
A table does get created but the word file is corrupt ... "word found unreadable content"
XmlCursor cursor = null;
cursor = paragraph.getCTP().newCursor();
// cursor.toNextSibling();
XWPFTable wTable = paragraph.getBody().insertNewTbl(cursor);
XWPFTableRow row = wTable.createRow(); //
row.addNewTableCell();
XWPFTableCell cell = row.createCell();
cell.setText("New work");
cursor.dispose();
Welcome to the nice world of XWPFTable creating methods. Instead of creating an empty table apache poi creates tables having rows and empty cells already. And what exactly it creates changes from version to version. So you cannot be sure what already exists and what not. So you always need to check. Is there a row already or needs one to create? Is there a cell already or needs one to create?
In your case:
...
if (paragraph != null) {
cursor = paragraph.getCTP().newCursor();
XWPFTable table = paragraph.getBody().insertNewTbl(cursor);
XWPFTableRow row = table.getRow(0); if (row == null) row = table.createRow();
XWPFTableCell cell = row.getCell(0); if (cell == null) cell = row.createCell();
cell.setText("New work");
cursor.dispose();
}
...
See Inserting XWPFTable in between contents where I provided a code which inserts a table in between existing paragraphs dependent on the text contents. There I have edited now because apache poi formerly had put a paragraph already in a new created cell. But now it does that not more. So now you also have to check whether is there a paragraph already or needs to be created.
Related
How to convert data from Firestore Into an Excel sheet on both Android app and flutter web?
Any response will be appreciated... thanks in advance!
Excel library for flutter
You can go through the documentation here.
Now as jay asked to explain in detail how you are gonna retrive the data and store it in the excel sheet,
First step,
var excel = Excel.createExcel(); //create an excel sheet
Sheet sheetObject = excel['SheetName']; //create an sheet object
Second step, commands to write in excel sheet,
where A is column id and 1 is row.
var cell = sheetObject.cell(CellIndex.indexByString("A1"));
cell.value = 8; // Insert value to selected cell;
Third step, getting data from firebase
QuerySnapshot _qs =
await _notificationRef.where('language', isEqualTo: selectedLang).get(); // Lets say I have some collection where I need to get some documents with specific language
//This loop will iterate in all of the documents in the collection
for (int i = 0; i < _qs.docs.length; i++) {
string data = _qs.docs[i].data()['names']; //Where name is the field value in the document and i is the index of the document.
}
});
Now if we combine second and third step
QuerySnapshot _qs =
await _notificationRef.where('language', isEqualTo: selectedLang).get();
for (int i = 0; i < _qs.docs.length; i++) {
var cell = sheetObject.cell(CellIndex.indexByString('A${i+1}')); //i+1 means when the loop iterates every time it will write values in new row, e.g A1, A2, ...
cell.value = _qs.docs[i].data()['names']; // Insert value to selected cell;
}
});
Once you are done with the data part you can save the file,
// Save the Changes in file
excel.encode().then((onValue) {
File(join("Path_to_destination/excel.xlsx"))
..createSync(recursive: true)
..writeAsBytesSync(onValue);
});
Once you are done with the saving you can choose any of the library to share your sheet to others,
Usually this libraries asks you to provide a file or file path
which you can easily provide using the last code block explained where I passed file path to join method
Is there a way in MigraDoc to make an entire table cell a link? I have a tabular table of contents, and the page number is difficult to click. I would prefer if the entire cell was clickable to navigate to a specified page. Here is an example of my code:
// Create the table within the document
var document = new Document();
var section = document.AddSection();
var table = section.AddTable();
// Create a column in the table
var column = table.AddColumn();
column.Width = "2cm";
// Create a row in the table
var row = table.AddRow();
row.Height = "1cm";
// Add a hyperlink to the appropriate page
var paragraph = row.Cells[0].AddParagraph();
var hyperlink = paragraph.AddHyperlink("MyBookmarkName");
hyperlink.AddPageRefField("MyBookmarkName");
...
// Create the bookmark later in the document
I'm afraid there is no easy way to make the whole cell clickable. I haven't tried it myself, but you can add images (visible or transparent) or text to the hyperlink.
This will make the clickable area bigger - and if you use e.g. blue underlined text there will be a visual hint that the text is clickable.
I was inspired by the answer from the PDFsharp Team to try and fill the cell with a blank hyperlink image, with text over the hyperlink. Since my ultimate goal was to actually make an entire row a hyperlink, I came up with the following solution.
First, add an additional zero-width column prior to the first column in the table that you want to be a hyperlink. Next, add a paragraph, hyperlink, and transparent 1-pixel image to each zero-width cell. Specify the image height and width to fill however many table cells you want to be a link. Also, be sure to set the font size of the paragraph containing the link to nearly zero (zero throws an exception, but images are aligned on the font baseline, so you need a very small number to prevent the paragraph from being larger than the image).
Note that a zero-width column, even with borders, does not change the apparent border width when viewing the resulting PDF. The following code illustrates my approach:
// Declare some constants
var _rowHeight = new Unit(.75, UnitType.Centimeter);
// Create the document, section, and table
var document = new Document();
var section = document.AddSection();
var table = section.AddTable();
// Format the table
table.Rows.Height = _rowHeight;
table.Rows.VerticalAlignment = VerticalAlignment.Center;
// Define the column titles and widths
var columnInfos = new[] {
new { Title = "Non-Link Column", Width = new Unit(8, UnitType.Centimeter) },
new { Title = "" , Width = new Unit(0 ) },
new { Title = "Link Column 1" , Width = new Unit(8, UnitType.Centimeter) },
new { Title = "Link Column 2" , Width = new Unit(8, UnitType.Centimeter) },
};
// Define the column indices
const int colNonLink = 0;
const int colHyperlink = 1;
const int colLink1 = 2;
const int colLink2 = 3;
// Create all of the table columns
Unit tableWidth = 0;
foreach (var columnInfo in columnInfos)
{
table.AddColumn(columnInfo.Width);
tableWidth += columnInfo.Width;
}
// Remove the padding on the link column
var linkColumn = table.Columns[colHyperlink];
linkColumn.LeftPadding = 0;
linkColumn.RightPadding = 0;
// Compute the width of the summary links
var linkWidth = tableWidth -
columnInfos.Take(colHyperlink).Sum(ci => ci.Width);
// Create a row to store the column headers
var headerRow = table.AddRow();
headerRow.Height = ".6cm";
headerRow.HeadingFormat = true;
headerRow.Format.Font.Bold = true;
// Populate the header row
for (var colIdx = 0; colIdx < columnInfos.Length; ++colIdx)
{
var columnTitle = columnInfos[colIdx].Title;
if (!string.IsNullOrWhiteSpace(columnTitle))
{
headerRow.Cells[colIdx].AddParagraph(columnTitle);
}
}
// In the real code, the following is done in a loop to dynamically add rows
var row = table.AddRow();
// Populate the row header
row.Cells[colNonLink].AddParagraph("Not part of link");
// Change the alignment of the link cell
var linkCell = row.Cells[colHyperlink];
linkCell.VerticalAlignment = VerticalAlignment.Top;
// Add a hyperlink that fills the remaining cells in the row
var linkParagraph = linkCell.AddParagraph();
linkParagraph.Format.Font.Size = new Unit(.001, UnitType.Point);
var hyperlink = linkParagraph.AddHyperlink("MyBookmarkName");
var linkImage = hyperlink.AddImage("Transparent.gif");
linkImage.Height = _rowHeight;
linkImage.Width = linkWidth;
// Populate the remaining two cells
row.Cells[colLink1].AddParagraph("Part of link 1");
row.Cells[colLink2].AddParagraph("Part of link 2");
// Add a border around the cells
table.SetEdge(0, 0, columnInfos.Length, table.Rows.Count,
Edge.Box | Edge.Interior, BorderStyle.Single, .75, Colors.Black);
The result of the above code is a document containing a table with 2 rows, 3 visible columns, where the entirety of the last two cells in the final row are a hyperlink to "MyBookmarkName". Just for reference, I did modify the PDFSharp source code according to the advice here to remove borders around hyperlinks, which looked wonky at certain zoom levels in Adobe Acrobat Reader.
I have a datatable problem when I reject changes on the table. I've created an example below which demonstrates the problem:
DataTable table = new DataTable();
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Last_Name", typeof(string));
table.Columns.Add("Male", typeof(Boolean));
foreach (DataColumn column in table.Columns)
{
if (column.ColumnName == "Name")
{
column.Unique = true;
}
}
DataRow row;
row = table.NewRow();
row["Name"] = String.Format("Steve");
row["Last_Name"] = String.Format("Smith");
row["Male"] = true;
table.Rows.Add(row);
table.AcceptChanges();
So at this stage I have a DataTable with a unique column constraint and 1 row in that table.
I now delete that row:
row.Delete();
This sets the rowstate to Deleted.
At this stage I realise that I've made a mistake and want to add the row again. So I create the new row again and add it to the DataTable:
row = table.NewRow();
row["Name"] = String.Format("Steve");
row["Last_Name"] = String.Format("Smith");
row["Male"] = true;
table.Rows.Add(row);
At this stage my DataTable contents are in the following state:
table.Rows[0].RowState is Deleted
table.Rows[1].RowState is Added
Now, I've changed my mind about the whole thing and want to get back to how I started so I call RejectChanges:
table.RejectChanges();
When I do this I receive the following error:
Column 'Name' is constrained to be unique. Value 'Steve' is already present.
I understand that there are 2 rows with the same values but I thought reject changes would have ingored this as the RowStates are different.
Any ideas how I can get round this?
In my live code I use this to move rows between to 2 grids (like allowing the user to selected what columns are visible)
I'm using C#4.0 in Visual Studio 2012
Thanks in advance
I am creating grid view through data adapter and all columns and rows are created from data base but problem occurs that when rows all rows are created there comes another empty row i want to stop that row to be generated and when i click and some value in that extra row another new row is created i want to stop all extra rows how to do this any help???
this is the grid view code i am using
conn.ConnectionString = s;
conn.Open();
dAdapter = new SqlDataAdapter(query, s);
dTable = new DataTable();
DataView myDataView = dTable.DefaultView;
dAdapter.Fill(dTable);
BindingSource bndSource = new BindingSource();
bndSource.DataSource = dTable;
dataGrid.DataSource = bndSource;
dataGrid.Columns["StudentId"].ReadOnly = true;
dataGrid.Columns["StudentName"].ReadOnly = true;
conn.Close();
Try setting AllowUserToAddRows to false.
I am using openxml to create an excel report. The openxml operates on a template excel file using named ranges.
The client requires a totals row at the end of the list of rows. Sounds like a reasonable request!!
However, the data table I'm returning from the db can contain any number of rows. Using template rows and 'InsertBeforeSelf', my totals row is getting overridden.
My question is, using openxml, how can I insert rows into the spreadsheet, causing the totals row to be be moved down each time a row is inserted?
Regards ...
Assuming you're using the SDK 2.0, I did something similiar by using this function:
private static Row CreateRow(Row refRow, SheetData sheetData)
{
uint rowIndex = refRow.RowIndex.Value;
uint newRowIndex;
var newRow = (Row)refRow.Clone();
/*IEnumerable<Row> rows = sheetData.Descendants<Row>().Where(r => r.RowIndex.Value >= rowIndex);
foreach (Row row in rows)
{
newRowIndex = System.Convert.ToUInt32(row.RowIndex.Value + 1);
foreach (Cell cell in row.Elements<Cell>())
{
string cellReference = cell.CellReference.Value;
cell.CellReference = new StringValue(cellReference.Replace(row.RowIndex.Value.ToString(), newRowIndex.ToString()));
}
row.RowIndex = new UInt32Value(newRowIndex);
}*/
sheetData.InsertBefore(newRow, refRow);
return newRow;
}
I'm not sure how you were doing it with InsertBeforeSelf before, so maybe this isn't much of an improvement, but this has worked for me. I was thinking you could just use your totals row as the reference row. (The commented out part is for if you had rows after your reference row that you wanted to maintain. I made some modifications, but it mostly comes from this thread: http://social.msdn.microsoft.com/Forums/en-US/oxmlsdk/thread/65c9ca1c-25d4-482d-8eb3-91a3512bb0ac)
Since it returns the new row, you can use that object then to edit the cell values with the data from the database. I hope this is at least somewhat helpful to anyone trying to do this...
[Can someone with more points please put this text as a comment for the M_R_H's Answer.]
The solution that M_R_H gave helped me, but introduces a new bug to the problem. If you use the given CreateRow method as-is, if any of the rows being moved/re-referenced have formulas the CalcChain.xml (in the package) will be broken.
I added the following code to the proposed CreateRow solution. It still doesn't fix the problem, because, I think this code is only fixing the currently-being-copied row reference:
if (cell.CellFormula != null) {
string cellFormula = cell.CellFormula.Text;
cell.CellFormula = new CellFormula(cellFormula.Replace(row.RowIndex.Value.ToString(), newRowIndex.ToString()));
}
What is the proper way to fix/update CalcChain.xml?
PS: SheetData can be gotten from your worksheet as:
worksheet.GetFirstChild<SheetData>();
You have to loop all rows and cells under the inserted row,change its rowindex and cellreference. I guess OpenXml not so smart that help you change index automatically.
static void InsertRow(string sheetName, WorkbookPart wbPart, uint rowIndex)
{
Sheet sheet = wbPart.Workbook.Descendants<Sheet>().Where((s) => s.Name == sheetName).FirstOrDefault();
if (sheet != null)
{
Worksheet ws = ((WorksheetPart)(wbPart.GetPartById(sheet.Id))).Worksheet;
SheetData sheetData = ws.WorksheetPart.Worksheet.GetFirstChild<SheetData>();
Row refRow = GetRow(sheetData, rowIndex);
++rowIndex;
Cell cell1 = new Cell() { CellReference = "A" + rowIndex };
CellValue cellValue1 = new CellValue();
cellValue1.Text = "";
cell1.Append(cellValue1);
Row newRow = new Row()
{
RowIndex = rowIndex
};
newRow.Append(cell1);
for (int i = (int)rowIndex; i <= sheetData.Elements<Row>().Count(); i++)
{
var row = sheetData.Elements<Row>().Where(r => r.RowIndex.Value == i).FirstOrDefault();
row.RowIndex++;
foreach (Cell c in row.Elements<Cell>())
{
string refer = c.CellReference.Value;
int num = Convert.ToInt32(Regex.Replace(refer, #"[^\d]*", ""));
num++;
string letters = Regex.Replace(refer, #"[^A-Z]*", "");
c.CellReference.Value = letters + num;
}
}
sheetData.InsertAfter(newRow, refRow);
//ws.Save();
}
}
static Row GetRow(SheetData wsData, UInt32 rowIndex)
{
var row = wsData.Elements<Row>().
Where(r => r.RowIndex.Value == rowIndex).FirstOrDefault();
if (row == null)
{
row = new Row();
row.RowIndex = rowIndex;
wsData.Append(row);
}
return row;
}
Above solution got from:How to insert the row in exisiting template in open xml. There is a clear explanation might help you a lot.