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