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