1 /* 2 * Copyright 2002-2012, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Vlad Slepukhin 7 * Siarzhuk Zharski 8 */ 9 10 11 #include "StatusView.h" 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include <Catalog.h> 18 #include <CharacterSet.h> 19 #include <CharacterSetRoster.h> 20 #include <ControlLook.h> 21 #include <MenuItem.h> 22 #include <Message.h> 23 #include <PopUpMenu.h> 24 #include <ScrollView.h> 25 #include <StringView.h> 26 #include <Window.h> 27 28 #include "Constants.h" 29 30 31 const float kHorzSpacing = 5.f; 32 #define UTF8_EXPAND_ARROW "\xe2\x96\xbe" 33 34 using namespace BPrivate; 35 36 37 #undef B_TRANSLATION_CONTEXT 38 #define B_TRANSLATION_CONTEXT "StatusView" 39 40 41 StatusView::StatusView(BScrollView* scrollView) 42 : 43 BView(BRect(), "statusview", 44 B_FOLLOW_BOTTOM | B_FOLLOW_LEFT, B_WILL_DRAW), 45 fScrollView(scrollView), 46 fPreferredSize(0., 0.), 47 fReadOnly(false) 48 { 49 memset(fCellWidth, 0, sizeof(fCellWidth)); 50 } 51 52 53 StatusView::~StatusView() 54 { 55 } 56 57 58 void 59 StatusView::AttachedToWindow() 60 { 61 SetFont(be_plain_font); 62 SetFontSize(10.); 63 64 BMessage message(UPDATE_STATUS); 65 message.AddInt32("line", 1); 66 message.AddInt32("column", 1); 67 message.AddString("encoding", ""); 68 SetStatus(&message); 69 70 BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL); 71 MoveTo(0., scrollBar->Frame().top); 72 73 rgb_color color = B_TRANSPARENT_COLOR; 74 BView* parent = Parent(); 75 if (parent != NULL) 76 color = parent->ViewColor(); 77 78 if (color == B_TRANSPARENT_COLOR) 79 color = ui_color(B_PANEL_BACKGROUND_COLOR); 80 81 SetViewColor(color); 82 83 ResizeToPreferred(); 84 } 85 86 87 void 88 StatusView::GetPreferredSize(float* _width, float* _height) 89 { 90 _ValidatePreferredSize(); 91 92 if (_width) 93 *_width = fPreferredSize.width; 94 95 if (_height) 96 *_height = fPreferredSize.height; 97 } 98 99 100 void 101 StatusView::ResizeToPreferred() 102 { 103 float width, height; 104 GetPreferredSize(&width, &height); 105 106 if (Bounds().Width() > width) 107 width = Bounds().Width(); 108 109 BView::ResizeTo(width, height); 110 } 111 112 113 void 114 StatusView::Draw(BRect updateRect) 115 { 116 if (fPreferredSize.width <= 0) 117 return; 118 119 if (be_control_look != NULL) { 120 BRect bounds(Bounds()); 121 be_control_look->DrawMenuBarBackground(this, 122 bounds, updateRect, ViewColor()); 123 } 124 125 BRect bounds(Bounds()); 126 rgb_color highColor = HighColor(); 127 SetHighColor(tint_color(ViewColor(), B_DARKEN_2_TINT)); 128 StrokeLine(bounds.LeftTop(), bounds.RightTop()); 129 130 float x = bounds.left; 131 for (size_t i = 0; i < kStatusCellCount - 1; i++) { 132 x += fCellWidth[i]; 133 StrokeLine(BPoint(x, bounds.top + 3), BPoint(x, bounds.bottom - 3)); 134 } 135 136 SetLowColor(ViewColor()); 137 SetHighColor(highColor); 138 139 font_height fontHeight; 140 GetFontHeight(&fontHeight); 141 142 x = bounds.left; 143 float y = (bounds.bottom + bounds.top 144 + ceilf(fontHeight.ascent) - ceilf(fontHeight.descent)) / 2; 145 146 for (size_t i = 0; i < kStatusCellCount; i++) { 147 if (fCellText[i].Length() == 0) 148 continue; 149 DrawString(fCellText[i], BPoint(x + kHorzSpacing, y)); 150 x += fCellWidth[i]; 151 } 152 } 153 154 155 void 156 StatusView::MouseDown(BPoint where) 157 { 158 if (!fReadOnly) 159 return; 160 161 float left = fCellWidth[kPositionCell] + fCellWidth[kEncodingCell]; 162 if (where.x < left) 163 return; 164 165 int32 clicks = 0; 166 BMessage* message = Window()->CurrentMessage(); 167 if (message != NULL 168 && message->FindInt32("clicks", &clicks) == B_OK && clicks > 1) 169 return; 170 171 BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false); 172 menu->AddItem(new BMenuItem(B_TRANSLATE("Unlock file"), 173 new BMessage(UNLOCK_FILE))); 174 where.x = left; 175 where.y = Bounds().bottom; 176 177 ConvertToScreen(&where); 178 menu->SetTargetForItems(this); 179 menu->Go(where, true, true, true); 180 } 181 182 183 void 184 StatusView::SetStatus(BMessage* message) 185 { 186 int32 line = 0, column = 0; 187 if (B_OK == message->FindInt32("line", &line) 188 && B_OK == message->FindInt32("column", &column)) 189 { 190 char info[256]; 191 snprintf(info, sizeof(info), 192 B_TRANSLATE("line %d, column %d"), line, column); 193 fCellText[kPositionCell].SetTo(info); 194 } 195 196 if (B_OK == message->FindString("encoding", &fEncoding)) { 197 // sometime corresponding Int-32 "encoding" attrib is read as string :( 198 if (fEncoding.Length() == 0 199 || fEncoding.Compare("\xff\xff") == 0 200 || fEncoding.Compare("UTF-8") == 0) 201 { 202 // do not display default UTF-8 encoding 203 fCellText[kEncodingCell].Truncate(0); 204 fEncoding.Truncate(0); 205 } else { 206 const BCharacterSet* charset 207 = BCharacterSetRoster::FindCharacterSetByName(fEncoding); 208 fCellText[kEncodingCell] 209 = charset != NULL ? charset->GetPrintName() : ""; 210 } 211 } 212 213 bool modified = false; 214 fReadOnly = false; 215 if (B_OK == message->FindBool("modified", &modified) && modified) { 216 fCellText[kFileStateCell] = B_TRANSLATE("Modified"); 217 } else if (B_OK == message->FindBool("readOnly", &fReadOnly) && fReadOnly) { 218 fCellText[kFileStateCell] = B_TRANSLATE("Read-only"); 219 fCellText[kFileStateCell] << " " UTF8_EXPAND_ARROW; 220 } else 221 fCellText[kFileStateCell].Truncate(0); 222 223 _ValidatePreferredSize(); 224 Invalidate(); 225 } 226 227 228 void 229 StatusView::_ValidatePreferredSize() 230 { 231 float orgWidth = fPreferredSize.width; 232 // width 233 fPreferredSize.width = 0.f; 234 for (size_t i = 0; i < kStatusCellCount; i++) { 235 if (fCellText[i].Length() == 0) { 236 fCellWidth[i] = 0; 237 continue; 238 } 239 float width = ceilf(StringWidth(fCellText[i])); 240 if (width > 0) 241 width += kHorzSpacing * 2; 242 if (width > fCellWidth[i] || i != kPositionCell) 243 fCellWidth[i] = width; 244 fPreferredSize.width += fCellWidth[i]; 245 } 246 247 // height 248 font_height fontHeight; 249 GetFontHeight(&fontHeight); 250 251 fPreferredSize.height = ceilf(fontHeight.ascent + fontHeight.descent 252 + fontHeight.leading); 253 254 if (fPreferredSize.height < B_H_SCROLL_BAR_HEIGHT) 255 fPreferredSize.height = B_H_SCROLL_BAR_HEIGHT; 256 257 float delta = fPreferredSize.width - orgWidth; 258 ResizeBy(delta, 0); 259 BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL); 260 scrollBar->ResizeBy(-delta, 0); 261 scrollBar->MoveBy(delta, 0); 262 } 263 264