1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 36 #include "HeaderView.h" 37 38 #include <Alert.h> 39 #include <Application.h> 40 #include <Catalog.h> 41 #include <Locale.h> 42 #include <PopUpMenu.h> 43 #include <ScrollView.h> 44 #include <Volume.h> 45 #include <VolumeRoster.h> 46 #include <Window.h> 47 48 #include "Commands.h" 49 #include "FSUtils.h" 50 #include "GeneralInfoView.h" 51 #include "IconMenuItem.h" 52 #include "Model.h" 53 #include "NavMenu.h" 54 #include "PoseView.h" 55 #include "Tracker.h" 56 57 58 #undef B_TRANSLATION_CONTEXT 59 #define B_TRANSLATION_CONTEXT "InfoWindow" 60 61 62 // Offsets taken from TAlertView::Draw in BAlert.cpp 63 const float kIconHorizOffset = 18.0f; 64 const float kIconVertOffset = 6.0f; 65 const float kBorderWidth = 32.0f; 66 67 // Amount you have to move the mouse before a drag starts 68 const float kDragSlop = 3.0f; 69 70 71 HeaderView::HeaderView(Model* model) 72 : 73 BView("header", B_WILL_DRAW), 74 fModel(model), 75 fIconModel(model), 76 fTitleEditView(NULL), 77 fTrackingState(no_track), 78 fMouseDown(false), 79 fIsDropTarget(false), 80 fDoubleClick(false), 81 fDragging(false) 82 { 83 // Create the rect for displaying the icon 84 fIconRect.Set(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1); 85 // Offset taken from BAlert 86 fIconRect.OffsetBy(kIconHorizOffset, kIconVertOffset); 87 SetExplicitSize(BSize(B_SIZE_UNSET, B_LARGE_ICON + 2 * kIconVertOffset)); 88 89 // The title rect 90 // The magic numbers are used to properly calculate the rect so that 91 // when the editing text view is displayed, the position of the text 92 // does not change. 93 BFont currentFont; 94 font_height fontMetrics; 95 GetFont(¤tFont); 96 currentFont.GetHeight(&fontMetrics); 97 98 fTitleRect.left = fIconRect.right + 5; 99 fTitleRect.top = 0; 100 fTitleRect.bottom = fontMetrics.ascent + 1; 101 fTitleRect.right = min_c( 102 fTitleRect.left + currentFont.StringWidth(fModel->Name()), 103 Bounds().Width() - 5); 104 // Offset so that it centers with the icon 105 fTitleRect.OffsetBy(0, 106 fIconRect.top + ((fIconRect.Height() - fTitleRect.Height()) / 2)); 107 // Make some room for the border for when we are in edit mode 108 // (Negative numbers increase the size of the rect) 109 fTitleRect.InsetBy(-1, -2); 110 111 // If the model is a symlink, then we deference the model to 112 // get the targets icon 113 if (fModel->IsSymLink()) { 114 Model* resolvedModel = new Model(model->EntryRef(), true, true); 115 if (resolvedModel->InitCheck() == B_OK) 116 fIconModel = resolvedModel; 117 // broken link, just show the symlink 118 else 119 delete resolvedModel; 120 } 121 122 } 123 124 125 HeaderView::~HeaderView() 126 { 127 if (fIconModel != fModel) 128 delete fIconModel; 129 } 130 131 132 void 133 HeaderView::ModelChanged(Model* model, BMessage* message) 134 { 135 // Update the icon stuff 136 if (fIconModel != fModel) { 137 delete fIconModel; 138 fIconModel = NULL; 139 } 140 141 fModel = model; 142 if (fModel->IsSymLink()) { 143 // if we are looking at a symlink, deference the model and look 144 // at the target 145 Model* resolvedModel = new Model(model->EntryRef(), true, true); 146 if (resolvedModel->InitCheck() == B_OK) { 147 if (fIconModel != fModel) 148 delete fIconModel; 149 fIconModel = resolvedModel; 150 } else { 151 fIconModel = model; 152 delete resolvedModel; 153 } 154 } 155 156 Invalidate(); 157 } 158 159 160 void 161 HeaderView::ReLinkTargetModel(Model* model) 162 { 163 fModel = model; 164 if (fModel->IsSymLink()) { 165 Model* resolvedModel = new Model(model->EntryRef(), true, true); 166 if (resolvedModel->InitCheck() == B_OK) { 167 if (fIconModel != fModel) 168 delete fIconModel; 169 fIconModel = resolvedModel; 170 } else { 171 fIconModel = fModel; 172 delete resolvedModel; 173 } 174 } 175 Invalidate(); 176 } 177 178 179 void 180 HeaderView::BeginEditingTitle() 181 { 182 if (fTitleEditView != NULL) 183 return; 184 185 BFont font(be_plain_font); 186 font.SetSize(font.Size() + 2); 187 BRect textFrame(fTitleRect); 188 textFrame.right = Bounds().Width() - 5; 189 BRect textRect(textFrame); 190 textRect.OffsetTo(0, 0); 191 textRect.InsetBy(1, 1); 192 193 // Just make it some really large size, since we don't do any line 194 // wrapping. The text filter will make sure to scroll the cursor 195 // into position 196 197 textRect.right = 2000; 198 fTitleEditView = new BTextView(textFrame, "text_editor", 199 textRect, &font, 0, B_FOLLOW_ALL, B_WILL_DRAW); 200 fTitleEditView->SetText(fModel->Name()); 201 DisallowFilenameKeys(fTitleEditView); 202 203 // Reset the width of the text rect 204 textRect = fTitleEditView->TextRect(); 205 textRect.right = fTitleEditView->LineWidth() + 20; 206 fTitleEditView->SetTextRect(textRect); 207 fTitleEditView->SetWordWrap(false); 208 // Add filter for catching B_RETURN and B_ESCAPE key's 209 fTitleEditView->AddFilter( 210 new BMessageFilter(B_KEY_DOWN, HeaderView::TextViewFilter)); 211 212 BScrollView* scrollView = new BScrollView("BorderView", fTitleEditView, 213 0, 0, false, false, B_PLAIN_BORDER); 214 AddChild(scrollView); 215 fTitleEditView->SelectAll(); 216 fTitleEditView->MakeFocus(); 217 218 Window()->UpdateIfNeeded(); 219 } 220 221 222 void 223 HeaderView::FinishEditingTitle(bool commit) 224 { 225 if (fTitleEditView == NULL) 226 return; 227 228 bool reopen = false; 229 230 const char* text = fTitleEditView->Text(); 231 uint32 length = strlen(text); 232 if (commit && strcmp(text, fModel->Name()) != 0 233 && length < B_FILE_NAME_LENGTH) { 234 BEntry entry(fModel->EntryRef()); 235 BDirectory parent; 236 if (entry.InitCheck() == B_OK 237 && entry.GetParent(&parent) == B_OK) { 238 if (parent.Contains(text)) { 239 BAlert* alert = new BAlert("", 240 B_TRANSLATE("That name is already taken. " 241 "Please type another one."), 242 B_TRANSLATE("OK"), 243 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 244 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 245 alert->Go(); 246 reopen = true; 247 } else { 248 if (fModel->IsVolume()) { 249 BVolume volume(fModel->NodeRef()->device); 250 if (volume.InitCheck() == B_OK) 251 volume.SetName(text); 252 } else 253 entry.Rename(text); 254 255 // Adjust the size of the text rect 256 BFont currentFont(be_plain_font); 257 currentFont.SetSize(currentFont.Size() + 2); 258 fTitleRect.right = min_c(fTitleRect.left 259 + currentFont.StringWidth(fTitleEditView->Text()), 260 Bounds().Width() - 5); 261 } 262 } 263 } else if (length >= B_FILE_NAME_LENGTH) { 264 BAlert* alert = new BAlert("", 265 B_TRANSLATE("That name is too long. Please type another one."), 266 B_TRANSLATE("OK"), 267 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 268 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 269 alert->Go(); 270 reopen = true; 271 } 272 273 // Remove view 274 BView* scrollView = fTitleEditView->Parent(); 275 RemoveChild(scrollView); 276 delete scrollView; 277 fTitleEditView = NULL; 278 279 if (reopen) 280 BeginEditingTitle(); 281 } 282 283 284 void 285 HeaderView::Draw(BRect) 286 { 287 // Set the low color for anti-aliasing 288 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 289 290 // Clear the old contents 291 SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 292 FillRect(Bounds()); 293 294 rgb_color labelColor = ui_color(B_PANEL_TEXT_COLOR); 295 296 // Draw the icon, straddling the border 297 SetDrawingMode(B_OP_OVER); 298 IconCache::sIconCache->Draw(fIconModel, this, fIconRect.LeftTop(), 299 kNormalIcon, B_LARGE_ICON, true); 300 SetDrawingMode(B_OP_COPY); 301 302 // Font information 303 font_height fontMetrics; 304 BFont currentFont; 305 float lineBase = 0; 306 307 // Draw the main title if the user is not currently editing it 308 if (fTitleEditView == NULL) { 309 SetFont(be_bold_font); 310 SetFontSize(be_bold_font->Size()); 311 GetFont(¤tFont); 312 currentFont.GetHeight(&fontMetrics); 313 lineBase = fTitleRect.bottom - fontMetrics.descent; 314 SetHighColor(labelColor); 315 MovePenTo(BPoint(fIconRect.right + 6, lineBase)); 316 317 // Recalculate the rect width 318 fTitleRect.right = min_c( 319 fTitleRect.left + currentFont.StringWidth(fModel->Name()), 320 Bounds().Width() - 5); 321 // Check for possible need of truncation 322 if (StringWidth(fModel->Name()) > fTitleRect.Width()) { 323 BString nameString(fModel->Name()); 324 TruncateString(&nameString, B_TRUNCATE_END, 325 fTitleRect.Width() - 2); 326 DrawString(nameString.String()); 327 } else 328 DrawString(fModel->Name()); 329 } 330 331 } 332 333 334 void 335 HeaderView::MakeFocus(bool focus) 336 { 337 if (!focus && fTitleEditView != NULL) 338 FinishEditingTitle(true); 339 } 340 341 342 void 343 HeaderView::WindowActivated(bool active) 344 { 345 if (active) 346 return; 347 348 if (fTitleEditView != NULL) 349 FinishEditingTitle(true); 350 } 351 352 353 void 354 HeaderView::MouseDown(BPoint where) 355 { 356 // Assume this isn't part of a double click 357 fDoubleClick = false; 358 359 BEntry entry; 360 fModel->GetEntry(&entry); 361 362 if (fTitleRect.Contains(where)) { 363 if (!fModel->HasLocalizedName() 364 && ConfirmChangeIfWellKnownDirectory(&entry, kRename, true)) { 365 BeginEditingTitle(); 366 } 367 } else if (fTitleEditView) { 368 FinishEditingTitle(true); 369 } else if (fIconRect.Contains(where)) { 370 uint32 buttons; 371 Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons); 372 if (SecondaryMouseButtonDown(modifiers(), buttons)) { 373 // Show contextual menu 374 BPopUpMenu* contextMenu 375 = new BPopUpMenu("FileContext", false, false); 376 if (contextMenu) { 377 BuildContextMenu(contextMenu); 378 contextMenu->SetAsyncAutoDestruct(true); 379 contextMenu->Go(ConvertToScreen(where), true, true, 380 ConvertToScreen(fIconRect)); 381 } 382 } else { 383 // Check to see if the point is actually on part of the icon, 384 // versus just in the container rect. The icons are always 385 // the large version 386 BPoint offsetPoint; 387 offsetPoint.x = where.x - fIconRect.left; 388 offsetPoint.y = where.y - fIconRect.top; 389 if (IconCache::sIconCache->IconHitTest(offsetPoint, fIconModel, 390 kNormalIcon, B_LARGE_ICON)) { 391 // Can't drag the trash anywhere.. 392 fTrackingState = fModel->IsTrash() 393 ? open_only_track : icon_track; 394 395 // Check for possible double click 396 if (abs((int32)(fClickPoint.x - where.x)) < kDragSlop 397 && abs((int32)(fClickPoint.y - where.y)) < kDragSlop) { 398 int32 clickCount; 399 Window()->CurrentMessage()->FindInt32("clicks", 400 &clickCount); 401 402 // This checks the* previous* click point 403 if (clickCount == 2) { 404 offsetPoint.x = fClickPoint.x - fIconRect.left; 405 offsetPoint.y = fClickPoint.y - fIconRect.top; 406 fDoubleClick 407 = IconCache::sIconCache->IconHitTest(offsetPoint, 408 fIconModel, kNormalIcon, B_LARGE_ICON); 409 } 410 } 411 } 412 } 413 } 414 415 fClickPoint = where; 416 fMouseDown = true; 417 SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); 418 } 419 420 421 void 422 HeaderView::MouseMoved(BPoint where, uint32, const BMessage* dragMessage) 423 { 424 if (dragMessage != NULL && dragMessage->ReturnAddress() != BMessenger(this) 425 && dragMessage->what == B_SIMPLE_DATA 426 && BPoseView::CanHandleDragSelection(fModel, dragMessage, 427 (modifiers() & B_CONTROL_KEY) != 0)) { 428 // highlight drag target 429 bool overTarget = fIconRect.Contains(where); 430 SetDrawingMode(B_OP_OVER); 431 if (overTarget != fIsDropTarget) { 432 IconCache::sIconCache->Draw(fIconModel, this, fIconRect.LeftTop(), 433 overTarget ? kSelectedIcon : kNormalIcon, B_LARGE_ICON, true); 434 fIsDropTarget = overTarget; 435 } 436 } 437 438 switch (fTrackingState) { 439 case icon_track: 440 if (fMouseDown && !fDragging 441 && (abs((int32)(where.x - fClickPoint.x)) > kDragSlop 442 || abs((int32)(where.y - fClickPoint.y)) > kDragSlop)) { 443 // Find the required height 444 BFont font; 445 GetFont(&font); 446 447 float height = CurrentFontHeight() 448 + fIconRect.Height() + 8; 449 BRect rect(0, 0, min_c(fIconRect.Width() 450 + font.StringWidth(fModel->Name()) + 4, 451 fIconRect.Width() * 3), height); 452 BBitmap* dragBitmap = new BBitmap(rect, B_RGBA32, true); 453 dragBitmap->Lock(); 454 BView* view = new BView(dragBitmap->Bounds(), "", 455 B_FOLLOW_NONE, 0); 456 dragBitmap->AddChild(view); 457 view->SetOrigin(0, 0); 458 BRect clipRect(view->Bounds()); 459 BRegion newClip; 460 newClip.Set(clipRect); 461 view->ConstrainClippingRegion(&newClip); 462 463 // Transparent draw magic 464 view->SetHighColor(0, 0, 0, 0); 465 view->FillRect(view->Bounds()); 466 view->SetDrawingMode(B_OP_ALPHA); 467 rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); 468 textColor.alpha = 128; 469 // set transparency by value 470 view->SetHighColor(textColor); 471 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE); 472 473 // Draw the icon 474 float hIconOffset = (rect.Width() - fIconRect.Width()) / 2; 475 IconCache::sIconCache->Draw(fIconModel, view, 476 BPoint(hIconOffset, 0), kNormalIcon, B_LARGE_ICON, true); 477 478 // See if we need to truncate the string 479 BString nameString(fModel->Name()); 480 if (view->StringWidth(fModel->Name()) > rect.Width()) { 481 view->TruncateString(&nameString, B_TRUNCATE_END, 482 rect.Width() - 5); 483 } 484 485 // Draw the label 486 font_height fontHeight; 487 font.GetHeight(&fontHeight); 488 float leftText = (view->StringWidth(nameString.String()) 489 - fIconRect.Width()) / 2; 490 view->MovePenTo(BPoint(hIconOffset - leftText + 2, 491 fIconRect.Height() + (fontHeight.ascent + 2))); 492 view->DrawString(nameString.String()); 493 494 view->Sync(); 495 dragBitmap->Unlock(); 496 497 BMessage dragMessage(B_REFS_RECEIVED); 498 dragMessage.AddPoint("click_pt", fClickPoint); 499 BPoint tmpLoc; 500 uint32 button; 501 GetMouse(&tmpLoc, &button); 502 if (button) 503 dragMessage.AddInt32("buttons", (int32)button); 504 505 dragMessage.AddInt32("be:actions", 506 (modifiers() & B_OPTION_KEY) != 0 507 ? B_COPY_TARGET : B_MOVE_TARGET); 508 dragMessage.AddRef("refs", fModel->EntryRef()); 509 DragMessage(&dragMessage, dragBitmap, B_OP_ALPHA, 510 BPoint((fClickPoint.x - fIconRect.left) 511 + hIconOffset, fClickPoint.y - fIconRect.top), this); 512 fDragging = true; 513 } 514 break; 515 516 case open_only_track : 517 // Special type of entry that can't be renamed or drag and dropped 518 // It can only be opened by double clicking on the icon 519 break; 520 521 case no_track: 522 // No mouse tracking, do nothing 523 break; 524 } 525 } 526 527 528 void 529 HeaderView::MouseUp(BPoint where) 530 { 531 if ((fTrackingState == icon_track 532 || fTrackingState == open_only_track) 533 && fIconRect.Contains(where)) { 534 // If it was a double click, then tell Tracker to open the item 535 // The CurrentMessage() here does* not* have a "clicks" field, 536 // which is why we are tracking the clicks with this temp var 537 if (fDoubleClick) { 538 // Double click, launch. 539 BMessage message(B_REFS_RECEIVED); 540 message.AddRef("refs", fModel->EntryRef()); 541 542 // add a messenger to the launch message that will be used to 543 // dispatch scripting calls from apps to the PoseView 544 message.AddMessenger("TrackerViewToken", BMessenger(this)); 545 be_app->PostMessage(&message); 546 fDoubleClick = false; 547 } 548 } 549 550 // End mouse tracking 551 fMouseDown = false; 552 fDragging = false; 553 fTrackingState = no_track; 554 } 555 556 557 void 558 HeaderView::MessageReceived(BMessage* message) 559 { 560 if (message->WasDropped() 561 && message->what == B_SIMPLE_DATA 562 && message->ReturnAddress() != BMessenger(this) 563 && fIconRect.Contains(ConvertFromScreen(message->DropPoint())) 564 && BPoseView::CanHandleDragSelection(fModel, message, 565 (modifiers() & B_CONTROL_KEY) != 0)) { 566 BPoseView::HandleDropCommon(message, fModel, 0, this, 567 message->DropPoint()); 568 Invalidate(fIconRect); 569 return; 570 } 571 572 BView::MessageReceived(message); 573 } 574 575 576 577 status_t 578 HeaderView::BuildContextMenu(BMenu* parent) 579 { 580 if (parent == NULL) 581 return B_BAD_VALUE; 582 583 // Add navigation menu if this is not a symlink 584 // Symlink's to directories are OK however! 585 BEntry entry(fModel->EntryRef()); 586 entry_ref ref; 587 entry.GetRef(&ref); 588 Model model(&entry); 589 bool navigate = false; 590 if (model.InitCheck() == B_OK) { 591 if (model.IsSymLink()) { 592 // Check if it's to a directory 593 if (entry.SetTo(model.EntryRef(), true) == B_OK) { 594 navigate = entry.IsDirectory(); 595 entry.GetRef(&ref); 596 } 597 } else if (model.IsDirectory() || model.IsVolume()) 598 navigate = true; 599 } 600 ModelMenuItem* navigationItem = NULL; 601 if (navigate) { 602 navigationItem = new ModelMenuItem(new Model(model), 603 new BNavMenu(model.Name(), B_REFS_RECEIVED, be_app, Window())); 604 605 // setup a navigation menu item which will dynamically load items 606 // as menu items are traversed 607 BNavMenu* navMenu = dynamic_cast<BNavMenu*>(navigationItem->Submenu()); 608 if (navMenu != NULL) 609 navMenu->SetNavDir(&ref); 610 611 navigationItem->SetLabel(model.Name()); 612 navigationItem->SetEntry(&entry); 613 614 parent->AddItem(navigationItem, 0); 615 parent->AddItem(new BSeparatorItem(), 1); 616 617 BMessage* message = new BMessage(B_REFS_RECEIVED); 618 message->AddRef("refs", &ref); 619 navigationItem->SetMessage(message); 620 navigationItem->SetTarget(be_app); 621 } 622 623 parent->AddItem(new BMenuItem(B_TRANSLATE("Open"), 624 new BMessage(kOpenSelection), 'O')); 625 626 if (!model.IsDesktop() && !model.IsRoot() && !model.IsTrash() 627 && !fModel->HasLocalizedName()) { 628 parent->AddItem(new BMenuItem(B_TRANSLATE("Edit name"), 629 new BMessage(kEditItem), 'E')); 630 parent->AddSeparatorItem(); 631 632 if (fModel->IsVolume()) { 633 BMenuItem* item = new BMenuItem(B_TRANSLATE("Unmount"), 634 new BMessage(kUnmountVolume), 'U'); 635 parent->AddItem(item); 636 // volume model, enable/disable the Unmount item 637 BVolume boot; 638 BVolumeRoster().GetBootVolume(&boot); 639 BVolume volume; 640 volume.SetTo(fModel->NodeRef()->device); 641 if (volume == boot) 642 item->SetEnabled(false); 643 } 644 } 645 646 if (!model.IsRoot() && !model.IsVolume() && !model.IsTrash()) 647 parent->AddItem(new BMenuItem(B_TRANSLATE("Identify"), 648 new BMessage(kIdentifyEntry))); 649 650 if (model.IsTrash()) 651 parent->AddItem(new BMenuItem(B_TRANSLATE("Empty Trash"), 652 new BMessage(kEmptyTrash))); 653 654 BMenuItem* sizeItem = NULL; 655 if (model.IsDirectory() && !model.IsVolume() && !model.IsRoot()) { 656 parent->AddItem(sizeItem 657 = new BMenuItem(B_TRANSLATE("Recalculate folder size"), 658 new BMessage(kRecalculateSize))); 659 } 660 661 if (model.IsSymLink()) { 662 parent->AddItem(sizeItem 663 = new BMenuItem(B_TRANSLATE("Set new link target"), 664 new BMessage(kSetLinkTarget))); 665 } 666 667 parent->AddItem(new BSeparatorItem()); 668 parent->AddItem(new BMenuItem(B_TRANSLATE("Permissions"), 669 new BMessage(kPermissionsSelected), 'P')); 670 671 parent->SetFont(be_plain_font); 672 parent->SetTargetForItems(this); 673 674 // Reset the nav menu to be_app 675 if (navigate) 676 navigationItem->SetTarget(be_app); 677 if (sizeItem) 678 sizeItem->SetTarget(Window()); 679 680 return B_OK; 681 } 682 683 684 filter_result 685 HeaderView::TextViewFilter(BMessage* message, BHandler**, 686 BMessageFilter* filter) 687 { 688 uchar key; 689 HeaderView* attribView = static_cast<HeaderView*>( 690 static_cast<BWindow*>(filter->Looper())->FindView("header")); 691 692 // Adjust the size of the text rect 693 BRect nuRect(attribView->TextView()->TextRect()); 694 nuRect.right = attribView->TextView()->LineWidth() + 20; 695 attribView->TextView()->SetTextRect(nuRect); 696 697 // Make sure the cursor is in view 698 attribView->TextView()->ScrollToSelection(); 699 if (message->FindInt8("byte", (int8*)&key) != B_OK) 700 return B_DISPATCH_MESSAGE; 701 702 if (key == B_RETURN || key == B_ESCAPE) { 703 attribView->FinishEditingTitle(key == B_RETURN); 704 return B_SKIP_MESSAGE; 705 } 706 707 return B_DISPATCH_MESSAGE; 708 } 709 710 711 float 712 HeaderView::CurrentFontHeight() 713 { 714 BFont font; 715 GetFont(&font); 716 font_height fontHeight; 717 font.GetHeight(&fontHeight); 718 719 return fontHeight.ascent + fontHeight.descent + fontHeight.leading + 2; 720 } 721 722 723