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 <tracker_private.h> 29 #include "DirMenu.h" 30 31 #include "Constants.h" 32 33 34 const float kHorzSpacing = 5.f; 35 #define UTF8_EXPAND_ARROW "\xe2\x96\xbe" 36 37 using namespace BPrivate; 38 39 40 #undef B_TRANSLATION_CONTEXT 41 #define B_TRANSLATION_CONTEXT "StatusView" 42 43 44 StatusView::StatusView(BScrollView* scrollView) 45 : 46 BView(BRect(), "statusview", 47 B_FOLLOW_BOTTOM | B_FOLLOW_LEFT, B_WILL_DRAW), 48 fScrollView(scrollView), 49 fPreferredSize(0., 0.), 50 fReadOnly(false), 51 fCanUnlock(false) 52 { 53 memset(fCellWidth, 0, sizeof(fCellWidth)); 54 } 55 56 57 StatusView::~StatusView() 58 { 59 } 60 61 62 void 63 StatusView::AttachedToWindow() 64 { 65 SetFont(be_plain_font); 66 SetFontSize(ceilf(be_plain_font->Size() * 0.83f)); 67 68 BMessage message(UPDATE_STATUS); 69 message.AddInt32("line", 1); 70 message.AddInt32("column", 1); 71 message.AddString("encoding", ""); 72 SetStatus(&message); 73 74 BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL); 75 MoveTo(0., scrollBar->Frame().top); 76 77 rgb_color color = B_TRANSPARENT_COLOR; 78 BView* parent = Parent(); 79 if (parent != NULL) 80 color = parent->ViewColor(); 81 82 if (color == B_TRANSPARENT_COLOR) 83 color = ui_color(B_PANEL_BACKGROUND_COLOR); 84 85 SetViewColor(color); 86 87 ResizeToPreferred(); 88 } 89 90 91 void 92 StatusView::GetPreferredSize(float* _width, float* _height) 93 { 94 _ValidatePreferredSize(); 95 96 if (_width) 97 *_width = fPreferredSize.width; 98 99 if (_height) 100 *_height = fPreferredSize.height; 101 } 102 103 104 void 105 StatusView::ResizeToPreferred() 106 { 107 float width, height; 108 GetPreferredSize(&width, &height); 109 110 if (Bounds().Width() > width) 111 width = Bounds().Width(); 112 113 BView::ResizeTo(width, height); 114 } 115 116 117 void 118 StatusView::Draw(BRect updateRect) 119 { 120 if (fPreferredSize.width <= 0) 121 return; 122 123 if (be_control_look != NULL) { 124 BRect bounds(Bounds()); 125 be_control_look->DrawMenuBarBackground(this, 126 bounds, updateRect, ViewColor()); 127 } 128 129 BRect bounds(Bounds()); 130 SetHighColor(tint_color(ViewColor(), B_DARKEN_2_TINT)); 131 StrokeLine(bounds.LeftTop(), bounds.RightTop()); 132 133 float x = bounds.left; 134 for (size_t i = 0; i < kStatusCellCount - 1; i++) { 135 x += fCellWidth[i]; 136 StrokeLine(BPoint(x, bounds.top + 3), BPoint(x, bounds.bottom - 3)); 137 } 138 139 SetLowColor(ViewColor()); 140 SetHighColor(ui_color(B_PANEL_TEXT_COLOR)); 141 142 font_height fontHeight; 143 GetFontHeight(&fontHeight); 144 145 x = bounds.left; 146 float y = (bounds.bottom + bounds.top 147 + ceilf(fontHeight.ascent) - ceilf(fontHeight.descent)) / 2; 148 149 for (size_t i = 0; i < kStatusCellCount; i++) { 150 if (fCellText[i].Length() == 0) 151 continue; 152 DrawString(fCellText[i], BPoint(x + kHorzSpacing, y)); 153 x += fCellWidth[i]; 154 } 155 } 156 157 158 void 159 StatusView::MouseDown(BPoint where) 160 { 161 if (where.x < fCellWidth[kPositionCell]) { 162 _ShowDirMenu(); 163 return; 164 } 165 166 if (!fReadOnly || !fCanUnlock) 167 return; 168 169 float left = fCellWidth[kPositionCell] + fCellWidth[kEncodingCell]; 170 if (where.x < left) 171 return; 172 173 int32 clicks = 0; 174 BMessage* message = Window()->CurrentMessage(); 175 if (message != NULL 176 && message->FindInt32("clicks", &clicks) == B_OK && clicks > 1) 177 return; 178 179 BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false); 180 menu->AddItem(new BMenuItem(B_TRANSLATE("Unlock file"), 181 new BMessage(UNLOCK_FILE))); 182 where.x = left; 183 where.y = Bounds().bottom; 184 185 ConvertToScreen(&where); 186 menu->SetTargetForItems(this); 187 menu->Go(where, true, true, true); 188 } 189 190 191 void 192 StatusView::SetStatus(BMessage* message) 193 { 194 int32 line = 0, column = 0; 195 if (B_OK == message->FindInt32("line", &line) 196 && B_OK == message->FindInt32("column", &column)) 197 { 198 char info[256]; 199 snprintf(info, sizeof(info), 200 B_TRANSLATE("line %d, column %d"), line, 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