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