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