1 /* 2 * Copyright 2002-2006, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Mattias Sundblad 7 * Andrew Bachmann 8 */ 9 10 11 #include "Constants.h" 12 #include "StyledEditView.h" 13 14 #include <Message.h> 15 #include <Messenger.h> 16 #include <Rect.h> 17 #include <Region.h> 18 #include <TranslationUtils.h> 19 #include <Node.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <CharacterSet.h> 23 #include <CharacterSetRoster.h> 24 #include <UTF8.h> 25 26 using namespace BPrivate; 27 28 29 StyledEditView::StyledEditView(BRect viewFrame, BRect textBounds, BHandler *handler) 30 : BTextView(viewFrame, "textview", textBounds, 31 B_FOLLOW_ALL, B_FRAME_EVENTS|B_WILL_DRAW) 32 { 33 fHandler = handler; 34 fMessenger = new BMessenger(handler); 35 fSuppressChanges = false; 36 fEncoding = 0; 37 } 38 39 40 StyledEditView::~StyledEditView() 41 { 42 delete fMessenger; 43 } 44 45 46 void 47 StyledEditView::FrameResized(float width, float height) 48 { 49 BTextView::FrameResized(width, height); 50 51 if (DoesWordWrap()) { 52 BRect textRect; 53 textRect = Bounds(); 54 textRect.OffsetTo(B_ORIGIN); 55 textRect.InsetBy(TEXT_INSET, TEXT_INSET); 56 SetTextRect(textRect); 57 } 58 59 /* // I tried to do some sort of intelligent resize thing but it just doesn't work 60 // so we revert to the R5 stylededit yucky practice of setting the text rect to 61 // some crazy large number when word wrap is turned off :-( 62 else if (textRect.Width() > TextRect().Width()) { 63 SetTextRect(textRect); 64 } 65 66 BRegion region; 67 GetTextRegion(0,TextLength(),®ion); 68 float textWidth = region.Frame().Width(); 69 if (textWidth < textRect.Width()) { 70 BRect textRect(B_ORIGIN,BPoint(textWidth+TEXT_INSET*2,Bounds().Height())); 71 textRect.InsetBy(TEXT_INSET,TEXT_INSET); 72 SetTextRect(textRect); 73 } 74 */ 75 } 76 77 78 status_t 79 StyledEditView::GetStyledText(BPositionIO* stream) 80 { 81 fSuppressChanges = true; 82 status_t result = BTranslationUtils::GetStyledText(stream, this, NULL); 83 fSuppressChanges = false; 84 85 if (result != B_OK) 86 return result; 87 88 BNode* node = dynamic_cast<BNode*>(stream); 89 if (node != NULL) { 90 ssize_t bytesRead; 91 // decode encoding 92 int32 encoding; 93 bytesRead = node->ReadAttr("be:encoding", 0, 0, &encoding, sizeof(encoding)); 94 if (bytesRead == (ssize_t)sizeof(encoding)) { 95 if (encoding == 65535) { 96 // UTF-8 97 fEncoding = 0; 98 } else { 99 const BCharacterSet* characterSet 100 = BCharacterSetRoster::GetCharacterSetByConversionID(encoding); 101 if (characterSet != 0) 102 fEncoding = characterSet->GetFontID(); 103 } 104 } 105 106 // restore alignment 107 int32 align; 108 bytesRead = node->ReadAttr("alignment", 0, 0, &align, sizeof(align)); 109 if (bytesRead == (ssize_t)sizeof(align)) 110 SetAlignment((alignment)align); 111 112 // restore wrapping 113 bool wrap; 114 bytesRead = node->ReadAttr("wrap", 0, 0, &wrap, sizeof(wrap)); 115 if (bytesRead == (ssize_t)sizeof(wrap)) { 116 SetWordWrap(wrap); 117 if (wrap == false) { 118 BRect textRect; 119 textRect = Bounds(); 120 textRect.OffsetTo(B_ORIGIN); 121 textRect.InsetBy(TEXT_INSET, TEXT_INSET); 122 // the width comes from stylededit R5. TODO: find a better way 123 textRect.SetRightBottom(BPoint(1500.0, textRect.RightBottom().y)); 124 SetTextRect(textRect); 125 } 126 } 127 } 128 129 if (fEncoding != 0) { 130 int32 length = stream->Seek(0, SEEK_END); 131 132 // Here we save the run_array before it gets overwritten... 133 text_run_array* runArray = RunArray(0, length); 134 uint32 id = BCharacterSetRoster::GetCharacterSetByFontID(fEncoding)->GetConversionID(); 135 136 fSuppressChanges = true; 137 SetText(""); 138 fSuppressChanges = false; 139 140 char inBuffer[32768]; 141 off_t location = 0; 142 int32 textOffset = 0; 143 int32 state = 0; 144 int32 bytesRead; 145 while ((bytesRead = stream->ReadAt(location, inBuffer, sizeof(inBuffer))) > 0) { 146 char* inPtr = inBuffer; 147 char textBuffer[32768]; 148 int32 textLength = sizeof(textBuffer); 149 int32 bytes = bytesRead; 150 while (textLength > 0 && bytes > 0) { 151 result = convert_to_utf8(id, inPtr, &bytes, textBuffer, &textLength, &state); 152 if (result != B_OK) 153 return result; 154 155 fSuppressChanges = true; 156 InsertText(textBuffer, textLength, textOffset); 157 fSuppressChanges = false; 158 textOffset += textLength; 159 inPtr += bytes; 160 location += bytes; 161 bytesRead -= bytes; 162 bytes = bytesRead; 163 if (textLength > 0) 164 textLength = sizeof(textBuffer); 165 } 166 } 167 168 // ... and here we restore it 169 SetRunArray(0, length, runArray); 170 FreeRunArray(runArray); 171 } 172 173 return result; 174 } 175 176 177 status_t 178 StyledEditView::WriteStyledEditFile(BFile* file) 179 { 180 status_t result = B_OK; 181 ssize_t bytes = 0; 182 result = BTranslationUtils::WriteStyledEditFile(this, file); 183 if (result != B_OK) 184 return result; 185 186 if (fEncoding == 0) { 187 int32 encoding = 65535; 188 bytes = file->WriteAttr("be:encoding", B_INT32_TYPE, 0, &encoding, sizeof(encoding)); 189 if (bytes < 0) 190 return bytes; 191 } else { 192 result = file->SetSize(0); 193 if (result != B_OK) 194 return result; 195 196 bytes = file->Seek(0, SEEK_SET); 197 if (bytes != 0) 198 return bytes; 199 200 const BCharacterSet* cs = BCharacterSetRoster::GetCharacterSetByFontID(fEncoding); 201 if (cs != 0) { 202 uint32 id = cs->GetConversionID(); 203 const char * outText = Text(); 204 int32 sourceLength = TextLength(); 205 int32 state = 0; 206 char buffer[32768]; 207 while (sourceLength > 0) { 208 int32 length = sourceLength; 209 int32 written = 32768; 210 result = convert_from_utf8(id,outText,&length,buffer,&written,&state); 211 if (result != B_OK) { 212 return result; 213 } 214 bytes = file->Write(buffer,written); 215 if (bytes < 0) 216 return bytes; 217 sourceLength -= length; 218 outText += length; 219 } 220 bytes = file->WriteAttr("be:encoding", B_INT32_TYPE, 0, &id, sizeof(id)); 221 if (bytes < 0) 222 return bytes; 223 } 224 } 225 226 int32 align = Alignment(); 227 bytes = file->WriteAttr("alignment", B_INT32_TYPE, 0, &align, sizeof(align)); 228 if (bytes < 0) 229 return bytes; 230 231 bool wrap = DoesWordWrap(); 232 bytes = file->WriteAttr("wrap", B_BOOL_TYPE, 0, &wrap, sizeof(wrap)); 233 if (bytes < 0) 234 return bytes; 235 236 return result; 237 } 238 239 240 void 241 StyledEditView::Reset() 242 { 243 fSuppressChanges = true; 244 SetText(""); 245 fSuppressChanges = false; 246 } 247 248 249 void 250 StyledEditView::Select(int32 start, int32 finish) 251 { 252 fChangeMessage = new BMessage(start == finish ? DISABLE_ITEMS : ENABLE_ITEMS); 253 fMessenger->SendMessage(fChangeMessage); 254 255 BTextView::Select(start, finish); 256 } 257 258 259 void 260 StyledEditView::SetEncoding(uint32 encoding) 261 { 262 fEncoding = encoding; 263 } 264 265 266 uint32 267 StyledEditView::GetEncoding() const 268 { 269 return fEncoding; 270 } 271 272 273 void 274 StyledEditView::InsertText(const char *text, int32 length, int32 offset, 275 const text_run_array *runs) 276 { 277 if (!fSuppressChanges) 278 fMessenger->SendMessage(new BMessage(TEXT_CHANGED)); 279 280 BTextView::InsertText(text, length, offset, runs); 281 } 282 283 284 void 285 StyledEditView::DeleteText(int32 start, int32 finish) 286 { 287 if (!fSuppressChanges) 288 fMessenger-> SendMessage(new BMessage(TEXT_CHANGED)); 289 290 BTextView::DeleteText(start, finish); 291 } 292 293