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
54
55void
56StyledEditView::FrameResized(float width, float height)
57{
58	BTextView::FrameResized(width, height);
59
60	if (DoesWordWrap()) {
61		BRect textRect;
62		textRect = Bounds();
63		textRect.OffsetTo(B_ORIGIN);
64		textRect.InsetBy(TEXT_INSET, TEXT_INSET);
65		SetTextRect(textRect);
66	}
67}
68
69
70void
71StyledEditView::DeleteText(int32 start, int32 finish)
72{
73	if (!fSuppressChanges)
74		fMessenger-> SendMessage(TEXT_CHANGED);
75
76	BTextView::DeleteText(start, finish);
77	_UpdateStatus();
78}
79
80
81void
82StyledEditView::InsertText(const char* text, int32 length, int32 offset,
83	const text_run_array* runs)
84{
85	if (!fSuppressChanges)
86		fMessenger->SendMessage(TEXT_CHANGED);
87
88	BTextView::InsertText(text, length, offset, runs);
89	_UpdateStatus();
90}
91
92
93void
94StyledEditView::Select(int32 start, int32 finish)
95{
96	fMessenger->SendMessage(start == finish ? DISABLE_ITEMS : ENABLE_ITEMS);
97	BTextView::Select(start, finish);
98	_UpdateStatus();
99}
100
101
102void
103StyledEditView::Reset()
104{
105	fSuppressChanges = true;
106	SetText("");
107	fEncoding = "";
108	fSuppressChanges = false;
109}
110
111
112void
113StyledEditView::SetSuppressChanges(bool suppressChanges)
114{
115	fSuppressChanges = suppressChanges;
116}
117
118
119status_t
120StyledEditView::GetStyledText(BPositionIO* stream, const char* forceEncoding)
121{
122	if (forceEncoding != NULL)
123		fEncoding = strcmp(forceEncoding, "auto") != 0 ? forceEncoding : "";
124
125	fSuppressChanges = true;
126	status_t result = BTranslationUtils::GetStyledText(stream, this,
127		fEncoding.String());
128	fSuppressChanges = false;
129
130	if (result != B_OK)
131		return result;
132
133	BNode* node = dynamic_cast<BNode*>(stream);
134	if (node != NULL) {
135		if (forceEncoding == NULL) {
136			// get encoding
137			if (node->ReadAttrString("be:encoding", &fEncoding) != B_OK) {
138				// try to read as "int32"
139				int32 encoding;
140				ssize_t bytesRead = node->ReadAttr("be:encoding", B_INT32_TYPE, 0,
141					&encoding, sizeof(encoding));
142				if (bytesRead == (ssize_t)sizeof(encoding)) {
143					if (encoding == 65535) {
144						fEncoding = "UTF-8";
145					} else {
146						const BCharacterSet* characterSet
147							= BCharacterSetRoster::GetCharacterSetByConversionID(encoding);
148						if (characterSet != NULL)
149							fEncoding = characterSet->GetName();
150					}
151				}
152			}
153		}
154		// TODO: move those into BTranslationUtils::GetStyledText() as well?
155
156		// restore alignment
157		int32 align;
158		ssize_t bytesRead = node->ReadAttr("alignment", 0, 0, &align, sizeof(align));
159		if (bytesRead == (ssize_t)sizeof(align))
160			SetAlignment((alignment)align);
161
162		// restore wrapping
163		bool wrap;
164		bytesRead = node->ReadAttr("wrap", 0, 0, &wrap, sizeof(wrap));
165		if (bytesRead == (ssize_t)sizeof(wrap)) {
166			SetWordWrap(wrap);
167			if (wrap == false) {
168				BRect textRect;
169				textRect = Bounds();
170				textRect.OffsetTo(B_ORIGIN);
171				textRect.InsetBy(TEXT_INSET, TEXT_INSET);
172					// the width comes from stylededit R5. TODO: find a better way
173				textRect.SetRightBottom(BPoint(1500.0, textRect.RightBottom().y));
174				SetTextRect(textRect);
175			}
176		}
177	}
178
179	return result;
180}
181
182
183status_t
184StyledEditView::WriteStyledEditFile(BFile* file)
185{
186	return BTranslationUtils::WriteStyledEditFile(this, file,
187		fEncoding.String());
188}
189
190
191void
192StyledEditView::SetEncoding(uint32 encoding)
193{
194	fEncoding = "";
195	if (encoding == 0)
196		return;
197
198	const BCharacterSet* set
199		= BCharacterSetRoster::GetCharacterSetByFontID(encoding);
200
201	if (set != NULL)
202		fEncoding = set->GetName();
203}
204
205
206uint32
207StyledEditView::GetEncoding() const
208{
209	if (fEncoding == "")
210		return 0;
211
212	const BCharacterSet* set =
213		BCharacterSetRoster::FindCharacterSetByName(fEncoding.String());
214	if (set != NULL)
215		return set->GetFontID();
216
217	return 0;
218}
219
220
221void
222StyledEditView::_UpdateStatus()
223{
224	int32 selStart, selFinish;
225	GetSelection(&selStart, &selFinish);
226
227	int32 line = CurrentLine();
228	int32 lineStart = OffsetAt(line);
229
230	int32 column = 1;
231	int32 tabSize = (int32)ceilf(TabWidth() / StringWidth("s"));
232	for (int i = lineStart; i < selStart; i++) {
233		unsigned char ch = ByteAt(i);
234		if ((ch & 0xC0) != 0x80) {
235			if (ch == '\t')
236				while (column % tabSize)
237					column++;
238			column++;
239		}
240	}
241
242	BMessage* message = new BMessage(UPDATE_STATUS);
243	message->AddInt32("line", line + 1);
244	message->AddInt32("column", column);
245	message->AddString("encoding", fEncoding.String());
246	fMessenger->SendMessage(message);
247}
248