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 "Attributes.h" 37 #include "MimeTypes.h" 38 #include "Model.h" 39 #include "PoseView.h" 40 #include "Utilities.h" 41 #include "ContainerWindow.h" 42 43 #include <IconUtils.h> 44 45 #include <Bitmap.h> 46 #include <Catalog.h> 47 #include <Debug.h> 48 #include <Directory.h> 49 #include <fs_attr.h> 50 #include <fs_info.h> 51 #include <MenuItem.h> 52 #include <OS.h> 53 #include <PopUpMenu.h> 54 #include <Region.h> 55 #include <StorageDefs.h> 56 #include <TextView.h> 57 #include <Volume.h> 58 #include <VolumeRoster.h> 59 #include <Window.h> 60 61 #include <ctype.h> 62 #include <string.h> 63 #include <stdlib.h> 64 #include <time.h> 65 #include <stdarg.h> 66 67 68 #ifndef _IMPEXP_BE 69 # define _IMPEXP_BE 70 #endif 71 extern _IMPEXP_BE const uint32 LARGE_ICON_TYPE; 72 extern _IMPEXP_BE const uint32 MINI_ICON_TYPE; 73 74 75 FILE* logFile = NULL; 76 77 static const float kMinSeparatorStubX = 10; 78 static const float kStubToStringSlotX = 5; 79 80 81 namespace BPrivate { 82 83 const float kExactMatchScore = INFINITY; 84 85 86 bool gLocalizedNamePreferred; 87 88 89 uint32 90 HashString(const char* string, uint32 seed) 91 { 92 char ch; 93 uint32 result = seed; 94 95 while((ch = *string++) != 0) { 96 result = (result << 7) ^ (result >> 24); 97 result ^= ch; 98 } 99 100 result ^= result << 12; 101 return result; 102 } 103 104 105 uint32 106 AttrHashString(const char* string, uint32 type) 107 { 108 char c; 109 uint32 hash = 0; 110 111 while((c = *string++) != 0) { 112 hash = (hash << 7) ^ (hash >> 24); 113 hash ^= c; 114 } 115 116 hash ^= hash << 12; 117 118 hash &= ~0xff; 119 hash |= type; 120 121 return hash; 122 } 123 124 125 bool 126 ValidateStream(BMallocIO* stream, uint32 key, int32 version) 127 { 128 uint32 testKey; 129 int32 testVersion; 130 131 if (stream->Read(&testKey, sizeof(uint32)) <= 0 132 || stream->Read(&testVersion, sizeof(int32)) <=0) 133 return false; 134 135 return testKey == key && testVersion == version; 136 } 137 138 139 void 140 DisallowFilenameKeys(BTextView* textView) 141 { 142 textView->DisallowChar('/'); 143 } 144 145 146 void 147 DisallowMetaKeys(BTextView* textView) 148 { 149 textView->DisallowChar(B_TAB); 150 textView->DisallowChar(B_ESCAPE); 151 textView->DisallowChar(B_INSERT); 152 textView->DisallowChar(B_DELETE); 153 textView->DisallowChar(B_HOME); 154 textView->DisallowChar(B_END); 155 textView->DisallowChar(B_PAGE_UP); 156 textView->DisallowChar(B_PAGE_DOWN); 157 textView->DisallowChar(B_FUNCTION_KEY); 158 } 159 160 161 PeriodicUpdatePoses::PeriodicUpdatePoses() 162 : 163 fPoseList(20, true) 164 { 165 fLock = new Benaphore("PeriodicUpdatePoses"); 166 } 167 168 169 PeriodicUpdatePoses::~PeriodicUpdatePoses() 170 { 171 fLock->Lock(); 172 fPoseList.MakeEmpty(); 173 delete fLock; 174 } 175 176 177 void 178 PeriodicUpdatePoses::AddPose(BPose* pose, BPoseView* poseView, 179 PeriodicUpdateCallback callback, void* cookie) 180 { 181 periodic_pose* periodic = new periodic_pose; 182 periodic->pose = pose; 183 periodic->pose_view = poseView; 184 periodic->callback = callback; 185 periodic->cookie = cookie; 186 fPoseList.AddItem(periodic); 187 } 188 189 190 bool 191 PeriodicUpdatePoses::RemovePose(BPose* pose, void** cookie) 192 { 193 int32 count = fPoseList.CountItems(); 194 for (int32 index = 0; index < count; index++) { 195 if (fPoseList.ItemAt(index)->pose == pose) { 196 if (!fLock->Lock()) 197 return false; 198 199 periodic_pose* periodic = fPoseList.RemoveItemAt(index); 200 if (cookie) 201 *cookie = periodic->cookie; 202 delete periodic; 203 fLock->Unlock(); 204 return true; 205 } 206 } 207 208 return false; 209 } 210 211 212 void 213 PeriodicUpdatePoses::DoPeriodicUpdate(bool forceRedraw) 214 { 215 if (!fLock->Lock()) 216 return; 217 218 int32 count = fPoseList.CountItems(); 219 for (int32 index = 0; index < count; index++) { 220 periodic_pose* periodic = fPoseList.ItemAt(index); 221 if (periodic->callback(periodic->pose, periodic->cookie) 222 || forceRedraw) { 223 periodic->pose_view->LockLooper(); 224 periodic->pose_view->UpdateIcon(periodic->pose); 225 periodic->pose_view->UnlockLooper(); 226 } 227 } 228 229 fLock->Unlock(); 230 } 231 232 233 PeriodicUpdatePoses gPeriodicUpdatePoses; 234 235 236 } // namespace BPrivate 237 238 239 void 240 PoseInfo::EndianSwap(void* castToThis) 241 { 242 PoseInfo* self = (PoseInfo*)castToThis; 243 244 PRINT(("swapping PoseInfo\n")); 245 246 STATIC_ASSERT(sizeof(ino_t) == sizeof(int64)); 247 self->fInitedDirectory = SwapInt64(self->fInitedDirectory); 248 swap_data(B_POINT_TYPE, &self->fLocation, sizeof(BPoint), B_SWAP_ALWAYS); 249 250 // do a sanity check on the icon position 251 if (self->fLocation.x < -20000 || self->fLocation.x > 20000 252 || self->fLocation.y < -20000 || self->fLocation.y > 20000) { 253 // position out of range, force autoplcemement 254 PRINT((" rejecting icon position out of range\n")); 255 self->fInitedDirectory = -1LL; 256 self->fLocation = BPoint(0, 0); 257 } 258 } 259 260 261 void 262 PoseInfo::PrintToStream() 263 { 264 PRINT(("%s, inode:%" B_PRIx64 ", location %f %f\n", 265 fInvisible ? "hidden" : "visible", 266 fInitedDirectory, fLocation.x, fLocation.y)); 267 } 268 269 270 // #pragma mark - 271 272 273 size_t 274 ExtendedPoseInfo::Size() const 275 { 276 return sizeof(ExtendedPoseInfo) + fNumFrames * sizeof(FrameLocation); 277 } 278 279 280 size_t 281 ExtendedPoseInfo::Size(int32 count) 282 { 283 return sizeof(ExtendedPoseInfo) + count * sizeof(FrameLocation); 284 } 285 286 287 size_t 288 ExtendedPoseInfo::SizeWithHeadroom() const 289 { 290 return sizeof(ExtendedPoseInfo) + (fNumFrames + 1) 291 * sizeof(FrameLocation); 292 } 293 294 295 size_t 296 ExtendedPoseInfo::SizeWithHeadroom(size_t oldSize) 297 { 298 int32 count = (ssize_t)oldSize - (ssize_t)sizeof(ExtendedPoseInfo); 299 if (count > 0) 300 count /= sizeof(FrameLocation); 301 else 302 count = 0; 303 304 return Size(count + 1); 305 } 306 307 308 bool 309 ExtendedPoseInfo::HasLocationForFrame(BRect frame) const 310 { 311 for (int32 index = 0; index < fNumFrames; index++) { 312 if (fLocations[index].fFrame == frame) 313 return true; 314 } 315 316 return false; 317 } 318 319 320 BPoint 321 ExtendedPoseInfo::LocationForFrame(BRect frame) const 322 { 323 for (int32 index = 0; index < fNumFrames; index++) { 324 if (fLocations[index].fFrame == frame) 325 return fLocations[index].fLocation; 326 } 327 328 TRESPASS(); 329 return BPoint(0, 0); 330 } 331 332 333 bool 334 ExtendedPoseInfo::SetLocationForFrame(BPoint newLocation, BRect frame) 335 { 336 for (int32 index = 0; index < fNumFrames; index++) { 337 if (fLocations[index].fFrame == frame) { 338 if (fLocations[index].fLocation == newLocation) 339 return false; 340 341 fLocations[index].fLocation = newLocation; 342 return true; 343 } 344 } 345 346 fLocations[fNumFrames].fFrame = frame; 347 fLocations[fNumFrames].fLocation = newLocation; 348 fLocations[fNumFrames].fWorkspaces = 0xffffffff; 349 fNumFrames++; 350 return true; 351 } 352 353 354 void 355 ExtendedPoseInfo::EndianSwap(void* castToThis) 356 { 357 ExtendedPoseInfo* self = (ExtendedPoseInfo *)castToThis; 358 359 PRINT(("swapping ExtendedPoseInfo\n")); 360 361 self->fWorkspaces = SwapUInt32(self->fWorkspaces); 362 self->fNumFrames = SwapInt32(self->fNumFrames); 363 364 for (int32 index = 0; index < self->fNumFrames; index++) { 365 swap_data(B_POINT_TYPE, &self->fLocations[index].fLocation, 366 sizeof(BPoint), B_SWAP_ALWAYS); 367 368 if (self->fLocations[index].fLocation.x < -20000 369 || self->fLocations[index].fLocation.x > 20000 370 || self->fLocations[index].fLocation.y < -20000 371 || self->fLocations[index].fLocation.y > 20000) { 372 // position out of range, force autoplcemement 373 PRINT((" rejecting icon position out of range\n")); 374 self->fLocations[index].fLocation = BPoint(0, 0); 375 } 376 swap_data(B_RECT_TYPE, &self->fLocations[index].fFrame, 377 sizeof(BRect), B_SWAP_ALWAYS); 378 } 379 } 380 381 382 void 383 ExtendedPoseInfo::PrintToStream() 384 { 385 } 386 387 388 // #pragma mark - 389 390 391 OffscreenBitmap::OffscreenBitmap(BRect frame) 392 : 393 fBitmap(NULL) 394 { 395 NewBitmap(frame); 396 } 397 398 399 OffscreenBitmap::OffscreenBitmap() 400 : 401 fBitmap(NULL) 402 { 403 } 404 405 406 OffscreenBitmap::~OffscreenBitmap() 407 { 408 delete fBitmap; 409 } 410 411 412 void 413 OffscreenBitmap::NewBitmap(BRect bounds) 414 { 415 delete fBitmap; 416 fBitmap = new(std::nothrow) BBitmap(bounds, B_RGB32, true); 417 if (fBitmap && fBitmap->Lock()) { 418 BView* view = new BView(fBitmap->Bounds(), "", B_FOLLOW_NONE, 0); 419 fBitmap->AddChild(view); 420 421 BRect clipRect = view->Bounds(); 422 BRegion newClip; 423 newClip.Set(clipRect); 424 view->ConstrainClippingRegion(&newClip); 425 426 fBitmap->Unlock(); 427 } else { 428 delete fBitmap; 429 fBitmap = NULL; 430 } 431 } 432 433 434 BView* 435 OffscreenBitmap::BeginUsing(BRect frame) 436 { 437 if (!fBitmap || fBitmap->Bounds() != frame) 438 NewBitmap(frame); 439 440 fBitmap->Lock(); 441 return View(); 442 } 443 444 445 void 446 OffscreenBitmap::DoneUsing() 447 { 448 fBitmap->Unlock(); 449 } 450 451 452 BBitmap* 453 OffscreenBitmap::Bitmap() const 454 { 455 ASSERT(fBitmap); 456 ASSERT(fBitmap->IsLocked()); 457 return fBitmap; 458 } 459 460 461 BView* 462 OffscreenBitmap::View() const 463 { 464 ASSERT(fBitmap); 465 return fBitmap->ChildAt(0); 466 } 467 468 469 // #pragma mark - 470 471 472 namespace BPrivate { 473 474 // Changes the alpha value of the given bitmap to create a nice 475 // horizontal fade out in the specified region. 476 // "from" is always transparent, "to" opaque. 477 void 478 FadeRGBA32Horizontal(uint32* bits, int32 width, int32 height, int32 from, 479 int32 to) 480 { 481 // check parameters 482 if (width < 0 || height < 0 || from < 0 || to < 0) 483 return; 484 485 float change = 1.f / (to - from); 486 if (from > to) { 487 int32 temp = from; 488 from = to; 489 to = temp; 490 } 491 492 for (int32 y = 0; y < height; y++) { 493 float alpha = change > 0 ? 0.0f : 1.0f; 494 495 for (int32 x = from; x <= to; x++) { 496 if (bits[x] & 0xff000000) { 497 uint32 a = uint32((bits[x] >> 24) * alpha); 498 bits[x] = (bits[x] & 0x00ffffff) | (a << 24); 499 } 500 alpha += change; 501 } 502 bits += width; 503 } 504 } 505 506 507 /*! Changes the alpha value of the given bitmap to create a nice 508 vertical fade out in the specified region. 509 "from" is always transparent, "to" opaque. 510 */ 511 void 512 FadeRGBA32Vertical(uint32* bits, int32 width, int32 height, int32 from, 513 int32 to) 514 { 515 // check parameters 516 if (width < 0 || height < 0 || from < 0 || to < 0) 517 return; 518 519 if (from > to) 520 bits += width * (height - (from - to)); 521 522 float change = 1.f / (to - from); 523 if (from > to) { 524 int32 temp = from; 525 from = to; 526 to = temp; 527 } 528 529 float alpha = change > 0 ? 0.0f : 1.0f; 530 531 for (int32 y = from; y <= to; y++) { 532 for (int32 x = 0; x < width; x++) { 533 if (bits[x] & 0xff000000) { 534 uint32 a = uint32((bits[x] >> 24) * alpha); 535 bits[x] = (bits[x] & 0x00ffffff) | (a << 24); 536 } 537 } 538 alpha += change; 539 bits += width; 540 } 541 } 542 543 544 } // namespace BPrivate 545 546 547 // #pragma mark - 548 549 550 DraggableIcon::DraggableIcon(BRect rect, const char* name, 551 const char* mimeType, icon_size size, const BMessage* message, 552 BMessenger target, uint32 resizeMask, uint32 flags) 553 : 554 BView(rect, name, resizeMask, flags), 555 fMessage(*message), 556 fTarget(target) 557 { 558 fBitmap = new BBitmap(Bounds(), kDefaultIconDepth); 559 BMimeType mime(mimeType); 560 status_t error = mime.GetIcon(fBitmap, size); 561 ASSERT(mime.IsValid()); 562 if (error != B_OK) { 563 PRINT(("failed to get icon for %s, %s\n", mimeType, strerror(error))); 564 BMimeType mime(B_FILE_MIMETYPE); 565 ASSERT(mime.IsInstalled()); 566 mime.GetIcon(fBitmap, size); 567 } 568 } 569 570 571 DraggableIcon::~DraggableIcon() 572 { 573 delete fBitmap; 574 } 575 576 577 void 578 DraggableIcon::SetTarget(BMessenger target) 579 { 580 fTarget = target; 581 } 582 583 584 BRect 585 DraggableIcon::PreferredRect(BPoint offset, icon_size size) 586 { 587 BRect result(0, 0, size - 1, size - 1); 588 result.OffsetTo(offset); 589 return result; 590 } 591 592 593 void 594 DraggableIcon::AttachedToWindow() 595 { 596 BView* parent = Parent(); 597 if (parent != NULL) { 598 SetViewColor(parent->ViewColor()); 599 SetLowColor(parent->LowColor()); 600 } 601 } 602 603 604 void 605 DraggableIcon::MouseDown(BPoint point) 606 { 607 if (!DragStarted(&fMessage)) 608 return; 609 610 BRect rect(Bounds()); 611 BBitmap* dragBitmap = new BBitmap(rect, B_RGBA32, true); 612 dragBitmap->Lock(); 613 BView* view = new BView(dragBitmap->Bounds(), "", B_FOLLOW_NONE, 0); 614 dragBitmap->AddChild(view); 615 view->SetOrigin(0, 0); 616 BRect clipRect(view->Bounds()); 617 BRegion newClip; 618 newClip.Set(clipRect); 619 view->ConstrainClippingRegion(&newClip); 620 621 // Transparent draw magic 622 view->SetHighColor(0, 0, 0, 0); 623 view->FillRect(view->Bounds()); 624 view->SetDrawingMode(B_OP_ALPHA); 625 view->SetHighColor(0, 0, 0, 128); 626 // set the level of transparency by value 627 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE); 628 view->DrawBitmap(fBitmap); 629 view->Sync(); 630 dragBitmap->Unlock(); 631 DragMessage(&fMessage, dragBitmap, B_OP_ALPHA, point, fTarget.Target(0)); 632 } 633 634 635 bool 636 DraggableIcon::DragStarted(BMessage*) 637 { 638 return true; 639 } 640 641 642 void 643 DraggableIcon::Draw(BRect) 644 { 645 SetDrawingMode(B_OP_ALPHA); 646 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 647 DrawBitmap(fBitmap); 648 } 649 650 651 // #pragma mark - 652 653 654 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char* name, 655 const char* text, uint32 resizeFlags, uint32 flags) 656 : 657 BStringView(bounds, name, text, resizeFlags, flags), 658 fBitmap(NULL), 659 fOrigBitmap(NULL) 660 { 661 } 662 663 664 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char* name, 665 const char* text, BBitmap* inBitmap, uint32 resizeFlags, uint32 flags) 666 : 667 BStringView(bounds, name, text, resizeFlags, flags), 668 fBitmap(NULL), 669 fOrigBitmap(inBitmap) 670 { 671 } 672 673 674 FlickerFreeStringView::~FlickerFreeStringView() 675 { 676 delete fBitmap; 677 } 678 679 680 void 681 FlickerFreeStringView::Draw(BRect) 682 { 683 BRect bounds(Bounds()); 684 if (!fBitmap) 685 fBitmap = new OffscreenBitmap(Bounds()); 686 687 BView* offscreen = fBitmap->BeginUsing(bounds); 688 689 if (Parent()) { 690 fViewColor = Parent()->ViewColor(); 691 fLowColor = Parent()->ViewColor(); 692 } 693 694 offscreen->SetViewColor(fViewColor); 695 offscreen->SetHighColor(HighColor()); 696 offscreen->SetLowColor(fLowColor); 697 698 BFont font; 699 GetFont(&font); 700 offscreen->SetFont(&font); 701 702 offscreen->Sync(); 703 if (fOrigBitmap) 704 offscreen->DrawBitmap(fOrigBitmap, Frame(), bounds); 705 else 706 offscreen->FillRect(bounds, B_SOLID_LOW); 707 708 if (Text()) { 709 BPoint loc; 710 711 font_height height; 712 GetFontHeight(&height); 713 714 edge_info eInfo; 715 switch (Alignment()) { 716 case B_ALIGN_LEFT: 717 case B_ALIGN_HORIZONTAL_UNSET: 718 case B_ALIGN_USE_FULL_WIDTH: 719 { 720 // If the first char has a negative left edge give it 721 // some more room by shifting that much more to the right. 722 font.GetEdges(Text(), 1, &eInfo); 723 loc.x = bounds.left + (2 - eInfo.left); 724 break; 725 } 726 727 case B_ALIGN_CENTER: 728 { 729 float width = StringWidth(Text()); 730 float center = (bounds.right - bounds.left) / 2; 731 loc.x = center - (width/2); 732 break; 733 } 734 735 case B_ALIGN_RIGHT: 736 { 737 float width = StringWidth(Text()); 738 loc.x = bounds.right - width - 2; 739 break; 740 } 741 } 742 loc.y = bounds.bottom - (1 + height.descent); 743 offscreen->DrawString(Text(), loc); 744 } 745 offscreen->Sync(); 746 SetDrawingMode(B_OP_COPY); 747 DrawBitmap(fBitmap->Bitmap()); 748 fBitmap->DoneUsing(); 749 } 750 751 752 void 753 FlickerFreeStringView::AttachedToWindow() 754 { 755 _inherited::AttachedToWindow(); 756 if (Parent()) { 757 fViewColor = Parent()->ViewColor(); 758 fLowColor = Parent()->ViewColor(); 759 } 760 SetViewColor(B_TRANSPARENT_32_BIT); 761 SetLowColor(B_TRANSPARENT_32_BIT); 762 } 763 764 765 void 766 FlickerFreeStringView::SetViewColor(rgb_color color) 767 { 768 if (fViewColor != color) { 769 fViewColor = color; 770 Invalidate(); 771 } 772 _inherited::SetViewColor(B_TRANSPARENT_32_BIT); 773 } 774 775 776 void 777 FlickerFreeStringView::SetLowColor(rgb_color color) 778 { 779 if (fLowColor != color) { 780 fLowColor = color; 781 Invalidate(); 782 } 783 _inherited::SetLowColor(B_TRANSPARENT_32_BIT); 784 } 785 786 787 // #pragma mark - 788 789 790 TitledSeparatorItem::TitledSeparatorItem(const char* label) 791 : 792 BMenuItem(label, 0) 793 { 794 _inherited::SetEnabled(false); 795 } 796 797 798 TitledSeparatorItem::~TitledSeparatorItem() 799 { 800 } 801 802 803 void 804 TitledSeparatorItem::SetEnabled(bool) 805 { 806 // leave disabled 807 } 808 809 810 void 811 TitledSeparatorItem::GetContentSize(float* width, float* height) 812 { 813 _inherited::GetContentSize(width, height); 814 } 815 816 817 inline rgb_color 818 ShiftMenuBackgroundColor(float by) 819 { 820 return tint_color(ui_color(B_MENU_BACKGROUND_COLOR), by); 821 } 822 823 824 void 825 TitledSeparatorItem::Draw() 826 { 827 BRect frame(Frame()); 828 829 BMenu* parent = Menu(); 830 ASSERT(parent); 831 832 menu_info minfo; 833 get_menu_info(&minfo); 834 835 if (minfo.separator > 0) { 836 frame.left += 10; 837 frame.right -= 10; 838 } else { 839 frame.left += 1; 840 frame.right -= 1; 841 } 842 843 float startX = frame.left; 844 float endX = frame.right; 845 846 float maxStringWidth = endX - startX - (2 * kMinSeparatorStubX 847 + 2 * kStubToStringSlotX); 848 849 // ToDo: 850 // handle case where maxStringWidth turns out negative here 851 852 BString truncatedLabel(Label()); 853 parent->TruncateString(&truncatedLabel, B_TRUNCATE_END, maxStringWidth); 854 855 maxStringWidth = parent->StringWidth(truncatedLabel.String()); 856 857 // first calculate the length of the stub part of the 858 // divider line, so we can use it for secondStartX 859 float firstEndX = ((endX - startX) - maxStringWidth) / 2 860 - kStubToStringSlotX; 861 if (firstEndX < 0) 862 firstEndX = 0; 863 864 float secondStartX = endX - firstEndX; 865 866 // now finish calculating firstEndX 867 firstEndX += startX; 868 869 parent->PushState(); 870 871 int32 y = (int32) (frame.top + (frame.bottom - frame.top) / 2); 872 873 parent->BeginLineArray(minfo.separator == 2 ? 6 : 4); 874 parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y), 875 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 876 parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y), 877 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 878 879 if (minfo.separator == 2) { 880 y++; 881 frame.left++; 882 frame.right--; 883 parent->AddLine(BPoint(frame.left,y), BPoint(firstEndX, y), 884 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 885 parent->AddLine(BPoint(secondStartX,y), BPoint(frame.right, y), 886 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 887 } 888 y++; 889 if (minfo.separator == 2) { 890 frame.left++; 891 frame.right--; 892 } 893 parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y), 894 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 895 parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y), 896 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 897 898 parent->EndLineArray(); 899 900 font_height finfo; 901 parent->GetFontHeight(&finfo); 902 903 parent->SetLowColor(parent->ViewColor()); 904 BPoint loc(firstEndX + kStubToStringSlotX, 905 ContentLocation().y + finfo.ascent); 906 907 parent->MovePenTo(loc + BPoint(1, 1)); 908 parent->SetHighColor(ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 909 parent->DrawString(truncatedLabel.String()); 910 911 parent->MovePenTo(loc); 912 parent->SetHighColor(ShiftMenuBackgroundColor(B_DISABLED_LABEL_TINT)); 913 parent->DrawString(truncatedLabel.String()); 914 915 parent->PopState(); 916 } 917 918 919 // #pragma mark - 920 921 922 ShortcutFilter::ShortcutFilter(uint32 shortcutKey, uint32 shortcutModifier, 923 uint32 shortcutWhat, BHandler* target) 924 : 925 BMessageFilter(B_KEY_DOWN), 926 fShortcutKey(shortcutKey), 927 fShortcutModifier(shortcutModifier), 928 fShortcutWhat(shortcutWhat), 929 fTarget(target) 930 { 931 } 932 933 934 filter_result 935 ShortcutFilter::Filter(BMessage* message, BHandler**) 936 { 937 if (message->what == B_KEY_DOWN) { 938 uint32 modifiers; 939 uint32 rawKeyChar = 0; 940 uint8 byte = 0; 941 int32 key = 0; 942 943 if (message->FindInt32("modifiers", (int32*)&modifiers) != B_OK 944 || message->FindInt32("raw_char", (int32*)&rawKeyChar) != B_OK 945 || message->FindInt8("byte", (int8*)&byte) != B_OK 946 || message->FindInt32("key", &key) != B_OK) 947 return B_DISPATCH_MESSAGE; 948 949 modifiers &= B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY 950 | B_OPTION_KEY | B_MENU_KEY; 951 // strip caps lock, etc. 952 953 if (modifiers == fShortcutModifier && rawKeyChar == fShortcutKey) { 954 fTarget->Looper()->PostMessage(fShortcutWhat, fTarget); 955 return B_SKIP_MESSAGE; 956 } 957 } 958 959 // let others deal with this 960 return B_DISPATCH_MESSAGE; 961 } 962 963 964 // #pragma mark - 965 966 967 namespace BPrivate { 968 969 970 void 971 EmbedUniqueVolumeInfo(BMessage* message, const BVolume* volume) 972 { 973 BDirectory rootDirectory; 974 time_t created; 975 fs_info info; 976 977 if (volume->GetRootDirectory(&rootDirectory) == B_OK 978 && rootDirectory.GetCreationTime(&created) == B_OK 979 && fs_stat_dev(volume->Device(), &info) == 0) { 980 message->AddInt32("creationDate", created); 981 message->AddInt64("capacity", volume->Capacity()); 982 message->AddString("deviceName", info.device_name); 983 message->AddString("volumeName", info.volume_name); 984 message->AddString("fshName", info.fsh_name); 985 } 986 } 987 988 989 status_t 990 MatchArchivedVolume(BVolume* result, const BMessage* message, int32 index) 991 { 992 time_t created; 993 off_t capacity; 994 995 if (message->FindInt32("creationDate", index, &created) != B_OK 996 || message->FindInt64("capacity", index, &capacity) != B_OK) 997 return B_ERROR; 998 999 BVolumeRoster roster; 1000 BVolume volume; 1001 BString deviceName, volumeName, fshName; 1002 1003 if (message->FindString("deviceName", &deviceName) == B_OK 1004 && message->FindString("volumeName", &volumeName) == B_OK 1005 && message->FindString("fshName", &fshName) == B_OK) { 1006 // New style volume identifiers: We have a couple of characteristics, 1007 // and compute a score from them. The volume with the greatest score 1008 // (if over a certain threshold) is the one we're looking for. We 1009 // pick the first volume, in case there is more than one with the 1010 // same score. 1011 dev_t foundDevice = -1; 1012 int foundScore = -1; 1013 roster.Rewind(); 1014 while (roster.GetNextVolume(&volume) == B_OK) { 1015 if (volume.IsPersistent() && volume.KnowsQuery()) { 1016 // get creation time and fs_info 1017 BDirectory root; 1018 volume.GetRootDirectory(&root); 1019 time_t cmpCreated; 1020 fs_info info; 1021 if (root.GetCreationTime(&cmpCreated) == B_OK 1022 && fs_stat_dev(volume.Device(), &info) == 0) { 1023 // compute the score 1024 int score = 0; 1025 1026 // creation time 1027 if (created == cmpCreated) 1028 score += 5; 1029 // capacity 1030 if (capacity == volume.Capacity()) 1031 score += 4; 1032 // device name 1033 if (deviceName == info.device_name) 1034 score += 3; 1035 // volume name 1036 if (volumeName == info.volume_name) 1037 score += 2; 1038 // fsh name 1039 if (fshName == info.fsh_name) 1040 score += 1; 1041 1042 // check score 1043 if (score >= 9 && score > foundScore) { 1044 foundDevice = volume.Device(); 1045 foundScore = score; 1046 } 1047 } 1048 } 1049 } 1050 if (foundDevice >= 0) 1051 return result->SetTo(foundDevice); 1052 } else { 1053 // Old style volume identifiers: We have only creation time and 1054 // capacity. Both must match. 1055 roster.Rewind(); 1056 while (roster.GetNextVolume(&volume) == B_OK) 1057 if (volume.IsPersistent() && volume.KnowsQuery()) { 1058 BDirectory root; 1059 volume.GetRootDirectory(&root); 1060 time_t cmpCreated; 1061 root.GetCreationTime(&cmpCreated); 1062 if (created == cmpCreated && capacity == volume.Capacity()) { 1063 *result = volume; 1064 return B_OK; 1065 } 1066 } 1067 } 1068 1069 return B_DEV_BAD_DRIVE_NUM; 1070 } 1071 1072 1073 void 1074 StringFromStream(BString* string, BMallocIO* stream, bool endianSwap) 1075 { 1076 int32 length; 1077 stream->Read(&length, sizeof(length)); 1078 if (endianSwap) 1079 length = SwapInt32(length); 1080 1081 if (length < 0 || length > 10000) { 1082 // TODO: should fail here 1083 PRINT(("problems instatiating a string, length probably wrong %" 1084 B_PRId32 "\n", length)); 1085 return; 1086 } 1087 1088 char* buffer = string->LockBuffer(length + 1); 1089 stream->Read(buffer, (size_t)length + 1); 1090 string->UnlockBuffer(length); 1091 } 1092 1093 1094 void 1095 StringToStream(const BString* string, BMallocIO* stream) 1096 { 1097 int32 length = string->Length(); 1098 stream->Write(&length, sizeof(int32)); 1099 stream->Write(string->String(), (size_t)string->Length() + 1); 1100 } 1101 1102 1103 int32 1104 ArchiveSize(const BString* string) 1105 { 1106 return string->Length() + 1 + (ssize_t)sizeof(int32); 1107 } 1108 1109 1110 int32 1111 CountRefs(const BMessage* message) 1112 { 1113 uint32 type; 1114 int32 count; 1115 message->GetInfo("refs", &type, &count); 1116 1117 return count; 1118 } 1119 1120 1121 static entry_ref* 1122 EachEntryRefCommon(BMessage* message, entry_ref *(*func)(entry_ref*, void*), 1123 void* passThru, int32 maxCount) 1124 { 1125 uint32 type; 1126 int32 count; 1127 message->GetInfo("refs", &type, &count); 1128 1129 if (maxCount >= 0 && count > maxCount) 1130 count = maxCount; 1131 1132 for (int32 index = 0; index < count; index++) { 1133 entry_ref ref; 1134 message->FindRef("refs", index, &ref); 1135 entry_ref* result = (func)(&ref, passThru); 1136 if (result) 1137 return result; 1138 } 1139 1140 return NULL; 1141 } 1142 1143 1144 bool 1145 ContainsEntryRef(const BMessage* message, const entry_ref* ref) 1146 { 1147 entry_ref match; 1148 for (int32 index = 0; (message->FindRef("refs", index, &match) == B_OK); 1149 index++) { 1150 if (*ref == match) 1151 return true; 1152 } 1153 1154 return false; 1155 } 1156 1157 1158 entry_ref* 1159 EachEntryRef(BMessage* message, entry_ref* (*func)(entry_ref*, void*), 1160 void* passThru) 1161 { 1162 return EachEntryRefCommon(message, func, passThru, -1); 1163 } 1164 1165 typedef entry_ref *(*EachEntryIteratee)(entry_ref *, void *); 1166 1167 1168 const entry_ref* 1169 EachEntryRef(const BMessage* message, 1170 const entry_ref* (*func)(const entry_ref*, void*), void* passThru) 1171 { 1172 return EachEntryRefCommon(const_cast<BMessage*>(message), 1173 (EachEntryIteratee)func, passThru, -1); 1174 } 1175 1176 1177 entry_ref* 1178 EachEntryRef(BMessage* message, entry_ref* (*func)(entry_ref*, void*), 1179 void* passThru, int32 maxCount) 1180 { 1181 return EachEntryRefCommon(message, func, passThru, maxCount); 1182 } 1183 1184 1185 const entry_ref * 1186 EachEntryRef(const BMessage* message, 1187 const entry_ref *(*func)(const entry_ref *, void *), void* passThru, 1188 int32 maxCount) 1189 { 1190 return EachEntryRefCommon(const_cast<BMessage *>(message), 1191 (EachEntryIteratee)func, passThru, maxCount); 1192 } 1193 1194 1195 void 1196 TruncateLeaf(BString* string) 1197 { 1198 for (int32 index = string->Length(); index >= 0; index--) { 1199 if ((*string)[index] == '/') { 1200 string->Truncate(index + 1); 1201 return; 1202 } 1203 } 1204 } 1205 1206 1207 int64 1208 StringToScalar(const char* text) 1209 { 1210 char* end; 1211 int64 val; 1212 1213 char* buffer = new char [strlen(text) + 1]; 1214 strcpy(buffer, text); 1215 1216 if (strstr(buffer, "k") || strstr(buffer, "K")) { 1217 val = strtoll(buffer, &end, 10); 1218 val *= kKBSize; 1219 } else if (strstr(buffer, "mb") || strstr(buffer, "MB")) { 1220 val = strtoll(buffer, &end, 10); 1221 val *= kMBSize; 1222 } else if (strstr(buffer, "gb") || strstr(buffer, "GB")) { 1223 val = strtoll(buffer, &end, 10); 1224 val *= kGBSize; 1225 } else if (strstr(buffer, "byte") || strstr(buffer, "BYTE")) { 1226 val = strtoll(buffer, &end, 10); 1227 val *= kGBSize; 1228 } else { 1229 // no suffix, try plain byte conversion 1230 val = strtoll(buffer, &end, 10); 1231 } 1232 1233 delete [] buffer; 1234 return val; 1235 } 1236 1237 1238 static BRect 1239 LineBounds(BPoint where, float length, bool vertical) 1240 { 1241 BRect result; 1242 result.SetLeftTop(where); 1243 result.SetRightBottom(where + BPoint(2, 2)); 1244 if (vertical) 1245 result.bottom = result.top + length; 1246 else 1247 result.right = result.left + length; 1248 1249 return result; 1250 } 1251 1252 1253 SeparatorLine::SeparatorLine(BPoint where, float length, bool vertical, 1254 const char* name) 1255 : 1256 BView(LineBounds(where, length, vertical), name, 1257 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW) 1258 { 1259 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 1260 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 1261 } 1262 1263 1264 void 1265 SeparatorLine::Draw(BRect) 1266 { 1267 BRect bounds(Bounds()); 1268 rgb_color hiliteColor = tint_color(ViewColor(), 1.5f); 1269 1270 bool vertical = (bounds.left > bounds.right - 3); 1271 BeginLineArray(2); 1272 if (vertical) { 1273 AddLine(bounds.LeftTop(), bounds.LeftBottom(), hiliteColor); 1274 AddLine(bounds.LeftTop() + BPoint(1, 0), 1275 bounds.LeftBottom() + BPoint(1, 0), kWhite); 1276 } else { 1277 AddLine(bounds.LeftTop(), bounds.RightTop(), hiliteColor); 1278 AddLine(bounds.LeftTop() + BPoint(0, 1), 1279 bounds.RightTop() + BPoint(0, 1), kWhite); 1280 } 1281 EndLineArray(); 1282 } 1283 1284 1285 void 1286 HexDump(const void* buf, int32 length) 1287 { 1288 const int32 kBytesPerLine = 16; 1289 int32 offset; 1290 unsigned char* buffer = (unsigned char*)buf; 1291 1292 for (offset = 0; ; offset += kBytesPerLine, buffer += kBytesPerLine) { 1293 int32 remain = length; 1294 int32 index; 1295 1296 printf( "0x%06x: ", (int)offset); 1297 1298 for (index = 0; index < kBytesPerLine; index++) { 1299 if (remain-- > 0) 1300 printf("%02x%c", buffer[index], remain > 0 ? ',' : ' '); 1301 else 1302 printf(" "); 1303 } 1304 1305 remain = length; 1306 printf(" \'"); 1307 for (index = 0; index < kBytesPerLine; index++) { 1308 if (remain-- > 0) 1309 printf("%c", buffer[index] > ' ' ? buffer[index] : '.'); 1310 else 1311 printf(" "); 1312 } 1313 printf("\'\n"); 1314 1315 length -= kBytesPerLine; 1316 if (length <= 0) 1317 break; 1318 } 1319 fflush(stdout); 1320 } 1321 1322 1323 void 1324 EnableNamedMenuItem(BMenu* menu, const char* itemName, bool on) 1325 { 1326 BMenuItem* item = menu->FindItem(itemName); 1327 if (item) 1328 item->SetEnabled(on); 1329 } 1330 1331 1332 void 1333 MarkNamedMenuItem(BMenu* menu, const char* itemName, bool on) 1334 { 1335 BMenuItem* item = menu->FindItem(itemName); 1336 if (item) 1337 item->SetMarked(on); 1338 } 1339 1340 1341 void 1342 EnableNamedMenuItem(BMenu* menu, uint32 commandName, bool on) 1343 { 1344 BMenuItem* item = menu->FindItem(commandName); 1345 if (item) 1346 item->SetEnabled(on); 1347 } 1348 1349 1350 void 1351 MarkNamedMenuItem(BMenu* menu, uint32 commandName, bool on) 1352 { 1353 BMenuItem* item = menu->FindItem(commandName); 1354 if (item) 1355 item->SetMarked(on); 1356 } 1357 1358 1359 void 1360 DeleteSubmenu(BMenuItem* submenuItem) 1361 { 1362 if (!submenuItem) 1363 return; 1364 1365 BMenu* menu = submenuItem->Submenu(); 1366 if (!menu) 1367 return; 1368 1369 for (;;) { 1370 BMenuItem* item = menu->RemoveItem((int32)0); 1371 if (!item) 1372 return; 1373 1374 delete item; 1375 } 1376 } 1377 1378 1379 status_t 1380 GetAppSignatureFromAttr(BFile* file, char* result) 1381 { 1382 // This call is a performance improvement that 1383 // avoids using the BAppFileInfo API when retrieving the 1384 // app signature -- the call is expensive because by default 1385 // the resource fork is scanned to read the attribute 1386 1387 #ifdef B_APP_FILE_INFO_IS_FAST 1388 BAppFileInfo appFileInfo(file); 1389 return appFileInfo.GetSignature(result); 1390 #else 1391 ssize_t readResult = file->ReadAttr(kAttrAppSignature, B_MIME_STRING_TYPE, 1392 0, result, B_MIME_TYPE_LENGTH); 1393 1394 if (readResult <= 0) 1395 return (status_t)readResult; 1396 1397 return B_OK; 1398 #endif // B_APP_FILE_INFO_IS_FAST 1399 } 1400 1401 1402 status_t 1403 GetAppIconFromAttr(BFile* file, BBitmap* result, icon_size size) 1404 { 1405 // This call is a performance improvement that 1406 // avoids using the BAppFileInfo API when retrieving the 1407 // app icons -- the call is expensive because by default 1408 // the resource fork is scanned to read the icons 1409 1410 //#ifdef B_APP_FILE_INFO_IS_FAST 1411 BAppFileInfo appFileInfo(file); 1412 return appFileInfo.GetIcon(result, size); 1413 //#else 1414 // 1415 // const char* attrName = kAttrIcon; 1416 // uint32 type = B_VECTOR_ICON_TYPE; 1417 // 1418 // // try vector icon 1419 // attr_info ainfo; 1420 // status_t ret = file->GetAttrInfo(attrName, &ainfo); 1421 // 1422 // if (ret == B_OK) { 1423 // uint8 buffer[ainfo.size]; 1424 // ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, 1425 // ainfo.size); 1426 // if (readResult == ainfo.size) { 1427 // if (BIconUtils::GetVectorIcon(buffer, ainfo.size, result) == B_OK) 1428 // return B_OK; 1429 // } 1430 // } 1431 // 1432 // // try again with R5 icons 1433 // attrName = size == B_LARGE_ICON ? kAttrLargeIcon : kAttrMiniIcon; 1434 // type = size == B_LARGE_ICON ? LARGE_ICON_TYPE : MINI_ICON_TYPE; 1435 // 1436 // ret = file->GetAttrInfo(attrName, &ainfo); 1437 // if (ret < B_OK) 1438 // return ret; 1439 // 1440 // uint8 buffer[ainfo.size]; 1441 // 1442 // ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, ainfo.size); 1443 // if (readResult <= 0) 1444 // return (status_t)readResult; 1445 // 1446 // if (result->ColorSpace() != B_CMAP8) { 1447 // ret = BIconUtils::ConvertFromCMAP8(buffer, size, size, size, result); 1448 // } else { 1449 // result->SetBits(buffer, result->BitsLength(), 0, B_CMAP8); 1450 // } 1451 // 1452 // return ret; 1453 //#endif // B_APP_FILE_INFO_IS_FAST 1454 } 1455 1456 1457 status_t 1458 GetFileIconFromAttr(BNode* file, BBitmap* result, icon_size size) 1459 { 1460 BNodeInfo fileInfo(file); 1461 return fileInfo.GetIcon(result, size); 1462 } 1463 1464 1465 void 1466 PrintToStream(rgb_color color) 1467 { 1468 printf("r:%x, g:%x, b:%x, a:%x\n", 1469 color.red, color.green, color.blue, color.alpha); 1470 } 1471 1472 1473 extern BMenuItem* 1474 EachMenuItem(BMenu* menu, bool recursive, BMenuItem* (*func)(BMenuItem *)) 1475 { 1476 int32 count = menu->CountItems(); 1477 for (int32 index = 0; index < count; index++) { 1478 BMenuItem* item = menu->ItemAt(index); 1479 BMenuItem* result = (func)(item); 1480 if (result) 1481 return result; 1482 1483 if (recursive) { 1484 BMenu* submenu = menu->SubmenuAt(index); 1485 if (submenu) 1486 return EachMenuItem(submenu, true, func); 1487 } 1488 } 1489 1490 return NULL; 1491 } 1492 1493 1494 extern const BMenuItem* 1495 EachMenuItem(const BMenu* menu, bool recursive, 1496 BMenuItem* (*func)(const BMenuItem *)) 1497 { 1498 int32 count = menu->CountItems(); 1499 for (int32 index = 0; index < count; index++) { 1500 BMenuItem* item = menu->ItemAt(index); 1501 BMenuItem* result = (func)(item); 1502 if (result) 1503 return result; 1504 1505 if (recursive) { 1506 BMenu* submenu = menu->SubmenuAt(index); 1507 if (submenu) 1508 return EachMenuItem(submenu, true, func); 1509 } 1510 } 1511 1512 return NULL; 1513 } 1514 1515 1516 PositionPassingMenuItem::PositionPassingMenuItem(const char* title, 1517 BMessage* message, char shortcut, uint32 modifiers) 1518 : 1519 BMenuItem(title, message, shortcut, modifiers) 1520 { 1521 } 1522 1523 1524 PositionPassingMenuItem::PositionPassingMenuItem(BMenu* menu, BMessage* message) 1525 : 1526 BMenuItem(menu, message) 1527 { 1528 } 1529 1530 1531 status_t 1532 PositionPassingMenuItem::Invoke(BMessage* message) 1533 { 1534 if (!Menu()) 1535 return B_ERROR; 1536 1537 if (!IsEnabled()) 1538 return B_ERROR; 1539 1540 if (!message) 1541 message = Message(); 1542 1543 if (!message) 1544 return B_BAD_VALUE; 1545 1546 BMessage clone(*message); 1547 clone.AddInt32("index", Menu()->IndexOf(this)); 1548 clone.AddInt64("when", system_time()); 1549 clone.AddPointer("source", this); 1550 1551 // embed the invoke location of the menu so that we can create 1552 // a new folder, etc. on the spot 1553 BMenu* menu = Menu(); 1554 1555 for (;;) { 1556 if (!menu->Supermenu()) 1557 break; 1558 menu = menu->Supermenu(); 1559 } 1560 1561 // use the window position only, if the item was invoked from the menu 1562 // menu->Window() points to the window the item was invoked from 1563 if (dynamic_cast<BContainerWindow*>(menu->Window()) == NULL) { 1564 LooperAutoLocker lock(menu); 1565 if (lock.IsLocked()) { 1566 BPoint invokeOrigin(menu->Window()->Frame().LeftTop()); 1567 clone.AddPoint("be:invoke_origin", invokeOrigin); 1568 } 1569 } 1570 1571 return BInvoker::Invoke(&clone); 1572 } 1573 1574 1575 bool 1576 BootedInSafeMode() 1577 { 1578 const char* safeMode = getenv("SAFEMODE"); 1579 return (safeMode && strcmp(safeMode, "yes") == 0); 1580 } 1581 1582 1583 float 1584 ComputeTypeAheadScore(const char* text, const char* match, bool wordMode) 1585 { 1586 // highest score: exact match 1587 const char* found = strcasestr(text, match); 1588 if (found != NULL) { 1589 if (found == text) 1590 return kExactMatchScore; 1591 1592 return 1.f / (found - text); 1593 } 1594 1595 // there was no exact match 1596 1597 // second best: all characters at word beginnings 1598 if (wordMode) { 1599 float score = 0; 1600 for (int32 j = 0, k = 0; match[j]; j++) { 1601 while (text[k] 1602 && tolower(text[k]) != tolower(match[j])) { 1603 k++; 1604 } 1605 if (text[k] == '\0') { 1606 score = 0; 1607 break; 1608 } 1609 1610 bool wordStart = k == 0 || isspace(text[k - 1]); 1611 if (wordStart) 1612 score++; 1613 if (j > 0) { 1614 bool wordEnd = !text[k + 1] || isspace(text[k + 1]); 1615 if (wordEnd) 1616 score += 0.3; 1617 if (match[j - 1] == text[k - 1]) 1618 score += 0.7; 1619 } 1620 1621 score += 1.f / (k + 1); 1622 k++; 1623 } 1624 1625 return score; 1626 } 1627 1628 return -1; 1629 } 1630 1631 1632 void 1633 _ThrowOnError(status_t error, const char* DEBUG_ONLY(file), 1634 int32 DEBUG_ONLY(line)) 1635 { 1636 if (error != B_OK) { 1637 PRINT(("failing %s at %s:%d\n", strerror(error), file, (int)line)); 1638 throw error; 1639 } 1640 } 1641 1642 1643 void 1644 _ThrowIfNotSize(ssize_t size, const char* DEBUG_ONLY(file), 1645 int32 DEBUG_ONLY(line)) 1646 { 1647 if (size < B_OK) { 1648 PRINT(("failing %s at %s:%d\n", strerror(size), file, (int)line)); 1649 throw (status_t)size; 1650 } 1651 } 1652 1653 1654 void 1655 _ThrowOnError(status_t error, const char* DEBUG_ONLY(debugString), 1656 const char* DEBUG_ONLY(file), int32 DEBUG_ONLY(line)) 1657 { 1658 if (error != B_OK) { 1659 PRINT(("failing %s, %s at %s:%d\n", debugString, strerror(error), file, 1660 (int)line)); 1661 throw error; 1662 } 1663 } 1664 1665 } // namespace BPrivate 1666