1/*
2 * Copyright 2002-2007, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Mattias Sundblad
7 *		Andrew Bachmann
8 *		Axel D��rfler, axeld@pinc-software.de
9 */
10
11
12#include "Constants.h"
13#include "StyledEditView.h"
14
15#include <CharacterSet.h>
16#include <CharacterSetRoster.h>
17#include <DataIO.h>
18#include <File.h>
19#include <Message.h>
20#include <Messenger.h>
21#include <Node.h>
22#include <Rect.h>
23#include <TranslationUtils.h>
24#include <UTF8.h>
25
26#include <stdio.h>
27#include <stdlib.h>
28
29
30using namespace BPrivate;
31
32
33StyledEditView::StyledEditView(BRect viewFrame, BRect textBounds,
34	BHandler* handler)
35	:
36	BTextView(viewFrame, "textview", textBounds, NULL,
37		&(fInitialColor = ui_color(B_DOCUMENT_TEXT_COLOR)),
38		B_FOLLOW_ALL, B_FRAME_EVENTS | B_WILL_DRAW)
39{
40	SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
41	SetLowUIColor(ViewUIColor());
42
43	fMessenger = new BMessenger(handler);
44	fSuppressChanges = false;
45}
46
47
48StyledEditView::~StyledEditView()
49{
50	delete fMessenger;
51}
52
53
54void
55StyledEditView::FrameResized(float width, float height)
56{
57	BTextView::FrameResized(width, height);
58}
59
60
61void
62StyledEditView::DeleteText(int32 start, int32 finish)
63{
64	if (!fSuppressChanges)
65		fMessenger-> SendMessage(TEXT_CHANGED);
66
67	BTextView::DeleteText(start, finish);
68	_UpdateStatus();
69}
70
71
72void
73StyledEditView::InsertText(const char* text, int32 length, int32 offset,
74	const text_run_array* runs)
75{
76	if (!fSuppressChanges)
77		fMessenger->SendMessage(TEXT_CHANGED);
78
79	BTextView::InsertText(text, length, offset, runs);
80	_UpdateStatus();
81}
82
83
84void
85StyledEditView::Select(int32 start, int32 finish)
86{
87	fMessenger->SendMessage(start == finish ? DISABLE_ITEMS : ENABLE_ITEMS);
88	BTextView::Select(start, finish);
89	_UpdateStatus();
90}
91
92
93void
94StyledEditView::Reset()
95{
96	fSuppressChanges = true;
97	SetText("");
98	fEncoding = "";
99	fSuppressChanges = false;
100}
101
102
103void
104StyledEditView::SetSuppressChanges(bool suppressChanges)
105{
106	fSuppressChanges = suppressChanges;
107}
108
109
110status_t
111StyledEditView::GetStyledText(BPositionIO* stream, const char* forceEncoding)
112{
113	if (forceEncoding != NULL)
114		fEncoding = strcmp(forceEncoding, "auto") != 0 ? forceEncoding : "";
115
116	fSuppressChanges = true;
117	status_t result = BTranslationUtils::GetStyledText(stream, this,
118		fEncoding.String());
119	fSuppressChanges = false;
120
121	if (result != B_OK)
122		return result;
123
124	BNode* node = dynamic_cast<BNode*>(stream);
125	if (node != NULL) {
126		if (forceEncoding == NULL) {
127			// get encoding
128			if (node->ReadAttrString("be:encoding", &fEncoding) != B_OK) {
129				// try to read as "int32"
130				int32 encoding;
131				ssize_t bytesRead = node->ReadAttr("be:encoding", B_INT32_TYPE, 0,
132					&encoding, sizeof(encoding));
133				if (bytesRead == (ssize_t)sizeof(encoding)) {
134					if (encoding == 65535) {
135						fEncoding = "UTF-8";
136					} else {
137						const BCharacterSet* characterSet
138							= BCharacterSetRoster::GetCharacterSetByConversionID(encoding);
139						if (characterSet != NULL)
140							fEncoding = characterSet->GetName();
141					}
142				}
143			}
144		}
145		// TODO: move those into BTranslationUtils::GetStyledText() as well?
146
147		// restore alignment
148		int32 align;
149		ssize_t bytesRead = node->ReadAttr("alignment", 0, 0, &align, sizeof(align));
150		if (bytesRead == (ssize_t)sizeof(align))
151			SetAlignment((alignment)align);
152
153		// restore wrapping
154		bool wrap;
155		bytesRead = node->ReadAttr("wrap", 0, 0, &wrap, sizeof(wrap));
156		if (bytesRead == (ssize_t)sizeof(wrap)) {
157			SetWordWrap(wrap);
158			if (wrap == false) {
159				BRect textRect;
160				textRect = Bounds();
161				textRect.OffsetTo(B_ORIGIN);
162				textRect.InsetBy(TEXT_INSET, TEXT_INSET);
163					// the width comes from stylededit R5. TODO: find a better way
164				textRect.SetRightBottom(BPoint(1500.0, textRect.RightBottom().y));
165				SetTextRect(textRect);
166			}
167		}
168	}
169
170	return result;
171}
172
173
174status_t
175StyledEditView::WriteStyledEditFile(BFile* file)
176{
177	return BTranslationUtils::WriteStyledEditFile(this, file,
178		fEncoding.String());
179}
180
181
182void
183StyledEditView::SetEncoding(uint32 encoding)
184{
185	fEncoding = "";
186	if (encoding == 0)
187		return;
188
189	const BCharacterSet* set
190		= BCharacterSetRoster::GetCharacterSetByFontID(encoding);
191
192	if (set != NULL)
193		fEncoding = set->GetName();
194}
195
196
197uint32
198StyledEditView::GetEncoding() const
199{
200	if (fEncoding == "")
201		return 0;
202
203	const BCharacterSet* set =
204		BCharacterSetRoster::FindCharacterSetByName(fEncoding.String());
205	if (set != NULL)
206		return set->GetFontID();
207
208	return 0;
209}
210
211
212void
213StyledEditView::_UpdateStatus()
214{
215	int32 selStart, selFinish;
216	GetSelection(&selStart, &selFinish);
217
218	int32 line = CurrentLine();
219	int32 lineStart = OffsetAt(line);
220
221	int32 column = 1;
222	int32 tabSize = (int32)ceilf(TabWidth() / StringWidth("s"));
223	for (int i = lineStart; i < selStart; i++) {
224		unsigned char ch = ByteAt(i);
225		if ((ch & 0xC0) != 0x80) {
226			if (ch == '\t')
227				while (column % tabSize)
228					column++;
229			column++;
230		}
231	}
232
233	BMessage* message = new BMessage(UPDATE_STATUS);
234	message->AddInt32("line", line + 1);
235	message->AddInt32("column", column);
236	message->AddString("encoding", fEncoding.String());
237	fMessenger->SendMessage(message);
238}
239