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