1 /*
2 ** Copyright 2003-2011, Double Precision Inc.
3 **
4 ** See COPYING for distribution information.
5 */
6 #ifndef curseseditmessage_H
7 #define curseseditmessage_H
8 
9 ///////////////////////////////////////////////////////////////////////////////
10 //
11 // The message editor
12 
13 #include "config.h"
14 #include "curses/cursescontainer.H"
15 #include "curses/curseskeyhandler.H"
16 #include "curses/cursesflowedline.H"
17 #include "libmail/objectmonitor.H"
18 #include <courier-unicode.h>
19 #include "spellcheckerbase.H"
20 #include <time.h>
21 
22 #include <vector>
23 #include <string>
24 
25 #define LINEW 77
26 
27 namespace mail {
28 	class Search;
29 }
30 
31 class CursesEditMessage : public Curses,
32 			  public CursesKeyHandler,
33 			  public mail::obj {
34 
35 	// Text that's being edited
36 
37 	std::vector<CursesFlowedLine> text_UTF8;
38 
39 public:
numLines()40 	size_t numLines() const { return text_UTF8.size(); }
41 	void getText(size_t line, std::u32string &textRef);
42 	void getText(size_t line, std::u32string &textRef,
43 		     bool &wrapped);
getText(size_t line,CursesFlowedLine & textRef)44 	void getText(size_t line, CursesFlowedLine &textRef)
45 	{
46 		textRef=line >= text_UTF8.size() ? CursesFlowedLine()
47 			: text_UTF8[line];
48 	}
49 
50 	// Retrieve text in its native UTF-8 format. Optionally append a
51 	// space if the line of text is flowed.
52 
53 	std::string getUTF8Text(size_t line,
54 				bool useflowedformat);
55 
56 private:
57 	void setText(size_t line, const std::u32string &textRef);
58 	void setText(size_t line, const CursesFlowedLine &textRef);
59 
60 	void getTextBeforeAfter(std::u32string &before,
61 				std::u32string &after);
62 
63 	void getTextBeforeAfter(std::u32string &before,
64 				std::u32string &after,
65 				bool &flowed);
66 
67 	void setTextBeforeAfter(const std::u32string &before,
68 				const std::u32string &after,
69 				bool flowed=false);
70 
71 	bool justifiable(size_t lineNum);
72 
73 	void insertKeyPos(char32_t key);
74 
75 	template<typename iter_type>
76 	void replaceTextLines(size_t start, size_t cnt,
77 			      iter_type beg_iter, iter_type end_iter);
78 
79 	template<typename iter_type>
80 	void replaceTextLinesImpl(size_t start, size_t cnt,
81 				  iter_type beg_iter, iter_type end_iter);
82 
83 	template<typename value_type>
84 	void replaceTextLine(size_t line, const value_type &value);
85 
86 	template<typename iter_category>
87 	class replace_text_lines_helper;
88 
89 	class get_file_helper;
90 
91 	class unicode_wordwrap_iterator;
92 	class unicode_wordwrap_rewrapper;
93 
94 	class unicode_wordwrap_oiterator;
95 public:
96 	template<typename iter_category>
97 	friend class replace_text_lines_helper;
98 private:
99 	//
100 	// Whenever cursor row changes, leaf wants to update the status bar.
101 	// Rather then remembering to call a function each time the cursor
102 	// row variable gets modified, the cursor row # is this object, which
103 	// automatically invokes cursorRowChanged() each time it's poked.
104 	//
105 
106 	class CursorRowUpdate {
107 
108 		size_t r;
109 	public:
110 		CursesEditMessage *me;
111 
CursorRowUpdate()112 		CursorRowUpdate() : r(0), me(NULL) {}
~CursorRowUpdate()113 		~CursorRowUpdate() {}
114 
size_t()115 		operator size_t()
116 		{
117 			return r;
118 		}
119 
120 		size_t operator=(size_t newRow)
121 		{
122 			r=newRow;
123 			if (me)
124 				me->cursorRowChanged();
125 			return r;
126 		}
127 
128 		size_t operator--()
129 		{
130 			return ((*this)=r-1);
131 		}
132 
133 		size_t operator++()
134 		{
135 			return ((*this)=r+1);
136 		}
137 
138 	};
139 
140 	CursorRowUpdate cursorRow;
141 	size_t cursorCol; // Current cursor column
142 	size_t cursorLineHorizShift; // Current horiz scroll offset
143 
144 	bool marked;	// Region being marked
145 	size_t markRow;	// The other end of the region.
146 	size_t markCursorPos;
147 
148 	std::string defaultSearchStr; // Prev search string
149 	std::string defaultReplaceStr; // Prev replace string
150 
151 	//
152 	// Given horizontal position #col, return an iterator to the character
153 	// in "line" that's shown at the given horizontal position.
154 	//
155 	std::u32string
156 	::iterator getIndexOfCol(std::u32string &line,
157 				 size_t col);
158 
159 	//
160 	// Same thing, except that the starting position of each character
161 	// in 'line' is precomputed in pos
162 	//
163 	static std::u32string
164 	::iterator getIndexOfCol(std::u32string &line,
165 				 std::vector<size_t> &pos,
166 				 size_t colNum);
167 
168 	// Return the horizontal location of the given character
169 
170 	static size_t getTextHorizPos(const std::u32string &line,
171 				      size_t column);
172 
173 	class SpellCheckerManager;
174 
175 public:
176 	virtual void cursorRowChanged();
177 
178 	CursesEditMessage(CursesContainer *parent);
179 	~CursesEditMessage();
180 
181 	static time_t autosaveInterval;
182 
183 	int getWidth() const;
184 	int getHeight() const;
185 
186 	void load(std::istream &i, bool isflowed, bool delsp);
187 	void save(std::ostream &o, bool isflowed);
188 	bool isFocusable();
189 	bool processKeyInFocus(const Key &key);
190 	int getCursorPosition(int &row, int &col);
191 
192 	void draw();
193 	void erase();
194 
195 	void enterKey();
196 
setCurrentLine(size_t row)197 	void setCurrentLine(size_t row)
198 	{
199 		if (row < numLines())
200 		{
201 			cursorRow=row;
202 			cursorCol=0;
203 		}
204 	}
205 
currentLine()206 	size_t currentLine() { return cursorRow; }
207 
208 private:
209 	virtual void macroDefined();
210 	void processMacroKey(std::string &repl_utf8);
211 
212 	void inserted();
213 	void drawLine(size_t lineNum);
214 	void left(bool);
215 	void right();
216 	void deleteChar(bool is_clreol_key);
217 	bool checkReplace(bool &, std::string &, SpellCheckerBase::Manager *);
218 	class ReplacePrompt;
219 
220 	bool search(bool doUpdate, bool doWrap, mail::Search &engine);
221 	void mark();
222 	void end();
223 
224 	void yank(const std::list<CursesFlowedLine> &yankText,
225 		  const std::string &chset,
226 		  bool doUpdate);
227 
228 	bool getMarkedRegion(size_t &row1, size_t &row2,
229 			     size_t &col1, size_t &col2);
230 
231 	static size_t colToPos(std::string &, std::vector<size_t> &, size_t,
232 			       bool);
233 
234 	Curses::Key lastKey;
235 	bool processKey(const Curses::Key &key);
236 	bool listKeys( std::vector< std::pair<std::string, std::string> >
237 		       &list);
238 
239 	virtual void modified()=0;
240 	virtual std::string getConfigDir();
241 	virtual void extedited();
242 
243 public:
244 	static std::string externalEditor;
245 };
246 
247 #endif
248