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 const rgb_color kBlack = {0, 0, 0, 255}; 85 const rgb_color kWhite = {255, 255, 255, 255}; 86 87 88 bool gLocalizedNamePreferred; 89 90 91 uint32 92 HashString(const char *string, uint32 seed) 93 { 94 char ch; 95 uint32 result = seed; 96 97 while((ch = *string++) != 0) { 98 result = (result << 7) ^ (result >> 24); 99 result ^= ch; 100 } 101 102 result ^= result << 12; 103 return result; 104 } 105 106 107 uint32 108 AttrHashString(const char *string, uint32 type) 109 { 110 char c; 111 uint32 hash = 0; 112 113 while((c = *string++) != 0) { 114 hash = (hash << 7) ^ (hash >> 24); 115 hash ^= c; 116 } 117 118 hash ^= hash << 12; 119 120 hash &= ~0xff; 121 hash |= type; 122 123 return hash; 124 } 125 126 127 bool 128 ValidateStream(BMallocIO *stream, uint32 key, int32 version) 129 { 130 uint32 testKey; 131 int32 testVersion; 132 133 if (stream->Read(&testKey, sizeof(uint32)) <= 0 134 || stream->Read(&testVersion, sizeof(int32)) <=0) 135 return false; 136 137 return testKey == key && testVersion == version; 138 } 139 140 141 void 142 DisallowFilenameKeys(BTextView *textView) 143 { 144 textView->DisallowChar('/'); 145 } 146 147 148 void 149 DisallowMetaKeys(BTextView *textView) 150 { 151 textView->DisallowChar(B_TAB); 152 textView->DisallowChar(B_ESCAPE); 153 textView->DisallowChar(B_INSERT); 154 textView->DisallowChar(B_DELETE); 155 textView->DisallowChar(B_HOME); 156 textView->DisallowChar(B_END); 157 textView->DisallowChar(B_PAGE_UP); 158 textView->DisallowChar(B_PAGE_DOWN); 159 textView->DisallowChar(B_FUNCTION_KEY); 160 } 161 162 163 PeriodicUpdatePoses::PeriodicUpdatePoses() 164 : 165 fPoseList(20, true) 166 { 167 fLock = new Benaphore("PeriodicUpdatePoses"); 168 } 169 170 171 PeriodicUpdatePoses::~PeriodicUpdatePoses() 172 { 173 fLock->Lock(); 174 fPoseList.MakeEmpty(); 175 delete fLock; 176 } 177 178 179 void 180 PeriodicUpdatePoses::AddPose(BPose *pose, BPoseView *poseView, 181 PeriodicUpdateCallback callback, void *cookie) 182 { 183 periodic_pose *periodic = new periodic_pose; 184 periodic->pose = pose; 185 periodic->pose_view = poseView; 186 periodic->callback = callback; 187 periodic->cookie = cookie; 188 fPoseList.AddItem(periodic); 189 } 190 191 192 bool 193 PeriodicUpdatePoses::RemovePose(BPose *pose, void **cookie) 194 { 195 int32 count = fPoseList.CountItems(); 196 for (int32 index = 0; index < count; index++) { 197 if (fPoseList.ItemAt(index)->pose == pose) { 198 if (!fLock->Lock()) 199 return false; 200 201 periodic_pose *periodic = fPoseList.RemoveItemAt(index); 202 if (cookie) 203 *cookie = periodic->cookie; 204 delete periodic; 205 fLock->Unlock(); 206 return true; 207 } 208 } 209 210 return false; 211 } 212 213 214 void 215 PeriodicUpdatePoses::DoPeriodicUpdate(bool forceRedraw) 216 { 217 if (!fLock->Lock()) 218 return; 219 220 int32 count = fPoseList.CountItems(); 221 for (int32 index = 0; index < count; index++) { 222 periodic_pose *periodic = fPoseList.ItemAt(index); 223 if (periodic->callback(periodic->pose, periodic->cookie) 224 || forceRedraw) { 225 periodic->pose_view->LockLooper(); 226 periodic->pose_view->UpdateIcon(periodic->pose); 227 periodic->pose_view->UnlockLooper(); 228 } 229 } 230 231 fLock->Unlock(); 232 } 233 234 235 PeriodicUpdatePoses gPeriodicUpdatePoses; 236 237 238 } // namespace BPrivate 239 240 241 void 242 PoseInfo::EndianSwap(void *castToThis) 243 { 244 PoseInfo *self = (PoseInfo *)castToThis; 245 246 PRINT(("swapping PoseInfo\n")); 247 248 STATIC_ASSERT(sizeof(ino_t) == sizeof(int64)); 249 self->fInitedDirectory = SwapInt64(self->fInitedDirectory); 250 swap_data(B_POINT_TYPE, &self->fLocation, sizeof(BPoint), B_SWAP_ALWAYS); 251 252 // do a sanity check on the icon position 253 if (self->fLocation.x < -20000 || self->fLocation.x > 20000 254 || self->fLocation.y < -20000 || self->fLocation.y > 20000) { 255 // position out of range, force autoplcemement 256 PRINT((" rejecting icon position out of range\n")); 257 self->fInitedDirectory = -1LL; 258 self->fLocation = BPoint(0, 0); 259 } 260 } 261 262 263 void 264 PoseInfo::PrintToStream() 265 { 266 PRINT(("%s, inode:%Lx, location %f %f\n", fInvisible ? "hidden" : "visible", 267 fInitedDirectory, fLocation.x, fLocation.y)); 268 } 269 270 271 // #pragma mark - 272 273 274 size_t 275 ExtendedPoseInfo::Size() const 276 { 277 return sizeof(ExtendedPoseInfo) + fNumFrames * sizeof(FrameLocation); 278 } 279 280 281 size_t 282 ExtendedPoseInfo::Size(int32 count) 283 { 284 return sizeof(ExtendedPoseInfo) + count * sizeof(FrameLocation); 285 } 286 287 288 size_t 289 ExtendedPoseInfo::SizeWithHeadroom() const 290 { 291 return sizeof(ExtendedPoseInfo) + (fNumFrames + 1) * 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 */ 478 void 479 FadeRGBA32Horizontal(uint32 *bits, int32 width, int32 height, int32 from, 480 int32 to) 481 { 482 // check parameters 483 if (width < 0 || height < 0 || from < 0 || to < 0) 484 return; 485 486 float change = 1.f / (to - from); 487 if (from > to) { 488 int32 temp = from; 489 from = to; 490 to = temp; 491 } 492 493 for (int32 y = 0; y < height; y++) { 494 float alpha = change > 0 ? 0.0f : 1.0f; 495 496 for (int32 x = from; x <= to; x++) { 497 if (bits[x] & 0xff000000) { 498 uint32 a = uint32((bits[x] >> 24) * alpha); 499 bits[x] = (bits[x] & 0x00ffffff) | (a << 24); 500 } 501 alpha += change; 502 } 503 bits += width; 504 } 505 } 506 507 508 /*! Changes the alpha value of the given bitmap to create a nice 509 vertical fade out in the specified region. 510 "from" is always transparent, "to" opaque. 511 */ 512 void 513 FadeRGBA32Vertical(uint32 *bits, int32 width, int32 height, int32 from, 514 int32 to) 515 { 516 // check parameters 517 if (width < 0 || height < 0 || from < 0 || to < 0) 518 return; 519 520 if (from > to) 521 bits += width * (height - (from - to)); 522 523 float change = 1.f / (to - from); 524 if (from > to) { 525 int32 temp = from; 526 from = to; 527 to = temp; 528 } 529 530 float alpha = change > 0 ? 0.0f : 1.0f; 531 532 for (int32 y = from; y <= to; y++) { 533 for (int32 x = 0; x < width; x++) { 534 if (bits[x] & 0xff000000) { 535 uint32 a = uint32((bits[x] >> 24) * alpha); 536 bits[x] = (bits[x] & 0x00ffffff) | (a << 24); 537 } 538 } 539 alpha += change; 540 bits += width; 541 } 542 } 543 544 545 } // namespace BPrivate 546 547 548 // #pragma mark - 549 550 551 DraggableIcon::DraggableIcon(BRect rect, const char *name, const char *mimeType, 552 icon_size size, const BMessage *message, BMessenger target, 553 uint32 resizeMask, uint32 flags) 554 : 555 BView(rect, name, resizeMask, flags), 556 fMessage(*message), 557 fTarget(target) 558 { 559 fBitmap = new BBitmap(Bounds(), kDefaultIconDepth); 560 BMimeType mime(mimeType); 561 status_t error = mime.GetIcon(fBitmap, size); 562 ASSERT(mime.IsValid()); 563 if (error != B_OK) { 564 PRINT(("failed to get icon for %s, %s\n", mimeType, strerror(error))); 565 BMimeType mime(B_FILE_MIMETYPE); 566 ASSERT(mime.IsInstalled()); 567 mime.GetIcon(fBitmap, size); 568 } 569 } 570 571 572 DraggableIcon::~DraggableIcon() 573 { 574 delete fBitmap; 575 } 576 577 578 void 579 DraggableIcon::SetTarget(BMessenger target) 580 { 581 fTarget = target; 582 } 583 584 585 BRect 586 DraggableIcon::PreferredRect(BPoint offset, icon_size size) 587 { 588 BRect result(0, 0, size - 1, size - 1); 589 result.OffsetTo(offset); 590 return result; 591 } 592 593 594 void 595 DraggableIcon::AttachedToWindow() 596 { 597 BView *parent = Parent(); 598 if (parent != NULL) { 599 SetViewColor(parent->ViewColor()); 600 SetLowColor(parent->LowColor()); 601 } 602 } 603 604 605 void 606 DraggableIcon::MouseDown(BPoint point) 607 { 608 if (!DragStarted(&fMessage)) 609 return; 610 611 BRect rect(Bounds()); 612 BBitmap *dragBitmap = new BBitmap(rect, B_RGBA32, true); 613 dragBitmap->Lock(); 614 BView *view = new BView(dragBitmap->Bounds(), "", B_FOLLOW_NONE, 0); 615 dragBitmap->AddChild(view); 616 view->SetOrigin(0, 0); 617 BRect clipRect(view->Bounds()); 618 BRegion newClip; 619 newClip.Set(clipRect); 620 view->ConstrainClippingRegion(&newClip); 621 622 // Transparent draw magic 623 view->SetHighColor(0, 0, 0, 0); 624 view->FillRect(view->Bounds()); 625 view->SetDrawingMode(B_OP_ALPHA); 626 view->SetHighColor(0, 0, 0, 128); 627 // set the level of transparency by value 628 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE); 629 view->DrawBitmap(fBitmap); 630 view->Sync(); 631 dragBitmap->Unlock(); 632 DragMessage(&fMessage, dragBitmap, B_OP_ALPHA, point, fTarget.Target(0)); 633 } 634 635 636 bool 637 DraggableIcon::DragStarted(BMessage *) 638 { 639 return true; 640 } 641 642 643 void 644 DraggableIcon::Draw(BRect) 645 { 646 SetDrawingMode(B_OP_ALPHA); 647 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 648 DrawBitmap(fBitmap); 649 } 650 651 652 // #pragma mark - 653 654 655 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char *name, 656 const char *text, uint32 resizeFlags, uint32 flags) 657 : 658 BStringView(bounds, name, text, resizeFlags, flags), 659 fBitmap(NULL), 660 fOrigBitmap(NULL) 661 { 662 } 663 664 665 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char *name, 666 const char *text, BBitmap *inBitmap, uint32 resizeFlags, uint32 flags) 667 : 668 BStringView(bounds, name, text, resizeFlags, flags), 669 fBitmap(NULL), 670 fOrigBitmap(inBitmap) 671 { 672 } 673 674 675 FlickerFreeStringView::~FlickerFreeStringView() 676 { 677 delete fBitmap; 678 } 679 680 681 void 682 FlickerFreeStringView::Draw(BRect) 683 { 684 BRect bounds(Bounds()); 685 if (!fBitmap) 686 fBitmap = new OffscreenBitmap(Bounds()); 687 688 BView *offscreen = fBitmap->BeginUsing(bounds); 689 690 if (Parent()) { 691 fViewColor = Parent()->ViewColor(); 692 fLowColor = Parent()->ViewColor(); 693 } 694 695 offscreen->SetViewColor(fViewColor); 696 offscreen->SetHighColor(HighColor()); 697 offscreen->SetLowColor(fLowColor); 698 699 BFont font; 700 GetFont(&font); 701 offscreen->SetFont(&font); 702 703 offscreen->Sync(); 704 if (fOrigBitmap) 705 offscreen->DrawBitmap(fOrigBitmap, Frame(), bounds); 706 else 707 offscreen->FillRect(bounds, B_SOLID_LOW); 708 709 if (Text()) { 710 BPoint loc; 711 712 font_height height; 713 GetFontHeight(&height); 714 715 edge_info eInfo; 716 switch (Alignment()) { 717 case B_ALIGN_LEFT: 718 case B_ALIGN_HORIZONTAL_UNSET: 719 case B_ALIGN_USE_FULL_WIDTH: 720 { 721 // If the first char has a negative left edge give it 722 // some more room by shifting that much more to the right. 723 font.GetEdges(Text(), 1, &eInfo); 724 loc.x = bounds.left + (2 - eInfo.left); 725 break; 726 } 727 728 case B_ALIGN_CENTER: 729 { 730 float width = StringWidth(Text()); 731 float center = (bounds.right - bounds.left) / 2; 732 loc.x = center - (width/2); 733 break; 734 } 735 736 case B_ALIGN_RIGHT: 737 { 738 float width = StringWidth(Text()); 739 loc.x = bounds.right - width - 2; 740 break; 741 } 742 } 743 loc.y = bounds.bottom - (1 + height.descent); 744 offscreen->DrawString(Text(), loc); 745 } 746 offscreen->Sync(); 747 SetDrawingMode(B_OP_COPY); 748 DrawBitmap(fBitmap->Bitmap()); 749 fBitmap->DoneUsing(); 750 } 751 752 753 void 754 FlickerFreeStringView::AttachedToWindow() 755 { 756 _inherited::AttachedToWindow(); 757 if (Parent()) { 758 fViewColor = Parent()->ViewColor(); 759 fLowColor = Parent()->ViewColor(); 760 } 761 SetViewColor(B_TRANSPARENT_32_BIT); 762 SetLowColor(B_TRANSPARENT_32_BIT); 763 } 764 765 766 void 767 FlickerFreeStringView::SetViewColor(rgb_color color) 768 { 769 if (fViewColor != color) { 770 fViewColor = color; 771 Invalidate(); 772 } 773 _inherited::SetViewColor(B_TRANSPARENT_32_BIT); 774 } 775 776 777 void 778 FlickerFreeStringView::SetLowColor(rgb_color color) 779 { 780 if (fLowColor != color) { 781 fLowColor = color; 782 Invalidate(); 783 } 784 _inherited::SetLowColor(B_TRANSPARENT_32_BIT); 785 } 786 787 788 // #pragma mark - 789 790 791 TitledSeparatorItem::TitledSeparatorItem(const char *label) 792 : 793 BMenuItem(label, 0) 794 { 795 _inherited::SetEnabled(false); 796 } 797 798 799 TitledSeparatorItem::~TitledSeparatorItem() 800 { 801 } 802 803 804 void 805 TitledSeparatorItem::SetEnabled(bool) 806 { 807 // leave disabled 808 } 809 810 811 void 812 TitledSeparatorItem::GetContentSize(float *width, float *height) 813 { 814 _inherited::GetContentSize(width, height); 815 } 816 817 818 inline rgb_color 819 ShiftMenuBackgroundColor(float by) 820 { 821 return tint_color(ui_color(B_MENU_BACKGROUND_COLOR), by); 822 } 823 824 825 void 826 TitledSeparatorItem::Draw() 827 { 828 BRect frame(Frame()); 829 830 BMenu *parent = Menu(); 831 ASSERT(parent); 832 833 menu_info minfo; 834 get_menu_info(&minfo); 835 836 if (minfo.separator > 0) { 837 frame.left += 10; 838 frame.right -= 10; 839 } else { 840 frame.left += 1; 841 frame.right -= 1; 842 } 843 844 float startX = frame.left; 845 float endX = frame.right; 846 847 float maxStringWidth = endX - startX - (2 * kMinSeparatorStubX 848 + 2 * kStubToStringSlotX); 849 850 // ToDo: 851 // handle case where maxStringWidth turns out negative here 852 853 BString truncatedLabel(Label()); 854 parent->TruncateString(&truncatedLabel, B_TRUNCATE_END, maxStringWidth); 855 856 maxStringWidth = parent->StringWidth(truncatedLabel.String()); 857 858 // first calculate the length of the stub part of the 859 // divider line, so we can use it for secondStartX 860 float firstEndX = ((endX - startX) - maxStringWidth) / 2 861 - kStubToStringSlotX; 862 if (firstEndX < 0) 863 firstEndX = 0; 864 865 float secondStartX = endX - firstEndX; 866 867 // now finish calculating firstEndX 868 firstEndX += startX; 869 870 parent->PushState(); 871 872 int32 y = (int32) (frame.top + (frame.bottom - frame.top) / 2); 873 874 parent->BeginLineArray(minfo.separator == 2 ? 6 : 4); 875 parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y), 876 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 877 parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y), 878 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 879 880 if (minfo.separator == 2) { 881 y++; 882 frame.left++; 883 frame.right--; 884 parent->AddLine(BPoint(frame.left,y), BPoint(firstEndX, y), 885 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 886 parent->AddLine(BPoint(secondStartX,y), BPoint(frame.right, y), 887 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 888 } 889 y++; 890 if (minfo.separator == 2) { 891 frame.left++; 892 frame.right--; 893 } 894 parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y), 895 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 896 parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y), 897 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 898 899 parent->EndLineArray(); 900 901 font_height finfo; 902 parent->GetFontHeight(&finfo); 903 904 parent->SetLowColor(parent->ViewColor()); 905 BPoint loc(firstEndX + kStubToStringSlotX, 906 ContentLocation().y + finfo.ascent); 907 908 parent->MovePenTo(loc + BPoint(1, 1)); 909 parent->SetHighColor(ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 910 parent->DrawString(truncatedLabel.String()); 911 912 parent->MovePenTo(loc); 913 parent->SetHighColor(ShiftMenuBackgroundColor(B_DISABLED_LABEL_TINT)); 914 parent->DrawString(truncatedLabel.String()); 915 916 parent->PopState(); 917 } 918 919 920 // #pragma mark - 921 922 923 ShortcutFilter::ShortcutFilter(uint32 shortcutKey, uint32 shortcutModifier, 924 uint32 shortcutWhat, BHandler *target) 925 : 926 BMessageFilter(B_KEY_DOWN), 927 fShortcutKey(shortcutKey), 928 fShortcutModifier(shortcutModifier), 929 fShortcutWhat(shortcutWhat), 930 fTarget(target) 931 { 932 } 933 934 935 filter_result 936 ShortcutFilter::Filter(BMessage *message, BHandler **) 937 { 938 if (message->what == B_KEY_DOWN) { 939 uint32 modifiers; 940 uint32 rawKeyChar = 0; 941 uint8 byte = 0; 942 int32 key = 0; 943 944 if (message->FindInt32("modifiers", (int32 *)&modifiers) != B_OK 945 || message->FindInt32("raw_char", (int32 *)&rawKeyChar) != B_OK 946 || message->FindInt8("byte", (int8 *)&byte) != B_OK 947 || message->FindInt32("key", &key) != B_OK) 948 return B_DISPATCH_MESSAGE; 949 950 modifiers &= B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY 951 | B_OPTION_KEY | B_MENU_KEY; 952 // strip caps lock, etc. 953 954 if (modifiers == fShortcutModifier && rawKeyChar == fShortcutKey) { 955 fTarget->Looper()->PostMessage(fShortcutWhat, fTarget); 956 return B_SKIP_MESSAGE; 957 } 958 } 959 960 // let others deal with this 961 return B_DISPATCH_MESSAGE; 962 } 963 964 965 // #pragma mark - 966 967 968 namespace BPrivate { 969 970 971 void 972 EmbedUniqueVolumeInfo(BMessage *message, const BVolume *volume) 973 { 974 BDirectory rootDirectory; 975 time_t created; 976 fs_info info; 977 978 if (volume->GetRootDirectory(&rootDirectory) == B_OK 979 && rootDirectory.GetCreationTime(&created) == B_OK 980 && fs_stat_dev(volume->Device(), &info) == 0) { 981 message->AddInt32("creationDate", created); 982 message->AddInt64("capacity", volume->Capacity()); 983 message->AddString("deviceName", info.device_name); 984 message->AddString("volumeName", info.volume_name); 985 message->AddString("fshName", info.fsh_name); 986 } 987 } 988 989 990 status_t 991 MatchArchivedVolume(BVolume *result, const BMessage *message, int32 index) 992 { 993 time_t created; 994 off_t capacity; 995 996 if (message->FindInt32("creationDate", index, &created) != B_OK 997 || message->FindInt64("capacity", index, &capacity) != B_OK) 998 return B_ERROR; 999 1000 BVolumeRoster roster; 1001 BVolume volume; 1002 BString deviceName, volumeName, fshName; 1003 1004 if (message->FindString("deviceName", &deviceName) == B_OK 1005 && message->FindString("volumeName", &volumeName) == B_OK 1006 && message->FindString("fshName", &fshName) == B_OK) { 1007 // New style volume identifiers: We have a couple of characteristics, 1008 // and compute a score from them. The volume with the greatest score 1009 // (if over a certain threshold) is the one we're looking for. We 1010 // pick the first volume, in case there is more than one with the 1011 // same score. 1012 dev_t foundDevice = -1; 1013 int foundScore = -1; 1014 roster.Rewind(); 1015 while (roster.GetNextVolume(&volume) == B_OK) { 1016 if (volume.IsPersistent() && volume.KnowsQuery()) { 1017 // get creation time and fs_info 1018 BDirectory root; 1019 volume.GetRootDirectory(&root); 1020 time_t cmpCreated; 1021 fs_info info; 1022 if (root.GetCreationTime(&cmpCreated) == B_OK 1023 && fs_stat_dev(volume.Device(), &info) == 0) { 1024 // compute the score 1025 int score = 0; 1026 1027 // creation time 1028 if (created == cmpCreated) 1029 score += 5; 1030 // capacity 1031 if (capacity == volume.Capacity()) 1032 score += 4; 1033 // device name 1034 if (deviceName == info.device_name) 1035 score += 3; 1036 // volume name 1037 if (volumeName == info.volume_name) 1038 score += 2; 1039 // fsh name 1040 if (fshName == info.fsh_name) 1041 score += 1; 1042 1043 // check score 1044 if (score >= 9 && score > foundScore) { 1045 foundDevice = volume.Device(); 1046 foundScore = score; 1047 } 1048 } 1049 } 1050 } 1051 if (foundDevice >= 0) 1052 return result->SetTo(foundDevice); 1053 } else { 1054 // Old style volume identifiers: We have only creation time and 1055 // capacity. Both must match. 1056 roster.Rewind(); 1057 while (roster.GetNextVolume(&volume) == B_OK) 1058 if (volume.IsPersistent() && volume.KnowsQuery()) { 1059 BDirectory root; 1060 volume.GetRootDirectory(&root); 1061 time_t cmpCreated; 1062 root.GetCreationTime(&cmpCreated); 1063 if (created == cmpCreated && capacity == volume.Capacity()) { 1064 *result = volume; 1065 return B_OK; 1066 } 1067 } 1068 } 1069 1070 return B_DEV_BAD_DRIVE_NUM; 1071 } 1072 1073 1074 void 1075 StringFromStream(BString *string, BMallocIO *stream, bool endianSwap) 1076 { 1077 int32 length; 1078 stream->Read(&length, sizeof(length)); 1079 if (endianSwap) 1080 length = SwapInt32(length); 1081 1082 if (length < 0 || length > 10000) { 1083 // TODO: should fail here 1084 PRINT(("problems instatiating a string, length probably wrong %" 1085 B_PRId32 "\n", length)); 1086 return; 1087 } 1088 1089 char *buffer = string->LockBuffer(length + 1); 1090 stream->Read(buffer, (size_t)length + 1); 1091 string->UnlockBuffer(length); 1092 } 1093 1094 1095 void 1096 StringToStream(const BString *string, BMallocIO *stream) 1097 { 1098 int32 length = string->Length(); 1099 stream->Write(&length, sizeof(int32)); 1100 stream->Write(string->String(), (size_t)string->Length() + 1); 1101 } 1102 1103 1104 int32 1105 ArchiveSize(const BString *string) 1106 { 1107 return string->Length() + 1 + (ssize_t)sizeof(int32); 1108 } 1109 1110 1111 int32 1112 CountRefs(const BMessage *message) 1113 { 1114 uint32 type; 1115 int32 count; 1116 message->GetInfo("refs", &type, &count); 1117 1118 return count; 1119 } 1120 1121 1122 static entry_ref * 1123 EachEntryRefCommon(BMessage *message, entry_ref *(*func)(entry_ref *, void *), 1124 void *passThru, int32 maxCount) 1125 { 1126 uint32 type; 1127 int32 count; 1128 message->GetInfo("refs", &type, &count); 1129 1130 if (maxCount >= 0 && count > maxCount) 1131 count = maxCount; 1132 1133 for (int32 index = 0; index < count; index++) { 1134 entry_ref ref; 1135 message->FindRef("refs", index, &ref); 1136 entry_ref *result = (func)(&ref, passThru); 1137 if (result) 1138 return result; 1139 } 1140 1141 return NULL; 1142 } 1143 1144 1145 bool 1146 ContainsEntryRef(const BMessage *message, const entry_ref *ref) 1147 { 1148 entry_ref match; 1149 for (int32 index = 0; (message->FindRef("refs", index, &match) == B_OK); 1150 index++) { 1151 if (*ref == match) 1152 return true; 1153 } 1154 1155 return false; 1156 } 1157 1158 1159 entry_ref * 1160 EachEntryRef(BMessage *message, entry_ref *(*func)(entry_ref *, void *), 1161 void *passThru) 1162 { 1163 return EachEntryRefCommon(message, func, passThru, -1); 1164 } 1165 1166 typedef entry_ref *(*EachEntryIteratee)(entry_ref *, void *); 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 1666 } // namespace BPrivate 1667