From b6d2f5f5b6a8a3e8223a1bd631f7c858f81aa117 Mon Sep 17 00:00:00 2001 From: Adrian-George Bostan Date: Tue, 5 Mar 2019 21:39:55 +0200 Subject: [PATCH 1/5] Add chapter hierarchy support --- pdf/creator/chapters.go | 115 ++++++++++++------- pdf/creator/creator.go | 9 +- pdf/creator/subchapter.go | 233 -------------------------------------- 3 files changed, 80 insertions(+), 277 deletions(-) delete mode 100644 pdf/creator/subchapter.go diff --git a/pdf/creator/chapters.go b/pdf/creator/chapters.go index bff39f00..2e097aea 100644 --- a/pdf/creator/chapters.go +++ b/pdf/creator/chapters.go @@ -17,14 +17,14 @@ import ( // Chapter is used to arrange multiple drawables (paragraphs, images, etc) into a single section. // The concept is the same as a book or a report chapter. type Chapter struct { - number int - title string - heading *Paragraph - - subchapters int - + number int + title string + heading *Paragraph contents []Drawable + // The number of subchapters the chapter has. + subchapters int + // Show chapter numbering showNumbering bool @@ -40,6 +40,9 @@ type Chapter struct { // Margins to be applied around the block when drawing on Page. margins margins + // Reference to the parent chapter the current chapter belongs to. + parent *Chapter + // Reference to the TOC of the creator. toc *TOC @@ -48,36 +51,53 @@ type Chapter struct { // The item of the chapter in the outline. outlineItem *model.OutlineItem + + // The level of the chapter in the chapters hierarchy. + level uint } // newChapter creates a new chapter with the specified title as the heading. -func newChapter(toc *TOC, outline *model.Outline, title string, number int, style TextStyle) *Chapter { - p := newParagraph(fmt.Sprintf("%d. %s", number, title), style) - p.SetFont(style.Font) - p.SetFontSize(16) +func newChapter(parent *Chapter, toc *TOC, outline *model.Outline, title string, number int, style TextStyle) *Chapter { + var level uint = 1 + if parent != nil { + level = parent.level + 1 + } - return &Chapter{ + chapter := &Chapter{ number: number, title: title, showNumbering: true, includeInTOC: true, + parent: parent, toc: toc, outline: outline, - heading: p, contents: []Drawable{}, + level: level, } + + p := newParagraph(chapter.headingText(), style) + p.SetFont(style.Font) + p.SetFontSize(style.FontSize) + + chapter.heading = p + return chapter +} + +// NewSubchapter creates a new child chapter with specified heading. +func (chap *Chapter) NewSubchapter(title string) *Chapter { + style := newTextStyle(chap.heading.textFont) + style.FontSize = 14 + + chap.subchapters++ + subchapter := newChapter(chap, chap.toc, chap.outline, title, chap.subchapters, style) + chap.Add(subchapter) + + return subchapter } // SetShowNumbering sets a flag to indicate whether or not to show chapter numbers as part of title. func (chap *Chapter) SetShowNumbering(show bool) { - if show { - heading := fmt.Sprintf("%d. %s", chap.number, chap.title) - chap.heading.SetText(heading) - } else { - heading := fmt.Sprintf("%s", chap.title) - chap.heading.SetText(heading) - } - chap.showNumbering = show + chap.heading.SetText(chap.headingText()) } // SetIncludeInTOC sets a flag to indicate whether or not to include in tOC. @@ -112,10 +132,7 @@ func (chap *Chapter) Add(d Drawable) error { } switch d.(type) { - case *Chapter: - common.Log.Debug("ERROR: Cannot add chapter to a chapter") - return errors.New("type check error") - case *Paragraph, *Image, *Block, *Subchapter, *Table, *PageBreak: + case *Paragraph, *Image, *Block, *Table, *PageBreak, *Chapter: chap.contents = append(chap.contents, d) default: common.Log.Debug("Unsupported: %T", d) @@ -125,6 +142,33 @@ func (chap *Chapter) Add(d Drawable) error { return nil } +func (chap *Chapter) headingNumber() string { + var chapNumber string + if chap.showNumbering { + if chap.number != 0 { + chapNumber = strconv.Itoa(chap.number) + "." + } + + if chap.parent != nil { + parentChapNumber := chap.parent.headingNumber() + if parentChapNumber != "" { + chapNumber = parentChapNumber + chapNumber + } + } + } + + return chapNumber +} + +func (chap *Chapter) headingText() string { + heading := chap.title + if chapNumber := chap.headingNumber(); chapNumber != "" { + heading = fmt.Sprintf("%s %s", chapNumber, heading) + } + + return heading +} + // GeneratePageBlocks generate the Page blocks. Multiple blocks are generated if the contents wrap // over multiple pages. func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) { @@ -150,23 +194,13 @@ func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, } // Generate chapter title and number. - chapTitle := chap.title - var chapNumber string page := int64(ctx.Page) - - if chap.showNumbering { - if chap.number != 0 { - chapNumber = strconv.Itoa(chap.number) + "." - } - } - - if chapNumber != "" { - chapTitle = fmt.Sprintf("%s %s", chapNumber, chapTitle) - } + chapNumber := chap.headingNumber() + chapTitle := chap.headingText() // Add to TOC. if chap.includeInTOC { - line := chap.toc.Add(chapNumber, chap.title, strconv.FormatInt(page, 10), 1) + line := chap.toc.Add(chapNumber, chap.title, strconv.FormatInt(page, 10), chap.level) if chap.toc.showLinks { line.SetLink(page, origX, origY) } @@ -178,7 +212,12 @@ func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, chapTitle, model.NewOutlineDest(page-1, origX, origY), ) - chap.outline.Add(chap.outlineItem) + + if chap.parent != nil { + chap.parent.outlineItem.Add(chap.outlineItem) + } else { + chap.outline.Add(chap.outlineItem) + } } else { outlineDest := &chap.outlineItem.Dest outlineDest.Page = page - 1 diff --git a/pdf/creator/creator.go b/pdf/creator/creator.go index 6d0c55e5..a0a0e872 100644 --- a/pdf/creator/creator.go +++ b/pdf/creator/creator.go @@ -714,13 +714,10 @@ func (c *Creator) NewStyledTOCLine(number, title, page TextChunk, level uint, st // NewChapter creates a new chapter with the specified title as the heading. func (c *Creator) NewChapter(title string) *Chapter { c.chapters++ - return newChapter(c.toc, c.outline, title, c.chapters, c.NewTextStyle()) -} + style := c.NewTextStyle() + style.FontSize = 16 -// NewSubchapter creates a new Subchapter under Chapter ch with specified title. -// All other parameters are set to their defaults. -func (c *Creator) NewSubchapter(ch *Chapter, title string) *Subchapter { - return newSubchapter(ch, title, c.NewTextStyle()) + return newChapter(nil, c.toc, c.outline, title, c.chapters, style) } // NewInvoice returns an instance of an empty invoice. diff --git a/pdf/creator/subchapter.go b/pdf/creator/subchapter.go deleted file mode 100644 index aaadfa93..00000000 --- a/pdf/creator/subchapter.go +++ /dev/null @@ -1,233 +0,0 @@ -/* - * This file is subject to the terms and conditions defined in - * file 'LICENSE.md', which is part of this source code package. - */ - -package creator - -import ( - "fmt" - "strconv" - - "github.com/unidoc/unidoc/common" - "github.com/unidoc/unidoc/pdf/model" -) - -// Subchapter simply represents a sub chapter pertaining to a specific Chapter. It can contain -// multiple Drawables, just like a chapter. -type Subchapter struct { - subchapterNum int - title string - heading *Paragraph - - contents []Drawable - - // Show chapter numbering - showNumbering bool - - // Include in TOC. - includeInTOC bool - - // Positioning: relative / absolute. - positioning positioning - - // Absolute coordinates (when in absolute mode). - xPos, yPos float64 - - // Margins to be applied around the block when drawing on Page. - margins margins - - // Reference to the creator's TOC. - toc *TOC - - // Reference to the chapter the subchapter belongs to. - chapter *Chapter - - // Reference to the outline of the creator. - outline *model.Outline - - // The item of the subchapter in the outline. - outlineItem *model.OutlineItem -} - -// newSubchapter creates a new Subchapter under Chapter ch with specified title. -// All other parameters are set to their defaults. -func newSubchapter(ch *Chapter, title string, style TextStyle) *Subchapter { - ch.subchapters++ - - p := newParagraph(fmt.Sprintf("%d.%d %s", ch.number, ch.subchapters, title), style) - p.SetFont(style.Font) // bold? - p.SetFontSize(14) - - subchapter := &Subchapter{ - subchapterNum: ch.subchapters, - title: title, - showNumbering: true, - includeInTOC: true, - heading: p, - contents: []Drawable{}, - chapter: ch, - toc: ch.toc, - outline: ch.outline, - } - - // Add subchapter to chapter. - ch.Add(subchapter) - - return subchapter -} - -// SetShowNumbering sets a flag to indicate whether or not to show chapter numbers as part of title. -func (subchap *Subchapter) SetShowNumbering(show bool) { - if show { - heading := fmt.Sprintf("%d.%d. %s", subchap.chapter.number, subchap.subchapterNum, subchap.title) - subchap.heading.SetText(heading) - } else { - heading := fmt.Sprintf("%s", subchap.title) - subchap.heading.SetText(heading) - } - subchap.showNumbering = show -} - -// SetIncludeInTOC sets a flag to indicate whether or not to include in the table of contents. -func (subchap *Subchapter) SetIncludeInTOC(includeInTOC bool) { - subchap.includeInTOC = includeInTOC -} - -// GetHeading returns the Subchapter's heading Paragraph to address style (font type, size, etc). -func (subchap *Subchapter) GetHeading() *Paragraph { - return subchap.heading -} - -// Set absolute coordinates. -/* -func (subchap *subchapter) SetPos(x, y float64) { - subchap.positioning = positionAbsolute - subchap.xPos = x - subchap.yPos = y -} -*/ - -// SetMargins sets the Subchapter's margins (left, right, top, bottom). -// These margins are typically not needed as the Creator's page margins are used preferably. -func (subchap *Subchapter) SetMargins(left, right, top, bottom float64) { - subchap.margins.left = left - subchap.margins.right = right - subchap.margins.top = top - subchap.margins.bottom = bottom -} - -// GetMargins returns the Subchapter's margins: left, right, top, bottom. -func (subchap *Subchapter) GetMargins() (float64, float64, float64, float64) { - return subchap.margins.left, subchap.margins.right, subchap.margins.top, subchap.margins.bottom -} - -// Add adds a new Drawable to the chapter. -// The currently supported Drawables are: *Paragraph, *Image, *Block, *Table. -func (subchap *Subchapter) Add(d Drawable) { - switch d.(type) { - case *Chapter, *Subchapter: - common.Log.Debug("Error: Cannot add chapter or subchapter to a subchapter") - case *Paragraph, *Image, *Block, *Table, *PageBreak: - subchap.contents = append(subchap.contents, d) - default: - common.Log.Debug("Unsupported: %T", d) - } -} - -// GeneratePageBlocks generates the page blocks. Multiple blocks are generated if the contents wrap -// over multiple pages. Implements the Drawable interface. -func (subchap *Subchapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) { - origCtx := ctx - - if subchap.positioning.isRelative() { - // Update context. - ctx.X += subchap.margins.left - ctx.Y += subchap.margins.top - ctx.Width -= subchap.margins.left + subchap.margins.right - ctx.Height -= subchap.margins.top - } - - origX := ctx.X - origY := ctx.Y - - blocks, ctx, err := subchap.heading.GeneratePageBlocks(ctx) - if err != nil { - return blocks, ctx, err - } - if len(blocks) > 1 { - ctx.Page++ // did not fit - moved to next Page. - } - - // Generate subchapter title and number. - subchapTitle := subchap.title - var subchapNumber string - page := int64(ctx.Page) - - if subchap.showNumbering { - if subchap.chapter.number != 0 { - subchapNumber = strconv.Itoa(subchap.chapter.number) - } - if subchap.subchapterNum != 0 { - if subchapNumber != "" { - subchapNumber += "." - } - - subchapNumber += strconv.Itoa(subchap.subchapterNum) + "." - } - } - - if subchapNumber != "" { - subchapTitle = fmt.Sprintf("%s %s", subchapNumber, subchapTitle) - } - - // Add to TOC. - if subchap.includeInTOC { - line := subchap.toc.Add(subchapNumber, subchap.title, strconv.FormatInt(page, 10), 2) - if subchap.toc.showLinks { - line.SetLink(page, origX, origY) - } - } - - // Add to outline. - if subchap.outlineItem == nil { - subchap.outlineItem = model.NewOutlineItem( - subchapTitle, - model.NewOutlineDest(page-1, origX, origY), - ) - subchap.chapter.outlineItem.Add(subchap.outlineItem) - } else { - outlineDest := &subchap.outlineItem.Dest - outlineDest.Page = page - 1 - outlineDest.X = origX - outlineDest.Y = origY - } - - for _, d := range subchap.contents { - newBlocks, c, err := d.GeneratePageBlocks(ctx) - if err != nil { - return blocks, ctx, err - } - if len(newBlocks) < 1 { - continue - } - - // The first block is always appended to the last.. - blocks[len(blocks)-1].mergeBlocks(newBlocks[0]) - blocks = append(blocks, newBlocks[1:]...) - - ctx = c - } - - if subchap.positioning.isRelative() { - // Move back X to same start of line. - ctx.X = origCtx.X - } - - if subchap.positioning.isAbsolute() { - // If absolute: return original context. - return blocks, origCtx, nil - } - - return blocks, ctx, nil -} From 548af32929de9a19e1eaf0f9189937dc084cbbbe Mon Sep 17 00:00:00 2001 From: Adrian-George Bostan Date: Tue, 5 Mar 2019 21:40:38 +0200 Subject: [PATCH 2/5] Adapt creator test --- pdf/creator/creator_test.go | 44 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/pdf/creator/creator_test.go b/pdf/creator/creator_test.go index d122581d..b3b86c36 100644 --- a/pdf/creator/creator_test.go +++ b/pdf/creator/creator_test.go @@ -793,7 +793,7 @@ func TestSubchaptersSimple(t *testing.T) { // Add chapters. ch1 := c.NewChapter("Introduction") - subchap1 := c.NewSubchapter(ch1, "The fundamentals of the mastery of the most genious experiment of all times in modern world history. The story of the maker and the maker bot and the genius cow.") + subchap1 := ch1.NewSubchapter("The fundamentals of the mastery of the most genious experiment of all times in modern world history. The story of the maker and the maker bot and the genius cow.") subchap1.SetMargins(0, 0, 5, 0) //subCh1 := NewSubchapter(ch1, "Workflow") @@ -809,19 +809,19 @@ func TestSubchaptersSimple(t *testing.T) { subchap1.Add(p) } - subchap2 := c.NewSubchapter(ch1, "Mechanism") + subchap2 := ch1.NewSubchapter("Mechanism") subchap2.SetMargins(0, 0, 5, 0) for j := 0; j < 1; j++ { subchap2.Add(p) } - subchap3 := c.NewSubchapter(ch1, "Discussion") + subchap3 := ch1.NewSubchapter("Discussion") subchap3.SetMargins(0, 0, 5, 0) for j := 0; j < 1; j++ { subchap3.Add(p) } - subchap4 := c.NewSubchapter(ch1, "Conclusion") + subchap4 := ch1.NewSubchapter("Conclusion") subchap4.SetMargins(0, 0, 5, 0) for j := 0; j < 1; j++ { subchap4.Add(p) @@ -895,7 +895,7 @@ func TestSubchapters(t *testing.T) { // Add chapters. ch1 := c.NewChapter("Introduction") - subchap1 := c.NewSubchapter(ch1, "The fundamentals") + subchap1 := ch1.NewSubchapter("The fundamentals") subchap1.SetMargins(0, 0, 5, 0) //subCh1 := NewSubchapter(ch1, "Workflow") @@ -911,19 +911,19 @@ func TestSubchapters(t *testing.T) { subchap1.Add(p) } - subchap2 := c.NewSubchapter(ch1, "Mechanism") + subchap2 := ch1.NewSubchapter("Mechanism") subchap2.SetMargins(0, 0, 5, 0) for j := 0; j < 15; j++ { subchap2.Add(p) } - subchap3 := c.NewSubchapter(ch1, "Discussion") + subchap3 := ch1.NewSubchapter("Discussion") subchap3.SetMargins(0, 0, 5, 0) for j := 0; j < 19; j++ { subchap3.Add(p) } - subchap4 := c.NewSubchapter(ch1, "Conclusion") + subchap4 := ch1.NewSubchapter("Conclusion") subchap4.SetMargins(0, 0, 5, 0) for j := 0; j < 23; j++ { subchap4.Add(p) @@ -1808,7 +1808,7 @@ func TestTableInSubchapter(t *testing.T) { ch.GetHeading().SetFontSize(18) ch.GetHeading().SetColor(ColorRGBFrom8bit(72, 86, 95)) - sc := c.NewSubchapter(ch, "Issuer details") + sc := ch.NewSubchapter("Issuer details") sc.SetMargins(0, 0, 5, 0) sc.GetHeading().SetFont(fontRegular) sc.GetHeading().SetFontSize(18) @@ -1862,7 +1862,7 @@ func TestTableInSubchapter(t *testing.T) { ch.Add(issuerTable) - sc = c.NewSubchapter(ch, "My Statement") + sc = ch.NewSubchapter("My Statement") //sc.SetMargins(0, 0, 5, 0) sc.GetHeading().SetFont(fontRegular) sc.GetHeading().SetFontSize(18) @@ -2381,7 +2381,7 @@ func TestCombineDuplicateDirectObjects(t *testing.T) { c.AddTOC = true ch1 := c.NewChapter("Introduction") - subchap1 := c.NewSubchapter(ch1, "The fundamentals") + subchap1 := ch1.NewSubchapter("The fundamentals") subchap1.SetMargins(0, 0, 5, 0) //subCh1 := NewSubchapter(ch1, "Workflow") @@ -2398,19 +2398,19 @@ func TestCombineDuplicateDirectObjects(t *testing.T) { subchap1.Add(p) } - subchap2 := c.NewSubchapter(ch1, "Mechanism") + subchap2 := ch1.NewSubchapter("Mechanism") subchap2.SetMargins(0, 0, 5, 0) for j := 0; j < 3; j++ { subchap2.Add(p) } - subchap3 := c.NewSubchapter(ch1, "Discussion") + subchap3 := ch1.NewSubchapter("Discussion") subchap3.SetMargins(0, 0, 5, 0) for j := 0; j < 4; j++ { subchap3.Add(p) } - subchap4 := c.NewSubchapter(ch1, "Conclusion") + subchap4 := ch1.NewSubchapter("Conclusion") subchap4.SetMargins(0, 0, 5, 0) for j := 0; j < 3; j++ { subchap4.Add(p) @@ -2588,7 +2588,7 @@ func TestCombineIdenticalIndirectObjects(t *testing.T) { c.AddTOC = true ch1 := c.NewChapter("Introduction") - subchap1 := c.NewSubchapter(ch1, "The fundamentals") + subchap1 := ch1.NewSubchapter("The fundamentals") subchap1.SetMargins(0, 0, 5, 0) //subCh1 := NewSubchapter(ch1, "Workflow") @@ -2604,19 +2604,19 @@ func TestCombineIdenticalIndirectObjects(t *testing.T) { subchap1.Add(p) } - subchap2 := c.NewSubchapter(ch1, "Mechanism") + subchap2 := ch1.NewSubchapter("Mechanism") subchap2.SetMargins(0, 0, 5, 0) for j := 0; j < 15; j++ { subchap2.Add(p) } - subchap3 := c.NewSubchapter(ch1, "Discussion") + subchap3 := ch1.NewSubchapter("Discussion") subchap3.SetMargins(0, 0, 5, 0) for j := 0; j < 19; j++ { subchap3.Add(p) } - subchap4 := c.NewSubchapter(ch1, "Conclusion") + subchap4 := ch1.NewSubchapter("Conclusion") subchap4.SetMargins(0, 0, 5, 0) for j := 0; j < 23; j++ { subchap4.Add(p) @@ -2781,7 +2781,7 @@ func TestAllOptimizations(t *testing.T) { c.AddTOC = true ch1 := c.NewChapter("Introduction") - subchap1 := c.NewSubchapter(ch1, "The fundamentals") + subchap1 := ch1.NewSubchapter("The fundamentals") subchap1.SetMargins(0, 0, 5, 0) //subCh1 := NewSubchapter(ch1, "Workflow") @@ -2797,19 +2797,19 @@ func TestAllOptimizations(t *testing.T) { subchap1.Add(p) } - subchap2 := c.NewSubchapter(ch1, "Mechanism") + subchap2 := ch1.NewSubchapter("Mechanism") subchap2.SetMargins(0, 0, 5, 0) for j := 0; j < 15; j++ { subchap2.Add(p) } - subchap3 := c.NewSubchapter(ch1, "Discussion") + subchap3 := ch1.NewSubchapter("Discussion") subchap3.SetMargins(0, 0, 5, 0) for j := 0; j < 19; j++ { subchap3.Add(p) } - subchap4 := c.NewSubchapter(ch1, "Conclusion") + subchap4 := ch1.NewSubchapter("Conclusion") subchap4.SetMargins(0, 0, 5, 0) for j := 0; j < 23; j++ { subchap4.Add(p) From b92e7562d526e73bf0bd844d8cc963fbd47c14d7 Mon Sep 17 00:00:00 2001 From: Adrian-George Bostan Date: Wed, 6 Mar 2019 19:25:04 +0200 Subject: [PATCH 3/5] Fix toc and outline link destination coordinates on content page break --- pdf/creator/chapters.go | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/pdf/creator/chapters.go b/pdf/creator/chapters.go index 2e097aea..276ccedb 100644 --- a/pdf/creator/chapters.go +++ b/pdf/creator/chapters.go @@ -182,19 +182,17 @@ func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, ctx.Height -= chap.margins.top } - origX := ctx.X - origY := ctx.Y - - blocks, ctx, err := chap.heading.GeneratePageBlocks(ctx) + blocks, c, err := chap.heading.GeneratePageBlocks(ctx) if err != nil { return blocks, ctx, err } - if len(blocks) > 1 { - ctx.Page++ // Did not fit, moved to new Page block. - } + ctx = c // Generate chapter title and number. + posX := ctx.X + posY := ctx.Y - chap.heading.Height() page := int64(ctx.Page) + chapNumber := chap.headingNumber() chapTitle := chap.headingText() @@ -202,7 +200,7 @@ func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, if chap.includeInTOC { line := chap.toc.Add(chapNumber, chap.title, strconv.FormatInt(page, 10), chap.level) if chap.toc.showLinks { - line.SetLink(page, origX, origY) + line.SetLink(page, posX, posY) } } @@ -210,7 +208,7 @@ func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, if chap.outlineItem == nil { chap.outlineItem = model.NewOutlineItem( chapTitle, - model.NewOutlineDest(page-1, origX, origY), + model.NewOutlineDest(page-1, posX, posY), ) if chap.parent != nil { @@ -221,8 +219,8 @@ func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, } else { outlineDest := &chap.outlineItem.Dest outlineDest.Page = page - 1 - outlineDest.X = origX - outlineDest.Y = origY + outlineDest.X = posX + outlineDest.Y = posY } for _, d := range chap.contents { From b6819bc4918df5228e106aeb812923ddded86301 Mon Sep 17 00:00:00 2001 From: Adrian-George Bostan Date: Wed, 6 Mar 2019 19:32:00 +0200 Subject: [PATCH 4/5] Add multi-level subchapters to the creator test --- pdf/creator/creator_test.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pdf/creator/creator_test.go b/pdf/creator/creator_test.go index b3b86c36..f363e092 100644 --- a/pdf/creator/creator_test.go +++ b/pdf/creator/creator_test.go @@ -898,8 +898,6 @@ func TestSubchapters(t *testing.T) { subchap1 := ch1.NewSubchapter("The fundamentals") subchap1.SetMargins(0, 0, 5, 0) - //subCh1 := NewSubchapter(ch1, "Workflow") - p := c.NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " + "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore " + @@ -923,6 +921,15 @@ func TestSubchapters(t *testing.T) { subchap3.Add(p) } + // Create multi-level subchapters. + subchap := subchap3 + for i := 0; i < 5; i++ { + subchap = subchap.NewSubchapter(fmt.Sprintf("Discussion %d", i+1)) + for j := 0; j < 5; j++ { + subchap.Add(p) + } + } + subchap4 := ch1.NewSubchapter("Conclusion") subchap4.SetMargins(0, 0, 5, 0) for j := 0; j < 23; j++ { From 67451578ed97b13e0df37e8684d9b0b7d98ab74b Mon Sep 17 00:00:00 2001 From: Adrian-George Bostan Date: Wed, 6 Mar 2019 19:41:33 +0200 Subject: [PATCH 5/5] Improve code documentation --- pdf/creator/chapters.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/pdf/creator/chapters.go b/pdf/creator/chapters.go index 276ccedb..383d1091 100644 --- a/pdf/creator/chapters.go +++ b/pdf/creator/chapters.go @@ -17,9 +17,16 @@ import ( // Chapter is used to arrange multiple drawables (paragraphs, images, etc) into a single section. // The concept is the same as a book or a report chapter. type Chapter struct { - number int - title string - heading *Paragraph + // The number of the chapter. + number int + + // The title of the chapter. + title string + + // The heading paragraph of the chapter. + heading *Paragraph + + // The content components of the chapter. contents []Drawable // The number of subchapters the chapter has. @@ -83,7 +90,7 @@ func newChapter(parent *Chapter, toc *TOC, outline *model.Outline, title string, return chapter } -// NewSubchapter creates a new child chapter with specified heading. +// NewSubchapter creates a new child chapter with the specified title. func (chap *Chapter) NewSubchapter(title string) *Chapter { style := newTextStyle(chap.heading.textFont) style.FontSize = 14 @@ -142,6 +149,8 @@ func (chap *Chapter) Add(d Drawable) error { return nil } +// headingNumber returns the chapter heading number based on the chapter +// hierarchy and the showNumbering property. func (chap *Chapter) headingNumber() string { var chapNumber string if chap.showNumbering { @@ -160,6 +169,7 @@ func (chap *Chapter) headingNumber() string { return chapNumber } +// headingText returns the chapter heading text content. func (chap *Chapter) headingText() string { heading := chap.title if chapNumber := chap.headingNumber(); chapNumber != "" {