xref: /haiku/src/apps/stylededit/StyledEditView.cpp (revision c237c4ce593ee823d9867fd997e51e4c447f5623)
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, 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 
48 StyledEditView::~StyledEditView()
49 {
50 	delete fMessenger;
51 }
52 
53 
54 void
55 StyledEditView::FrameResized(float width, float height)
56 {
57 	BTextView::FrameResized(width, height);
58 }
59 
60 
61 void
62 StyledEditView::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 
72 void
73 StyledEditView::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 
84 void
85 StyledEditView::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 
93 void
94 StyledEditView::Reset()
95 {
96 	fSuppressChanges = true;
97 	SetText("");
98 	fEncoding = "";
99 	fSuppressChanges = false;
100 }
101 
102 
103 void
104 StyledEditView::SetSuppressChanges(bool suppressChanges)
105 {
106 	fSuppressChanges = suppressChanges;
107 }
108 
109 
110 status_t
111 StyledEditView::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 
174 status_t
175 StyledEditView::WriteStyledEditFile(BFile* file)
176 {
177 	return BTranslationUtils::WriteStyledEditFile(this, file,
178 		fEncoding.String());
179 }
180 
181 
182 void
183 StyledEditView::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 
197 uint32
198 StyledEditView::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 
212 void
213 StyledEditView::_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