xref: /haiku/src/apps/stylededit/StyledEditView.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 /*
2  * Copyright 2002-2006, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Mattias Sundblad
7  *		Andrew Bachmann
8  */
9 
10 
11 #include "Constants.h"
12 #include "StyledEditView.h"
13 
14 #include <Message.h>
15 #include <Messenger.h>
16 #include <Rect.h>
17 #include <Region.h>
18 #include <TranslationUtils.h>
19 #include <Node.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <CharacterSet.h>
23 #include <CharacterSetRoster.h>
24 #include <UTF8.h>
25 
26 using namespace BPrivate;
27 
28 
29 StyledEditView::StyledEditView(BRect viewFrame, BRect textBounds, BHandler *handler)
30 	: BTextView(viewFrame, "textview", textBounds,
31 		B_FOLLOW_ALL, B_FRAME_EVENTS|B_WILL_DRAW)
32 {
33 	fHandler = handler;
34 	fMessenger = new BMessenger(handler);
35 	fSuppressChanges = false;
36 	fEncoding = 0;
37 }
38 
39 
40 StyledEditView::~StyledEditView()
41 {
42 	delete fMessenger;
43 }
44 
45 
46 void
47 StyledEditView::FrameResized(float width, float height)
48 {
49 	BTextView::FrameResized(width, height);
50 
51 	if (DoesWordWrap()) {
52 		BRect textRect;
53 		textRect = Bounds();
54 		textRect.OffsetTo(B_ORIGIN);
55 		textRect.InsetBy(TEXT_INSET, TEXT_INSET);
56 		SetTextRect(textRect);
57 	}
58 
59 /*	// I tried to do some sort of intelligent resize thing but it just doesn't work
60 	// so we revert to the R5 stylededit yucky practice of setting the text rect to
61 	// some crazy large number when word wrap is turned off :-(
62 	 else if (textRect.Width() > TextRect().Width()) {
63 		SetTextRect(textRect);
64 	}
65 
66 	BRegion region;
67 	GetTextRegion(0,TextLength(),&region);
68 	float textWidth = region.Frame().Width();
69 	if (textWidth < textRect.Width()) {
70 		BRect textRect(B_ORIGIN,BPoint(textWidth+TEXT_INSET*2,Bounds().Height()));
71 		textRect.InsetBy(TEXT_INSET,TEXT_INSET);
72 		SetTextRect(textRect);
73 	}
74 	*/
75 }
76 
77 
78 status_t
79 StyledEditView::GetStyledText(BPositionIO* stream)
80 {
81 	fSuppressChanges = true;
82 	status_t result = BTranslationUtils::GetStyledText(stream, this, NULL);
83 	fSuppressChanges = false;
84 
85 	if (result != B_OK)
86 		return result;
87 
88 	BNode* node = dynamic_cast<BNode*>(stream);
89 	if (node != NULL) {
90 		ssize_t bytesRead;
91 		// decode encoding
92 		int32 encoding;
93 		bytesRead = node->ReadAttr("be:encoding", 0, 0, &encoding, sizeof(encoding));
94 		if (bytesRead == (ssize_t)sizeof(encoding)) {
95 			if (encoding == 65535) {
96 				// UTF-8
97 				fEncoding = 0;
98 			} else {
99 				const BCharacterSet* characterSet
100 					= BCharacterSetRoster::GetCharacterSetByConversionID(encoding);
101 				if (characterSet != 0)
102 					fEncoding = characterSet->GetFontID();
103 			}
104 		}
105 
106 		// restore alignment
107 		int32 align;
108 		bytesRead = node->ReadAttr("alignment", 0, 0, &align, sizeof(align));
109 		if (bytesRead == (ssize_t)sizeof(align))
110 			SetAlignment((alignment)align);
111 
112 		// restore wrapping
113 		bool wrap;
114 		bytesRead = node->ReadAttr("wrap", 0, 0, &wrap, sizeof(wrap));
115 		if (bytesRead == (ssize_t)sizeof(wrap)) {
116 			SetWordWrap(wrap);
117 			if (wrap == false) {
118 				BRect textRect;
119 				textRect = Bounds();
120 				textRect.OffsetTo(B_ORIGIN);
121 				textRect.InsetBy(TEXT_INSET, TEXT_INSET);
122 					// the width comes from stylededit R5. TODO: find a better way
123 				textRect.SetRightBottom(BPoint(1500.0, textRect.RightBottom().y));
124 				SetTextRect(textRect);
125 			}
126 		}
127 	}
128 
129 	if (fEncoding != 0) {
130 		int32 length = stream->Seek(0, SEEK_END);
131 
132 		// Here we save the run_array before it gets overwritten...
133 		text_run_array* runArray = RunArray(0, length);
134 		uint32 id = BCharacterSetRoster::GetCharacterSetByFontID(fEncoding)->GetConversionID();
135 
136 		fSuppressChanges = true;
137 		SetText("");
138 		fSuppressChanges = false;
139 
140 		char inBuffer[32768];
141 		off_t location = 0;
142 		int32 textOffset = 0;
143 		int32 state = 0;
144 		int32 bytesRead;
145 		while ((bytesRead = stream->ReadAt(location, inBuffer, sizeof(inBuffer))) > 0) {
146 			char* inPtr = inBuffer;
147 			char textBuffer[32768];
148 			int32 textLength = sizeof(textBuffer);
149 			int32 bytes = bytesRead;
150 			while (textLength > 0 && bytes > 0) {
151 				result = convert_to_utf8(id, inPtr, &bytes, textBuffer, &textLength, &state);
152 				if (result != B_OK)
153 					return result;
154 
155 				fSuppressChanges = true;
156 				InsertText(textBuffer, textLength, textOffset);
157 				fSuppressChanges = false;
158 				textOffset += textLength;
159 				inPtr += bytes;
160 				location += bytes;
161 				bytesRead -= bytes;
162 				bytes = bytesRead;
163 				if (textLength > 0)
164 					textLength = sizeof(textBuffer);
165 			}
166 		}
167 
168 		// ... and here we restore it
169 		SetRunArray(0, length, runArray);
170 		FreeRunArray(runArray);
171 	}
172 
173 	return result;
174 }
175 
176 
177 status_t
178 StyledEditView::WriteStyledEditFile(BFile* file)
179 {
180 	status_t result = B_OK;
181 	ssize_t bytes = 0;
182 	result = BTranslationUtils::WriteStyledEditFile(this, file);
183 	if (result != B_OK)
184 		return result;
185 
186 	if (fEncoding == 0) {
187 		int32 encoding = 65535;
188 		bytes = file->WriteAttr("be:encoding", B_INT32_TYPE, 0, &encoding, sizeof(encoding));
189 		if (bytes < 0)
190 			return bytes;
191 	} else {
192 		result = file->SetSize(0);
193 		if (result != B_OK)
194 			return result;
195 
196 		bytes = file->Seek(0, SEEK_SET);
197 		if (bytes != 0)
198 			return bytes;
199 
200 		const BCharacterSet* cs = BCharacterSetRoster::GetCharacterSetByFontID(fEncoding);
201 		if (cs != 0) {
202 			uint32 id = cs->GetConversionID();
203 			const char * outText = Text();
204 			int32 sourceLength = TextLength();
205 			int32 state = 0;
206 			char buffer[32768];
207 			while (sourceLength > 0) {
208 				int32 length = sourceLength;
209 				int32 written = 32768;
210 				result = convert_from_utf8(id,outText,&length,buffer,&written,&state);
211 				if (result != B_OK) {
212 					return result;
213 				}
214 				bytes = file->Write(buffer,written);
215 				if (bytes < 0)
216 					return bytes;
217 				sourceLength -= length;
218 				outText += length;
219 			}
220 			bytes = file->WriteAttr("be:encoding", B_INT32_TYPE, 0, &id, sizeof(id));
221 			if (bytes < 0)
222 				return bytes;
223 		}
224 	}
225 
226 	int32 align = Alignment();
227 	bytes = file->WriteAttr("alignment", B_INT32_TYPE, 0, &align, sizeof(align));
228 	if (bytes < 0)
229 		return bytes;
230 
231 	bool wrap = DoesWordWrap();
232 	bytes = file->WriteAttr("wrap", B_BOOL_TYPE, 0, &wrap, sizeof(wrap));
233 	if (bytes < 0)
234 		return bytes;
235 
236 	return result;
237 }
238 
239 
240 void
241 StyledEditView::Reset()
242 {
243 	fSuppressChanges = true;
244 	SetText("");
245 	fSuppressChanges = false;
246 }
247 
248 
249 void
250 StyledEditView::Select(int32 start, int32 finish)
251 {
252 	fChangeMessage = new BMessage(start == finish ? DISABLE_ITEMS : ENABLE_ITEMS);
253 	fMessenger->SendMessage(fChangeMessage);
254 
255 	BTextView::Select(start, finish);
256 }
257 
258 
259 void
260 StyledEditView::SetEncoding(uint32 encoding)
261 {
262 	fEncoding = encoding;
263 }
264 
265 
266 uint32
267 StyledEditView::GetEncoding() const
268 {
269 	return fEncoding;
270 }
271 
272 
273 void
274 StyledEditView::InsertText(const char *text, int32 length, int32 offset,
275 	const text_run_array *runs)
276 {
277 	if (!fSuppressChanges)
278 		fMessenger->SendMessage(new BMessage(TEXT_CHANGED));
279 
280 	BTextView::InsertText(text, length, offset, runs);
281 }
282 
283 
284 void
285 StyledEditView::DeleteText(int32 start, int32 finish)
286 {
287 	if (!fSuppressChanges)
288 		fMessenger-> SendMessage(new BMessage(TEXT_CHANGED));
289 
290 	BTextView::DeleteText(start, finish);
291 }
292 
293