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