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), 201 B_TRANSLATE("line %d, column %d"), line, column); 202 fCellText[kPositionCell].SetTo(info); 203 } 204 205 if (B_OK == message->FindString("encoding", &fEncoding)) { 206 // sometime corresponding Int-32 "encoding" attrib is read as string :( 207 if (fEncoding.Length() == 0 208 || fEncoding.Compare("\xff\xff") == 0 209 || fEncoding.Compare("UTF-8") == 0) 210 { 211 // do not display default UTF-8 encoding 212 fCellText[kEncodingCell].Truncate(0); 213 fEncoding.Truncate(0); 214 } else { 215 const BCharacterSet* charset 216 = BCharacterSetRoster::FindCharacterSetByName(fEncoding); 217 fCellText[kEncodingCell] 218 = charset != NULL ? charset->GetPrintName() : ""; 219 } 220 } 221 222 bool modified = false; 223 fReadOnly = false; 224 fCanUnlock = false; 225 if (B_OK == message->FindBool("modified", &modified) && modified) { 226 fCellText[kFileStateCell] = B_TRANSLATE("Modified"); 227 } else if (B_OK == message->FindBool("readOnly", &fReadOnly) && fReadOnly) { 228 fCellText[kFileStateCell] = B_TRANSLATE("Read-only"); 229 if (B_OK == message->FindBool("canUnlock", &fCanUnlock) && fCanUnlock) 230 fCellText[kFileStateCell] << " " UTF8_EXPAND_ARROW; 231 } else 232 fCellText[kFileStateCell].Truncate(0); 233 234 _ValidatePreferredSize(); 235 Invalidate(); 236 } 237 238 239 void 240 StatusView::SetRef(const entry_ref& ref) 241 { 242 fRef = ref; 243 } 244 245 246 void 247 StatusView::_ValidatePreferredSize() 248 { 249 float orgWidth = fPreferredSize.width; 250 // width 251 fPreferredSize.width = 0.f; 252 for (size_t i = 0; i < kStatusCellCount; i++) { 253 if (fCellText[i].Length() == 0) { 254 fCellWidth[i] = 0; 255 continue; 256 } 257 float width = ceilf(StringWidth(fCellText[i])); 258 if (width > 0) 259 width += kHorzSpacing * 2; 260 if (width > fCellWidth[i] || i != kPositionCell) 261 fCellWidth[i] = width; 262 fPreferredSize.width += fCellWidth[i]; 263 } 264 265 // height 266 font_height fontHeight; 267 GetFontHeight(&fontHeight); 268 269 fPreferredSize.height = ceilf(fontHeight.ascent + fontHeight.descent 270 + fontHeight.leading); 271 272 if (fPreferredSize.height < B_H_SCROLL_BAR_HEIGHT) 273 fPreferredSize.height = B_H_SCROLL_BAR_HEIGHT; 274 275 float delta = fPreferredSize.width - orgWidth; 276 ResizeBy(delta, 0); 277 BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL); 278 scrollBar->ResizeBy(-delta, 0); 279 scrollBar->MoveBy(delta, 0); 280 } 281 282 283 void 284 StatusView::_ShowDirMenu() 285 { 286 BEntry entry; 287 status_t status = entry.SetTo(&fRef); 288 289 if (status != B_OK || !entry.Exists()) 290 return; 291 292 BPrivate::BDirMenu* menu = new BDirMenu(NULL, 293 BMessenger(kTrackerSignature), B_REFS_RECEIVED); 294 295 menu->Populate(&entry, Window(), false, false, true, false, true); 296 297 BPoint point = Bounds().LeftBottom(); 298 point.y += 3; 299 ConvertToScreen(&point); 300 BRect clickToOpenRect(Bounds()); 301 ConvertToScreen(&clickToOpenRect); 302 menu->Go(point, true, true, clickToOpenRect); 303 delete menu; 304 } 305 306