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 lineHeight = 0; 306 float lineBase = 0; 307 308 // Draw the main title if the user is not currently editing it 309 if (fTitleEditView == NULL) { 310 SetFont(be_bold_font); 311 SetFontSize(be_bold_font->Size()); 312 GetFont(¤tFont); 313 currentFont.GetHeight(&fontMetrics); 314 lineHeight = CurrentFontHeight() + 5; 315 lineBase = fTitleRect.bottom - fontMetrics.descent; 316 SetHighColor(labelColor); 317 MovePenTo(BPoint(fIconRect.right + 6, lineBase)); 318 319 // Recalculate the rect width 320 fTitleRect.right = min_c( 321 fTitleRect.left + currentFont.StringWidth(fModel->Name()), 322 Bounds().Width() - 5); 323 // Check for possible need of truncation 324 if (StringWidth(fModel->Name()) > fTitleRect.Width()) { 325 BString nameString(fModel->Name()); 326 TruncateString(&nameString, B_TRUNCATE_END, 327 fTitleRect.Width() - 2); 328 DrawString(nameString.String()); 329 } else 330 DrawString(fModel->Name()); 331 } 332 333 } 334 335 336 void 337 HeaderView::MakeFocus(bool focus) 338 { 339 if (!focus && fTitleEditView != NULL) 340 FinishEditingTitle(true); 341 } 342 343 344 void 345 HeaderView::WindowActivated(bool active) 346 { 347 if (active) 348 return; 349 350 if (fTitleEditView != NULL) 351 FinishEditingTitle(true); 352 } 353 354 355 void 356 HeaderView::MouseDown(BPoint where) 357 { 358 // Assume this isn't part of a double click 359 fDoubleClick = false; 360 361 BEntry entry; 362 fModel->GetEntry(&entry); 363 364 if (fTitleRect.Contains(where)) { 365 if (!fModel->HasLocalizedName() 366 && ConfirmChangeIfWellKnownDirectory(&entry, kRename, true)) { 367 BeginEditingTitle(); 368 } 369 } else if (fTitleEditView) { 370 FinishEditingTitle(true); 371 } else if (fIconRect.Contains(where)) { 372 uint32 buttons; 373 Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons); 374 if (SecondaryMouseButtonDown(modifiers(), buttons)) { 375 // Show contextual menu 376 BPopUpMenu* contextMenu 377 = new BPopUpMenu("FileContext", false, false); 378 if (contextMenu) { 379 BuildContextMenu(contextMenu); 380 contextMenu->SetAsyncAutoDestruct(true); 381 contextMenu->Go(ConvertToScreen(where), true, true, 382 ConvertToScreen(fIconRect)); 383 } 384 } else { 385 // Check to see if the point is actually on part of the icon, 386 // versus just in the container rect. The icons are always 387 // the large version 388 BPoint offsetPoint; 389 offsetPoint.x = where.x - fIconRect.left; 390 offsetPoint.y = where.y - fIconRect.top; 391 if (IconCache::sIconCache->IconHitTest(offsetPoint, fIconModel, 392 kNormalIcon, B_LARGE_ICON)) { 393 // Can't drag the trash anywhere.. 394 fTrackingState = fModel->IsTrash() 395 ? open_only_track : icon_track; 396 397 // Check for possible double click 398 if (abs((int32)(fClickPoint.x - where.x)) < kDragSlop 399 && abs((int32)(fClickPoint.y - where.y)) < kDragSlop) { 400 int32 clickCount; 401 Window()->CurrentMessage()->FindInt32("clicks", 402 &clickCount); 403 404 // This checks the* previous* click point 405 if (clickCount == 2) { 406 offsetPoint.x = fClickPoint.x - fIconRect.left; 407 offsetPoint.y = fClickPoint.y - fIconRect.top; 408 fDoubleClick 409 = IconCache::sIconCache->IconHitTest(offsetPoint, 410 fIconModel, kNormalIcon, B_LARGE_ICON); 411 } 412 } 413 } 414 } 415 } 416 417 fClickPoint = where; 418 fMouseDown = true; 419 SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); 420 } 421 422 423 void 424 HeaderView::MouseMoved(BPoint where, uint32, const BMessage* dragMessage) 425 { 426 if (dragMessage != NULL && dragMessage->ReturnAddress() != BMessenger(this) 427 && dragMessage->what == B_SIMPLE_DATA 428 && BPoseView::CanHandleDragSelection(fModel, dragMessage, 429 (modifiers() & B_CONTROL_KEY) != 0)) { 430 // highlight drag target 431 bool overTarget = fIconRect.Contains(where); 432 SetDrawingMode(B_OP_OVER); 433 if (overTarget != fIsDropTarget) { 434 IconCache::sIconCache->Draw(fIconModel, this, fIconRect.LeftTop(), 435 overTarget ? kSelectedIcon : kNormalIcon, B_LARGE_ICON, true); 436 fIsDropTarget = overTarget; 437 } 438 } 439 440 switch (fTrackingState) { 441 case icon_track: 442 if (fMouseDown && !fDragging 443 && (abs((int32)(where.x - fClickPoint.x)) > kDragSlop 444 || abs((int32)(where.y - fClickPoint.y)) > kDragSlop)) { 445 // Find the required height 446 BFont font; 447 GetFont(&font); 448 449 float height = CurrentFontHeight() 450 + fIconRect.Height() + 8; 451 BRect rect(0, 0, min_c(fIconRect.Width() 452 + font.StringWidth(fModel->Name()) + 4, 453 fIconRect.Width() * 3), height); 454 BBitmap* dragBitmap = new BBitmap(rect, B_RGBA32, true); 455 dragBitmap->Lock(); 456 BView* view = new BView(dragBitmap->Bounds(), "", 457 B_FOLLOW_NONE, 0); 458 dragBitmap->AddChild(view); 459 view->SetOrigin(0, 0); 460 BRect clipRect(view->Bounds()); 461 BRegion newClip; 462 newClip.Set(clipRect); 463 view->ConstrainClippingRegion(&newClip); 464 465 // Transparent draw magic 466 view->SetHighColor(0, 0, 0, 0); 467 view->FillRect(view->Bounds()); 468 view->SetDrawingMode(B_OP_ALPHA); 469 rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); 470 textColor.alpha = 128; 471 // set transparency by value 472 view->SetHighColor(textColor); 473 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE); 474 475 // Draw the icon 476 float hIconOffset = (rect.Width() - fIconRect.Width()) / 2; 477 IconCache::sIconCache->Draw(fIconModel, view, 478 BPoint(hIconOffset, 0), kNormalIcon, B_LARGE_ICON, true); 479 480 // See if we need to truncate the string 481 BString nameString(fModel->Name()); 482 if (view->StringWidth(fModel->Name()) > rect.Width()) { 483 view->TruncateString(&nameString, B_TRUNCATE_END, 484 rect.Width() - 5); 485 } 486 487 // Draw the label 488 font_height fontHeight; 489 font.GetHeight(&fontHeight); 490 float leftText = (view->StringWidth(nameString.String()) 491 - fIconRect.Width()) / 2; 492 view->MovePenTo(BPoint(hIconOffset - leftText + 2, 493 fIconRect.Height() + (fontHeight.ascent + 2))); 494 view->DrawString(nameString.String()); 495 496 view->Sync(); 497 dragBitmap->Unlock(); 498 499 BMessage dragMessage(B_REFS_RECEIVED); 500 dragMessage.AddPoint("click_pt", fClickPoint); 501 BPoint tmpLoc; 502 uint32 button; 503 GetMouse(&tmpLoc, &button); 504 if (button) 505 dragMessage.AddInt32("buttons", (int32)button); 506 507 dragMessage.AddInt32("be:actions", 508 (modifiers() & B_OPTION_KEY) != 0 509 ? B_COPY_TARGET : B_MOVE_TARGET); 510 dragMessage.AddRef("refs", fModel->EntryRef()); 511 DragMessage(&dragMessage, dragBitmap, B_OP_ALPHA, 512 BPoint((fClickPoint.x - fIconRect.left) 513 + hIconOffset, fClickPoint.y - fIconRect.top), this); 514 fDragging = true; 515 } 516 break; 517 518 case open_only_track : 519 // Special type of entry that can't be renamed or drag and dropped 520 // It can only be opened by double clicking on the icon 521 break; 522 523 case no_track: 524 // No mouse tracking, do nothing 525 break; 526 } 527 } 528 529 530 void 531 HeaderView::MouseUp(BPoint where) 532 { 533 if ((fTrackingState == icon_track 534 || fTrackingState == open_only_track) 535 && fIconRect.Contains(where)) { 536 // If it was a double click, then tell Tracker to open the item 537 // The CurrentMessage() here does* not* have a "clicks" field, 538 // which is why we are tracking the clicks with this temp var 539 if (fDoubleClick) { 540 // Double click, launch. 541 BMessage message(B_REFS_RECEIVED); 542 message.AddRef("refs", fModel->EntryRef()); 543 544 // add a messenger to the launch message that will be used to 545 // dispatch scripting calls from apps to the PoseView 546 message.AddMessenger("TrackerViewToken", BMessenger(this)); 547 be_app->PostMessage(&message); 548 fDoubleClick = false; 549 } 550 } 551 552 // End mouse tracking 553 fMouseDown = false; 554 fDragging = false; 555 fTrackingState = no_track; 556 } 557 558 559 void 560 HeaderView::MessageReceived(BMessage* message) 561 { 562 if (message->WasDropped() 563 && message->what == B_SIMPLE_DATA 564 && message->ReturnAddress() != BMessenger(this) 565 && fIconRect.Contains(ConvertFromScreen(message->DropPoint())) 566 && BPoseView::CanHandleDragSelection(fModel, message, 567 (modifiers() & B_CONTROL_KEY) != 0)) { 568 BPoseView::HandleDropCommon(message, fModel, 0, this, 569 message->DropPoint()); 570 Invalidate(fIconRect); 571 return; 572 } 573 574 BView::MessageReceived(message); 575 } 576 577 578 579 status_t 580 HeaderView::BuildContextMenu(BMenu* parent) 581 { 582 if (parent == NULL) 583 return B_BAD_VALUE; 584 585 // Add navigation menu if this is not a symlink 586 // Symlink's to directories are OK however! 587 BEntry entry(fModel->EntryRef()); 588 entry_ref ref; 589 entry.GetRef(&ref); 590 Model model(&entry); 591 bool navigate = false; 592 if (model.InitCheck() == B_OK) { 593 if (model.IsSymLink()) { 594 // Check if it's to a directory 595 if (entry.SetTo(model.EntryRef(), true) == B_OK) { 596 navigate = entry.IsDirectory(); 597 entry.GetRef(&ref); 598 } 599 } else if (model.IsDirectory() || model.IsVolume()) 600 navigate = true; 601 } 602 ModelMenuItem* navigationItem = NULL; 603 if (navigate) { 604 navigationItem = new ModelMenuItem(new Model(model), 605 new BNavMenu(model.Name(), B_REFS_RECEIVED, be_app, Window())); 606 607 // setup a navigation menu item which will dynamically load items 608 // as menu items are traversed 609 BNavMenu* navMenu = dynamic_cast<BNavMenu*>(navigationItem->Submenu()); 610 if (navMenu != NULL) 611 navMenu->SetNavDir(&ref); 612 613 navigationItem->SetLabel(model.Name()); 614 navigationItem->SetEntry(&entry); 615 616 parent->AddItem(navigationItem, 0); 617 parent->AddItem(new BSeparatorItem(), 1); 618 619 BMessage* message = new BMessage(B_REFS_RECEIVED); 620 message->AddRef("refs", &ref); 621 navigationItem->SetMessage(message); 622 navigationItem->SetTarget(be_app); 623 } 624 625 parent->AddItem(new BMenuItem(B_TRANSLATE("Open"), 626 new BMessage(kOpenSelection), 'O')); 627 628 if (!model.IsDesktop() && !model.IsRoot() && !model.IsTrash() 629 && !fModel->HasLocalizedName()) { 630 parent->AddItem(new BMenuItem(B_TRANSLATE("Edit name"), 631 new BMessage(kEditItem), 'E')); 632 parent->AddSeparatorItem(); 633 634 if (fModel->IsVolume()) { 635 BMenuItem* item = new BMenuItem(B_TRANSLATE("Unmount"), 636 new BMessage(kUnmountVolume), 'U'); 637 parent->AddItem(item); 638 // volume model, enable/disable the Unmount item 639 BVolume boot; 640 BVolumeRoster().GetBootVolume(&boot); 641 BVolume volume; 642 volume.SetTo(fModel->NodeRef()->device); 643 if (volume == boot) 644 item->SetEnabled(false); 645 } 646 } 647 648 if (!model.IsRoot() && !model.IsVolume() && !model.IsTrash()) 649 parent->AddItem(new BMenuItem(B_TRANSLATE("Identify"), 650 new BMessage(kIdentifyEntry))); 651 652 if (model.IsTrash()) 653 parent->AddItem(new BMenuItem(B_TRANSLATE("Empty Trash"), 654 new BMessage(kEmptyTrash))); 655 656 BMenuItem* sizeItem = NULL; 657 if (model.IsDirectory() && !model.IsVolume() && !model.IsRoot()) { 658 parent->AddItem(sizeItem 659 = new BMenuItem(B_TRANSLATE("Recalculate folder size"), 660 new BMessage(kRecalculateSize))); 661 } 662 663 if (model.IsSymLink()) { 664 parent->AddItem(sizeItem 665 = new BMenuItem(B_TRANSLATE("Set new link target"), 666 new BMessage(kSetLinkTarget))); 667 } 668 669 parent->AddItem(new BSeparatorItem()); 670 parent->AddItem(new BMenuItem(B_TRANSLATE("Permissions"), 671 new BMessage(kPermissionsSelected), 'P')); 672 673 parent->SetFont(be_plain_font); 674 parent->SetTargetForItems(this); 675 676 // Reset the nav menu to be_app 677 if (navigate) 678 navigationItem->SetTarget(be_app); 679 if (sizeItem) 680 sizeItem->SetTarget(Window()); 681 682 return B_OK; 683 } 684 685 686 filter_result 687 HeaderView::TextViewFilter(BMessage* message, BHandler**, 688 BMessageFilter* filter) 689 { 690 uchar key; 691 HeaderView* attribView = static_cast<HeaderView*>( 692 static_cast<BWindow*>(filter->Looper())->FindView("header")); 693 694 // Adjust the size of the text rect 695 BRect nuRect(attribView->TextView()->TextRect()); 696 nuRect.right = attribView->TextView()->LineWidth() + 20; 697 attribView->TextView()->SetTextRect(nuRect); 698 699 // Make sure the cursor is in view 700 attribView->TextView()->ScrollToSelection(); 701 if (message->FindInt8("byte", (int8*)&key) != B_OK) 702 return B_DISPATCH_MESSAGE; 703 704 if (key == B_RETURN || key == B_ESCAPE) { 705 attribView->FinishEditingTitle(key == B_RETURN); 706 return B_SKIP_MESSAGE; 707 } 708 709 return B_DISPATCH_MESSAGE; 710 } 711 712 713 float 714 HeaderView::CurrentFontHeight() 715 { 716 BFont font; 717 GetFont(&font); 718 font_height fontHeight; 719 font.GetHeight(&fontHeight); 720 721 return fontHeight.ascent + fontHeight.descent + fontHeight.leading + 2; 722 } 723 724 725