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