StyledEditView.cpp revision 31139022cd3056691fc8d6f64b2d9ffa9a101de3
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
26using namespace BPrivate;
27
28
29StyledEditView::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
40StyledEditView::~StyledEditView()
41{
42	delete fMessenger;
43}
44
45
46void
47StyledEditView::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
78status_t
79StyledEditView::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				fEncoding = 0;
97			} else {
98				const BCharacterSet* characterSet
99					= BCharacterSetRoster::GetCharacterSetByConversionID(encoding);
100				if (characterSet != 0)
101					fEncoding = characterSet->GetFontID();
102			}
103		}
104
105		// restore alignment
106		alignment align;
107		bytesRead = node->ReadAttr("alignment", 0, 0, &align, sizeof(align));
108		if (bytesRead == (ssize_t)sizeof(align))
109			SetAlignment(align);
110
111		// restore wrapping
112		bool wrap;
113		bytesRead = node->ReadAttr("wrap", 0, 0, &wrap, sizeof(wrap));
114		if (bytesRead == (ssize_t)sizeof(wrap)) {
115			SetWordWrap(wrap);
116			if (wrap == false) {
117				BRect textRect;
118				textRect = Bounds();
119				textRect.OffsetTo(B_ORIGIN);
120				textRect.InsetBy(TEXT_INSET, TEXT_INSET);
121					// the width comes from stylededit R5. TODO: find a better way
122				textRect.SetRightBottom(BPoint(1500.0, textRect.RightBottom().y));
123				SetTextRect(textRect);
124			}
125		}
126	}
127
128	if (fEncoding != 0) {
129		int32 length = stream->Seek(0, SEEK_END);
130
131		// Here we save the run_array before it gets overwritten...
132		text_run_array* runArray = RunArray(0, length);
133		uint32 id = BCharacterSetRoster::GetCharacterSetByFontID(fEncoding)->GetConversionID();
134
135		fSuppressChanges = true;
136		SetText("");
137		fSuppressChanges = false;
138
139		char inBuffer[32768];
140		off_t location = 0;
141		int32 textOffset = 0;
142		int32 state = 0;
143		int32 bytesRead;
144		while ((bytesRead = stream->ReadAt(location, inBuffer, sizeof(inBuffer))) > 0) {
145			char* inPtr = inBuffer;
146			char textBuffer[32768];
147			int32 textLength = sizeof(textBuffer);
148			int32 bytes = bytesRead;
149			while (textLength > 0 && bytes > 0) {
150				result = convert_to_utf8(id, inPtr, &bytes, textBuffer, &textLength, &state);
151				if (result != B_OK)
152					return result;
153
154				fSuppressChanges = true;
155				InsertText(textBuffer, textLength, textOffset);
156				fSuppressChanges = false;
157				textOffset += textLength;
158				inPtr += bytes;
159				location += bytes;
160				bytesRead -= bytes;
161				bytes = bytesRead;
162				if (textLength > 0)
163					textLength = sizeof(textBuffer);
164			}
165		}
166
167		// ... and here we restore it
168		SetRunArray(0, length, runArray);
169		free(runArray);
170	}
171
172	return result;
173}
174
175
176status_t
177StyledEditView::WriteStyledEditFile(BFile* file)
178{
179	status_t result = B_OK;
180	ssize_t bytes = 0;
181	result = BTranslationUtils::WriteStyledEditFile(this, file);
182	if (result != B_OK)
183		return result;
184
185	if (fEncoding == 0) {
186		int32 encoding = 65535;
187		bytes = file->WriteAttr("be:encoding", B_INT32_TYPE, 0, &encoding, sizeof(encoding));
188		if (bytes < 0)
189			return bytes;
190	} else {
191		result = file->SetSize(0);
192		if (result != B_OK)
193			return result;
194
195		bytes = file->Seek(0, SEEK_SET);
196		if (bytes != 0)
197			return bytes;
198
199		const BCharacterSet* cs = BCharacterSetRoster::GetCharacterSetByFontID(fEncoding);
200		if (cs != 0) {
201			uint32 id = cs->GetConversionID();
202			const char * outText = Text();
203			int32 sourceLength = TextLength();
204			int32 state = 0;
205			char buffer[32768];
206			while (sourceLength > 0) {
207				int32 length = sourceLength;
208				int32 written = 32768;
209				result = convert_from_utf8(id,outText,&length,buffer,&written,&state);
210				if (result != B_OK) {
211					return result;
212				}
213				bytes = file->Write(buffer,written);
214				if (bytes < 0)
215					return bytes;
216				sourceLength -= length;
217				outText += length;
218			}
219			bytes = file->WriteAttr("be:encoding", B_INT32_TYPE, 0, &id, sizeof(id));
220			if (bytes < 0)
221				return bytes;
222		}
223	}
224
225	alignment align = Alignment();
226	bytes = file->WriteAttr("alignment", B_INT32_TYPE, 0, &align, sizeof(align));
227	if (bytes < 0)
228		return bytes;
229
230	bool wrap = DoesWordWrap();
231	bytes = file->WriteAttr("wrap", B_BOOL_TYPE, 0, &wrap, sizeof(wrap));
232	if (bytes < 0)
233		return bytes;
234
235	return result;
236}
237
238
239void
240StyledEditView::Reset()
241{
242	fSuppressChanges = true;
243	SetText("");
244	fSuppressChanges = false;
245}
246
247
248void
249StyledEditView::Select(int32 start, int32 finish)
250{
251	fChangeMessage = new BMessage(start == finish ? DISABLE_ITEMS : ENABLE_ITEMS);
252	fMessenger->SendMessage(fChangeMessage);
253
254	BTextView::Select(start, finish);
255}
256
257
258void
259StyledEditView::SetEncoding(uint32 encoding)
260{
261	fEncoding = encoding;
262}
263
264
265uint32
266StyledEditView::GetEncoding() const
267{
268	return fEncoding;
269}
270
271
272void
273StyledEditView::InsertText(const char *text, int32 length, int32 offset,
274	const text_run_array *runs)
275{
276	if (!fSuppressChanges)
277		fMessenger->SendMessage(new BMessage(TEXT_CHANGED));
278
279	BTextView::InsertText(text, length, offset, runs);
280}
281
282
283void
284StyledEditView::DeleteText(int32 start, int32 finish)
285{
286	if (!fSuppressChanges)
287		fMessenger-> SendMessage(new BMessage(TEXT_CHANGED));
288
289	BTextView::DeleteText(start, finish);
290}
291
292