1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* libwps
3  * Version: MPL 2.0 / LGPLv2.1+
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * Major Contributor(s):
10  * Copyright (C) 2006, 2007 Andrew Ziem
11  * Copyright (C) 2006 Fridrich Strba (fridrich.strba@bluewin.ch)
12  * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca)
13  * Copyright (C) 2003 Marc Maurer (uwog@uwog.net)
14  *
15  * For minor contributions see the git repository.
16  *
17  * Alternatively, the contents of this file may be used under the terms
18  * of the GNU Lesser General Public License Version 2.1 or later
19  * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
20  * applicable instead of those above.
21  *
22  * For further information visit http://libwps.sourceforge.net
23  */
24 
25 #ifndef WKSCONTENTLISTENER_H
26 #define WKSCONTENTLISTENER_H
27 
28 #include <vector>
29 
30 #include <librevenge/librevenge.h>
31 
32 #include "libwps_internal.h"
33 
34 #include "WPSEntry.h"
35 #include "WPSGraphicStyle.h"
36 
37 #include "WPSListener.h"
38 
39 class WPSCellFormat;
40 class WKSChart;
41 struct WPSColumnFormat;
42 class WPSGraphicShape;
43 class WPSGraphicStyle;
44 class WPSList;
45 class WPSPageSpan;
46 struct WPSParagraph;
47 struct WPSRowFormat;
48 struct WPSTabStop;
49 
50 struct WKSContentParsingState;
51 struct WKSDocumentParsingState;
52 
53 class WKSContentListener final : public WPSListener
54 {
55 public:
56 	//! small class use to define a formula instruction
57 	struct FormulaInstruction
58 	{
59 		enum What { F_Operator, F_Function, F_Cell, F_CellList, F_Long, F_Double, F_Text };
60 		//! constructor
FormulaInstructionFormulaInstruction61 		FormulaInstruction()
62 			: m_type(F_Text)
63 			, m_content()
64 			, m_longValue(0)
65 			, m_doubleValue(0)
66 			, m_fileName()
67 		{
68 			for (auto &pos : m_position) pos=Vec2i(0,0);
69 			for (auto &pos : m_positionRelative) pos=Vec2b(false,false);
70 			for (auto &id : m_sheetId) id=-1;
71 		}
72 		//! return a proplist corresponding to a instruction
73 		librevenge::RVNGPropertyList getPropertyList() const;
74 		//! operator<<
75 		friend std::ostream &operator<<(std::ostream &o, FormulaInstruction const &inst);
76 		//! the type
77 		What m_type;
78 		//! the content ( if type == F_Operator or type = F_Function or type==F_Text)
79 		std::string m_content;
80 		//! value ( if type==F_Long )
81 		double m_longValue;
82 		//! value ( if type==F_Double )
83 		double m_doubleValue;
84 		//! cell position ( if type==F_Cell or F_CellList )
85 		Vec2i m_position[2];
86 		//! relative cell position ( if type==F_Cell or F_CellList )
87 		Vec2b m_positionRelative[2];
88 		//! the sheet name
89 		librevenge::RVNGString m_sheetName[2];
90 		/** the sheet id
91 
92 			\note local field which can be used to store the sheet id
93 			before setting the sheet name */
94 		int m_sheetId[2];
95 		//! the file name (external reference)
96 		librevenge::RVNGString m_fileName;
97 	};
98 	//! small class use to define a sheet cell content
99 	struct CellContent
100 	{
101 		/** the different types of cell's field */
102 		enum ContentType { C_NONE, C_TEXT, C_NUMBER, C_FORMULA, C_UNKNOWN };
103 		/// constructor
CellContentCellContent104 		CellContent()
105 			: m_contentType(C_UNKNOWN)
106 			, m_value(0.0)
107 			, m_valueSet(false)
108 			, m_textEntry()
109 			, m_formula() { }
110 		CellContent(CellContent const &)=default;
111 		CellContent &operator=(CellContent const &)=default;
112 		/// destructor
~CellContentCellContent113 		~CellContent() {}
114 		//! operator<<
115 		friend std::ostream &operator<<(std::ostream &o, CellContent const &cell);
116 
117 		//! returns true if the cell has no content
emptyCellContent118 		bool empty() const
119 		{
120 			if (m_contentType == C_NUMBER) return false;
121 			if (m_contentType == C_TEXT && !m_textEntry.valid()) return false;
122 			if (m_contentType == C_FORMULA && (m_formula.size() || isValueSet())) return false;
123 			return true;
124 		}
125 		//! sets the double value
setValueCellContent126 		void setValue(double value)
127 		{
128 			m_value = value;
129 			m_valueSet = true;
130 		}
131 		//! returns true if the value has been setted
isValueSetCellContent132 		bool isValueSet() const
133 		{
134 			return m_valueSet;
135 		}
136 		//! returns true if the text is set
hasTextCellContent137 		bool hasText() const
138 		{
139 			return m_textEntry.valid();
140 		}
141 		/** conversion beetween double days since 1900 and date */
142 		static bool double2Date(double val, int &Y, int &M, int &D);
143 		/** conversion beetween double: second since 0:00 and time */
144 		static bool double2Time(double val, int &H, int &M, int &S);
145 
146 		//! the content type ( by default unknown )
147 		ContentType m_contentType;
148 		//! the cell value
149 		double m_value;
150 		//! true if the value has been set
151 		bool m_valueSet;
152 		//! the cell string
153 		WPSEntry m_textEntry;
154 		//! the formula list of instruction
155 		std::vector<FormulaInstruction> m_formula;
156 	};
157 
158 	WKSContentListener(std::vector<WPSPageSpan> const &pageList, librevenge::RVNGSpreadsheetInterface *documentInterface);
159 	~WKSContentListener() final;
160 
161 	void setDocumentLanguage(int lcid) final;
162 	void setMetaData(const librevenge::RVNGPropertyList &list);
163 
164 	void startDocument();
165 	void endDocument();
166 	void handleSubDocument(WPSSubDocumentPtr &subDocument, libwps::SubDocumentType subDocumentType);
167 
168 	// ------ text data -----------
169 
170 	//! adds a basic character, ..
171 	void insertCharacter(uint8_t character) final;
172 	/** adds an unicode character
173 	 *
174 	 * by convention if \a character=0xfffd(undef), no character is added */
175 	void insertUnicode(uint32_t character) final;
176 	//! adds a unicode string
177 	void insertUnicodeString(librevenge::RVNGString const &str) final;
178 
179 	void insertTab() final;
180 	void insertEOL(bool softBreak=false) final;
181 	void insertBreak(const uint8_t breakType) final;
182 
183 	// ------ text format -----------
184 	//! set the actual font
185 	void setFont(const WPSFont &font) final;
186 	//! returns the actual font
187 	WPSFont const &getFont() const final;
188 
189 	// ------ paragraph format -----------
190 	//! returns true if a paragraph or a list is opened
191 	bool isParagraphOpened() const final;
192 	//! sets the actual paragraph
193 	void setParagraph(const WPSParagraph &para) final;
194 	//! returns the actual paragraph
195 	WPSParagraph const &getParagraph() const final;
196 
197 	// ------- fields ----------------
198 	//! adds a field
199 	void insertField(WPSField const &field) final;
200 
201 	// ------- subdocument -----------------
202 	/** adds comment */
203 	void insertComment(WPSSubDocumentPtr &subDocument);
204 	/** adds a picture in given position */
205 	void insertPicture(WPSPosition const &pos, const librevenge::RVNGBinaryData &binaryData,
206 	                   std::string type="image/pict", WPSGraphicStyle const &style=WPSGraphicStyle::emptyStyle());
207 	/** adds an object with replacement picture in given position */
208 	void insertObject(WPSPosition const &pos, const WPSEmbeddedObject &obj,
209 	                  WPSGraphicStyle const &style=WPSGraphicStyle::emptyStyle());
210 	/** adds a picture in given position */
211 	void insertPicture(WPSPosition const &pos, WPSGraphicShape const &shape, WPSGraphicStyle const &style);
212 	/** adds a textbox in given position */
213 	void insertTextBox(WPSPosition const &pos, WPSSubDocumentPtr subDocument,
214 	                   WPSGraphicStyle const &frameStyle=WPSGraphicStyle::emptyStyle());
215 	/** open a group (not implemented) */
216 	bool openGroup(WPSPosition const &pos) final;
217 	/** close a group (not implemented) */
218 	void closeGroup() final;
219 
220 	// ------- sheet -----------------
221 	/** open a sheet*/
222 	void openSheet(std::vector<WPSColumnFormat> const &columns, librevenge::RVNGString const &name="");
223 	/** closes this sheet */
224 	void closeSheet();
225 	/** open a row */
226 	void openSheetRow(WPSRowFormat const &f, int numRepeated=1);
227 	/** closes this row */
228 	void closeSheetRow();
229 	/** low level function to define a cell.
230 		\param cell the cell position, alignement, ...
231 		\param content the cell content
232 		\param numRepeated the cell columns repeatition*/
233 	void openSheetCell(WPSCell const &cell, CellContent const &content, int numRepeated=1);
234 	/** close a cell */
235 	void closeSheetCell();
236 
237 	// ------- chart -----------------
238 	/** adds a chart in given position */
239 	void insertChart(WPSPosition const &pos, WKSChart const &chart,
240 	                 WPSGraphicStyle const &style=WPSGraphicStyle::emptyStyle());
241 protected:
242 	void _openPageSpan();
243 	void _closePageSpan();
244 
245 	void _handleFrameParameters(librevenge::RVNGPropertyList &propList, WPSPosition const &pos);
246 	bool _openFrame(WPSPosition const &pos, WPSGraphicStyle const &style);
247 	void _closeFrame();
248 
249 	void _startSubDocument();
250 	void _endSubDocument();
251 
252 	void _openParagraph();
253 	void _closeParagraph();
254 	void _appendParagraphProperties(librevenge::RVNGPropertyList &propList, const bool isListElement=false);
255 	void _resetParagraphState(const bool isListElement=false);
256 
257 	void _openSpan();
258 	void _closeSpan();
259 
260 	void _flushText();
261 	void _flushDeferredTabs();
262 
263 	void _insertBreakIfNecessary(librevenge::RVNGPropertyList &propList);
264 
265 	/** creates a new parsing state (copy of the actual state)
266 	 *
267 	 * \return the old one */
268 	std::shared_ptr<WKSContentParsingState> _pushParsingState();
269 	//! resets the previous parsing state
270 	void _popParsingState();
271 
272 protected:
273 	std::shared_ptr<WKSDocumentParsingState> m_ds; // main parse state
274 	std::shared_ptr<WKSContentParsingState> m_ps; // parse state
275 	std::vector<std::shared_ptr<WKSContentParsingState> > m_psStack;
276 	librevenge::RVNGSpreadsheetInterface *m_documentInterface;
277 
278 private:
279 	WKSContentListener(const WKSContentListener &) = delete;
280 	WKSContentListener &operator=(const WKSContentListener &) = delete;
281 };
282 
283 #endif
284 /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
285