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
StyledEditView(BRect viewFrame,BRect textBounds,BHandler * handler)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
~StyledEditView()48 StyledEditView::~StyledEditView()
49 {
50 delete fMessenger;
51 }
52
53
54 void
FrameResized(float width,float height)55 StyledEditView::FrameResized(float width, float height)
56 {
57 BTextView::FrameResized(width, height);
58 }
59
60
61 void
DeleteText(int32 start,int32 finish)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
InsertText(const char * text,int32 length,int32 offset,const text_run_array * runs)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
Select(int32 start,int32 finish)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
Reset()94 StyledEditView::Reset()
95 {
96 fSuppressChanges = true;
97 SetText("");
98 fEncoding = "";
99 fSuppressChanges = false;
100 }
101
102
103 void
SetSuppressChanges(bool suppressChanges)104 StyledEditView::SetSuppressChanges(bool suppressChanges)
105 {
106 fSuppressChanges = suppressChanges;
107 }
108
109
110 status_t
GetStyledText(BPositionIO * stream,const char * forceEncoding)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
WriteStyledEditFile(BFile * file)175 StyledEditView::WriteStyledEditFile(BFile* file)
176 {
177 return BTranslationUtils::WriteStyledEditFile(this, file,
178 fEncoding.String());
179 }
180
181
182 void
SetEncoding(uint32 encoding)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
GetEncoding() const198 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
_UpdateStatus()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