EvotecIT / OfficeIMO

Fast and easy to use cross-platform .NET library that creates or modifies Microsoft Word (DocX) and later also Excel (XLSX) files without installing any software. Library is based on Open XML SDK
MIT License
288 stars 50 forks source link

Table AutoFit To Content #33

Open PrzemyslawKlys opened 2 years ago

PrzemyslawKlys commented 2 years ago

Initially, I thought about implementing Table AutoFitType, but it seems that AutoFit.ToContent is not something that is automatic but is something that Word does automatically, as in set it to fixes size and then using TabelGrid sizes sets the rest.

I don't know the magic numbers to count this - but maybe someone does to fix this in future.

public enum AutoFitType {
    ToContent,
    ToWindow,
    Fixed
}

public AutoFitType? AutoFit {
    get {
        if (this.Width == 0 && WidthType == TableWidthUnitValues.Auto) {
            return AutoFitType.ToContent;
        } else if (this.Width == 5000 && WidthType == TableWidthUnitValues.Pct) {
            return AutoFitType.ToWindow;
        } else if (this.LayoutType == TableLayoutValues.Fixed) {
            return AutoFitType.Fixed;
        }
        return null;
    }
    set {
        if (value == AutoFitType.ToContent) {
            this.Width = 0;
            this.WidthType = TableWidthUnitValues.Auto;
            //this.LayoutType = TableLayoutValues.Autofit;
        } else if (value == AutoFitType.ToWindow) {
            this.Width = 5000;
            this.WidthType = TableWidthUnitValues.Pct;
        } else if (value == AutoFitType.Fixed) {
            this.LayoutType = TableLayoutValues.Fixed;
        } else {
            throw new ArgumentException("Invalid value for AutoFitType. Probably should add null handling");
        }
    }
}

        public TableGrid GenerateTableGrid()
        {
            TableGrid tableGrid1 = new TableGrid();
            GridColumn gridColumn1 = new GridColumn(){ Width = "3116" };
            GridColumn gridColumn2 = new GridColumn(){ Width = "3117" };
            GridColumn gridColumn3 = new GridColumn(){ Width = "3117" };

            tableGrid1.Append(gridColumn1);
            tableGrid1.Append(gridColumn2);
            tableGrid1.Append(gridColumn3);
            return tableGrid1;
        }
hisuwh commented 2 years ago

What about table full width of document, with columns certain percentage of that? Is that not a more common requirement for a word document?

PrzemyslawKlys commented 2 years ago

I believe this works:

                WordTable wordTable = document.AddTable(4, 4, WordTableStyle.GridTable1LightAccent1);
                wordTable.Rows[0].Cells[0].Paragraphs[0].Text = "Test 1";
                wordTable.Rows[1].Cells[0].Paragraphs[0].Text = "Test 2";
                wordTable.Rows[2].Cells[0].Paragraphs[0].Text = "Test 3";
                wordTable.Rows[3].Cells[0].Paragraphs[0].Text = "Test 4";
                wordTable.LayoutType = TableLayoutValues.Autofit;

or

         WordTable wordTable1 = document.AddTable(4, 4, WordTableStyle.GridTable1LightAccent1);
                wordTable1.Rows[0].Cells[0].Paragraphs[0].Text = "Test 1";
                wordTable1.Rows[1].Cells[0].Paragraphs[0].Text = "Test 2";
                wordTable1.Rows[2].Cells[0].Paragraphs[0].Text = "Test 3";
                wordTable1.Rows[3].Cells[0].Paragraphs[0].Text = "Test 4";

                wordTable1.WidthType = TableWidthUnitValues.Pct;
                wordTable1.Width = 3000;

or

                WordTable wordTable2 = document.AddTable(4, 4, WordTableStyle.GridTable1LightAccent1);
                wordTable2.Rows[0].Cells[0].Paragraphs[0].Text = "Test 1";
                wordTable2.Rows[1].Cells[0].Paragraphs[0].Text = "Test 2";
                wordTable2.Rows[2].Cells[0].Paragraphs[0].Text = "Test 3";
                wordTable2.Rows[3].Cells[0].Paragraphs[0].Text = "Test 4";

                wordTable2.ColumnWidth = new List<int>() { 1716, 3817, 300, 3000 };
                wordTable2.RowHeight = new List<int>() { 1000, 300, 500, 200 };

                // add a cell to 3rd row
                WordTableCell cell = new WordTableCell(document, wordTable2, wordTable2.Rows[2]);
                cell.Paragraphs[0].Text = "This cell is outside a bit";
                cell.TextDirection = TextDirectionValues.TopToBottomLeftToRightRotated;

                wordTable2.LayoutType = TableLayoutValues.Fixed;

It seems to be more complicated to generate proper fitting and it depends on page size i guess.

hisuwh commented 2 years ago

I will try these out. Where does the 3000 value come from?

PrzemyslawKlys commented 2 years ago

i've seen it when reading XML files created by Word. The width/height of different things in OfficeIMO is a mess

hisuwh commented 2 years ago

This seems to work:

wordTable.WidthType = TableWidthUnitValues.Pct;
wordTable.Width = 5000;
PrzemyslawKlys commented 2 years ago

Ye, but what happens if you set different page size?

PrzemyslawKlys commented 2 years ago

Generally someone needs to do the hard work of checking how things change on different pages and maybe improve the method above for it to be usable.

hisuwh commented 2 years ago

For my requirement, it won't be an issue - assuming this is at least constant from computer to computer.

Though I have found the explanation here: http://officeopenxml.com/WPtableWidth.php

So 5000 is 100%. Though it sounds like in the latest version of the spec you can specify 100% in the XML - though your API only allows for a number here.

hisuwh commented 2 years ago

Sent a pr to update the example here: https://github.com/EvotecIT/OfficeIMO/pull/41

PrzemyslawKlys commented 2 years ago

Then we need to change an API and accept both numbers and strings with percentages or another property