1 // Copyright (c) 2014-2020 Thomas Fussell
2 // Copyright (c) 2010-2015 openpyxl
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE
21 //
22 // @license: http://www.opensource.org/licenses/mit-license.php
23 // @author: see AUTHORS file
24 
25 #pragma once
26 
27 #include <cstdint>
28 #include <string>
29 #include <unordered_map>
30 
31 #include <xlnt/xlnt_config.hpp>
32 #include <xlnt/cell/rich_text.hpp>
33 #include <xlnt/utils/scoped_enum_hash.hpp>
34 
35 namespace xlnt {
36 
37 /// <summary>
38 /// Represents the header and footer of a sheet in a workbook.
39 /// </summary>
40 class XLNT_API header_footer
41 {
42 public:
43     /// <summary>
44     /// Enumerates the three possible locations of a header or footer.
45     /// </summary>
46     enum class location
47     {
48         left,
49         center,
50         right
51     };
52 
53     // General Properties
54 
55     /// <summary>
56     /// True if any text has been added for a header at any location on any page.
57     /// </summary>
58     bool has_header() const;
59 
60     /// <summary>
61     /// True if any text has been added for a footer at any location on any page.
62     /// </summary>
63     bool has_footer() const;
64 
65     /// <summary>
66     /// True if headers and footers should align to the page margins.
67     /// </summary>
68     bool align_with_margins() const;
69 
70     /// <summary>
71     /// Set to true if headers and footers should align to the page margins.
72     /// Set to false if headers and footers should align to the edge of the page.
73     /// </summary>
74     header_footer &align_with_margins(bool align);
75 
76     /// <summary>
77     /// True if headers and footers differ based on page number.
78     /// </summary>
79     bool different_odd_even() const;
80 
81     /// <summary>
82     /// True if headers and footers are different on the first page.
83     /// </summary>
84     bool different_first() const;
85 
86     /// <summary>
87     /// True if headers and footers should scale to match the worksheet.
88     /// </summary>
89     bool scale_with_doc() const;
90 
91     /// <summary>
92     /// Set to true if headers and footers should scale to match the worksheet.
93     /// </summary>
94     header_footer &scale_with_doc(bool scale);
95 
96     // Normal Header
97 
98     /// <summary>
99     /// True if any text has been added at the given location on any page.
100     /// </summary>
101     bool has_header(location where) const;
102 
103     /// <summary>
104     /// Remove all headers from all pages.
105     /// </summary>
106     void clear_header();
107 
108     /// <summary>
109     /// Remove header at the given location on any page.
110     /// </summary>
111     void clear_header(location where);
112 
113     /// <summary>
114     /// Add a header at the given location with the given text.
115     /// </summary>
116     header_footer &header(location where, const std::string &text);
117 
118     /// <summary>
119     /// Add a header at the given location with the given text.
120     /// </summary>
121     header_footer &header(location where, const rich_text &text);
122 
123     /// <summary>
124     /// Get the text of the  header at the given location. If headers are
125     /// different on odd and even pages, the odd header will be returned.
126     /// </summary>
127     rich_text header(location where) const;
128 
129     // First Page Header
130 
131     /// <summary>
132     /// True if a header has been set for the first page at any location.
133     /// </summary>
134     bool has_first_page_header() const;
135 
136     /// <summary>
137     /// True if a header has been set for the first page at the given location.
138     /// </summary>
139     bool has_first_page_header(location where) const;
140 
141     /// <summary>
142     /// Remove all headers from the first page.
143     /// </summary>
144     void clear_first_page_header();
145 
146     /// <summary>
147     /// Remove header from the first page at the given location.
148     /// </summary>
149     void clear_first_page_header(location where);
150 
151     /// <summary>
152     /// Add a header on the first page at the given location with the given text.
153     /// </summary>
154     header_footer &first_page_header(location where, const rich_text &text);
155 
156     /// <summary>
157     /// Get the text of the first page header at the given location. If no first
158     /// page header has been set, the general header for that location will
159     /// be returned.
160     /// </summary>
161     rich_text first_page_header(location where) const;
162 
163     // Odd/Even Header
164 
165     /// <summary>
166     /// True if different headers have been set for odd and even pages.
167     /// </summary>
168     bool has_odd_even_header() const;
169 
170     /// <summary>
171     /// True if different headers have been set for odd and even pages at the given location.
172     /// </summary>
173     bool has_odd_even_header(location where) const;
174 
175     /// <summary>
176     /// Remove odd/even headers at all locations.
177     /// </summary>
178     void clear_odd_even_header();
179 
180     /// <summary>
181     /// Remove odd/even headers at the given location.
182     /// </summary>
183     void clear_odd_even_header(location where);
184 
185     /// <summary>
186     /// Add a header for odd pages at the given location with the given text.
187     /// </summary>
188     header_footer &odd_even_header(location where, const rich_text &odd, const rich_text &even);
189 
190     /// <summary>
191     /// Get the text of the odd page header at the given location. If no odd
192     /// page header has been set, the general header for that location will
193     /// be returned.
194     /// </summary>
195     rich_text odd_header(location where) const;
196 
197     /// <summary>
198     /// Get the text of the even page header at the given location. If no even
199     /// page header has been set, the general header for that location will
200     /// be returned.
201     /// </summary>
202     rich_text even_header(location where) const;
203 
204     // Normal Footer
205 
206     /// <summary>
207     /// True if any text has been added at the given location on any page.
208     /// </summary>
209     bool has_footer(location where) const;
210 
211     /// <summary>
212     /// Remove all footers from all pages.
213     /// </summary>
214     void clear_footer();
215 
216     /// <summary>
217     /// Remove footer at the given location on any page.
218     /// </summary>
219     void clear_footer(location where);
220 
221     /// <summary>
222     /// Add a footer at the given location with the given text.
223     /// </summary>
224     header_footer &footer(location where, const std::string &text);
225 
226     /// <summary>
227     /// Add a footer at the given location with the given text.
228     /// </summary>
229     header_footer &footer(location where, const rich_text &text);
230 
231     /// <summary>
232     /// Get the text of the  footer at the given location. If footers are
233     /// different on odd and even pages, the odd footer will be returned.
234     /// </summary>
235     rich_text footer(location where) const;
236 
237     // First Page footer
238 
239     /// <summary>
240     /// True if a footer has been set for the first page at any location.
241     /// </summary>
242     bool has_first_page_footer() const;
243 
244     /// <summary>
245     /// True if a footer has been set for the first page at the given location.
246     /// </summary>
247     bool has_first_page_footer(location where) const;
248 
249     /// <summary>
250     /// Remove all footers from the first page.
251     /// </summary>
252     void clear_first_page_footer();
253 
254     /// <summary>
255     /// Remove footer from the first page at the given location.
256     /// </summary>
257     void clear_first_page_footer(location where);
258 
259     /// <summary>
260     /// Add a footer on the first page at the given location with the given text.
261     /// </summary>
262     header_footer &first_page_footer(location where, const rich_text &text);
263 
264     /// <summary>
265     /// Get the text of the first page footer at the given location. If no first
266     /// page footer has been set, the general footer for that location will
267     /// be returned.
268     /// </summary>
269     rich_text first_page_footer(location where) const;
270 
271     // Odd/Even Footer
272 
273     /// <summary>
274     /// True if different footers have been set for odd and even pages.
275     /// </summary>
276     bool has_odd_even_footer() const;
277 
278     /// <summary>
279     /// True if different footers have been set for odd and even pages at the given location.
280     /// </summary>
281     bool has_odd_even_footer(location where) const;
282 
283     /// <summary>
284     /// Remove odd/even footers at all locations.
285     /// </summary>
286     void clear_odd_even_footer();
287 
288     /// <summary>
289     /// Remove odd/even footers at the given location.
290     /// </summary>
291     void clear_odd_even_footer(location where);
292 
293     /// <summary>
294     /// Add a footer for odd pages at the given location with the given text.
295     /// </summary>
296     header_footer &odd_even_footer(location where, const rich_text &odd, const rich_text &even);
297 
298     /// <summary>
299     /// Get the text of the odd page footer at the given location. If no odd
300     /// page footer has been set, the general footer for that location will
301     /// be returned.
302     /// </summary>
303     rich_text odd_footer(location where) const;
304 
305     /// <summary>
306     /// Get the text of the even page footer at the given location. If no even
307     /// page footer has been set, the general footer for that location will
308     /// be returned.
309     /// </summary>
310     rich_text even_footer(location where) const;
311 
312     bool operator==(const header_footer &rhs) const;
313 
314 private:
315     bool align_with_margins_ = false;
316     bool different_odd_even_ = false;
317     bool scale_with_doc_ = false;
318 
319     using container = std::unordered_map<location, rich_text, scoped_enum_hash<location>>;
320 
321     container odd_headers_;
322     container even_headers_;
323     container first_headers_;
324     container odd_footers_;
325     container even_footers_;
326     container first_footers_;
327 };
328 
329 } // namespace xlnt
330