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