1 /* 2 * Copyright 2002-2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Mattias Sundblad 7 * Andrew Bachmann 8 * Philippe Saint-Pierre 9 * Jonas Sundström 10 */ 11 12 13 #include "Constants.h" 14 #include "ColorMenuItem.h" 15 #include "FindWindow.h" 16 #include "ReplaceWindow.h" 17 #include "StyledEditApp.h" 18 #include "StyledEditView.h" 19 #include "StyledEditWindow.h" 20 21 #include <Alert.h> 22 #include <Autolock.h> 23 #include <Catalog.h> 24 #include <CharacterSet.h> 25 #include <CharacterSetRoster.h> 26 #include <Clipboard.h> 27 #include <Debug.h> 28 #include <File.h> 29 #include <FilePanel.h> 30 #include <fs_attr.h> 31 #include <Locale.h> 32 #include <Menu.h> 33 #include <MenuBar.h> 34 #include <MenuItem.h> 35 #include <Path.h> 36 #include <PrintJob.h> 37 #include <Rect.h> 38 #include <Roster.h> 39 #include <Screen.h> 40 #include <ScrollView.h> 41 #include <TextControl.h> 42 #include <TextView.h> 43 #include <TranslationUtils.h> 44 45 46 using namespace BPrivate; 47 48 49 const float kLineViewWidth = 30.0; 50 const char* kInfoAttributeName = "StyledEdit-info"; 51 52 53 #undef B_TRANSLATE_CONTEXT 54 #define B_TRANSLATE_CONTEXT "StyledEditWindow" 55 56 57 // This is a temporary solution for building BString with printf like format. 58 // will be removed in the future. 59 static void 60 bs_printf(BString* string, const char* format, ...) 61 { 62 va_list ap; 63 va_start(ap, format); 64 char* buf; 65 vasprintf(&buf, format, ap); 66 string->SetTo(buf); 67 free(buf); 68 va_end(ap); 69 } 70 71 72 // #pragma mark - 73 74 75 StyledEditWindow::StyledEditWindow(BRect frame, int32 id, uint32 encoding) 76 : BWindow(frame, "untitled", B_DOCUMENT_WINDOW, B_ASYNCHRONOUS_CONTROLS) 77 { 78 InitWindow(encoding); 79 BString unTitled(B_TRANSLATE("Untitled ")); 80 unTitled << id; 81 SetTitle(unTitled.String()); 82 fSaveItem->SetEnabled(true); 83 // allow saving empty files 84 Show(); 85 } 86 87 88 StyledEditWindow::StyledEditWindow(BRect frame, entry_ref* ref, uint32 encoding) 89 : BWindow(frame, "untitled", B_DOCUMENT_WINDOW, B_ASYNCHRONOUS_CONTROLS) 90 { 91 InitWindow(encoding); 92 OpenFile(ref); 93 Show(); 94 } 95 96 97 StyledEditWindow::~StyledEditWindow() 98 { 99 delete fSaveMessage; 100 delete fPrintSettings; 101 delete fSavePanel; 102 } 103 104 105 #undef B_TRANSLATE_CONTEXT 106 #define B_TRANSLATE_CONTEXT "Menus" 107 108 109 void 110 StyledEditWindow::InitWindow(uint32 encoding) 111 { 112 fPrintSettings = NULL; 113 fSaveMessage = NULL; 114 115 // undo modes 116 fUndoFlag = false; 117 fCanUndo = false; 118 fRedoFlag = false; 119 fCanRedo = false; 120 121 // clean modes 122 fUndoCleans = false; 123 fRedoCleans = false; 124 fClean = true; 125 126 // search- state 127 fReplaceString = ""; 128 fStringToFind = ""; 129 fCaseSens = false; 130 fWrapAround = false; 131 fBackSearch = false; 132 133 // add menubar 134 fMenuBar = new BMenuBar(BRect(0, 0, 0, 0), "menubar"); 135 AddChild(fMenuBar); 136 137 // add textview and scrollview 138 139 BRect viewFrame = Bounds(); 140 viewFrame.top = fMenuBar->Bounds().Height() + 1; 141 viewFrame.right -= B_V_SCROLL_BAR_WIDTH; 142 viewFrame.left = 0; 143 viewFrame.bottom -= B_H_SCROLL_BAR_HEIGHT; 144 145 BRect textBounds = viewFrame; 146 textBounds.OffsetTo(B_ORIGIN); 147 textBounds.InsetBy(TEXT_INSET, TEXT_INSET); 148 149 fTextView= new StyledEditView(viewFrame, textBounds, this); 150 fTextView->SetDoesUndo(true); 151 fTextView->SetStylable(true); 152 fTextView->SetEncoding(encoding); 153 154 fScrollView = new BScrollView("scrollview", fTextView, B_FOLLOW_ALL, 0, 155 true, true, B_PLAIN_BORDER); 156 AddChild(fScrollView); 157 fTextView->MakeFocus(true); 158 159 // Add "File"-menu: 160 BMenu* menu = new BMenu(B_TRANSLATE("File")); 161 fMenuBar->AddItem(menu); 162 163 BMenuItem* menuItem; 164 menu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("New"), 165 new BMessage(MENU_NEW), 'N')); 166 menuItem->SetTarget(be_app); 167 168 menu->AddItem(menuItem = new BMenuItem(fRecentMenu = 169 new BMenu(B_TRANSLATE("Open" B_UTF8_ELLIPSIS)), 170 new BMessage(MENU_OPEN))); 171 menuItem->SetShortcut('O', 0); 172 menuItem->SetTarget(be_app); 173 menu->AddSeparatorItem(); 174 175 menu->AddItem(fSaveItem = new BMenuItem(B_TRANSLATE("Save"), 176 new BMessage(MENU_SAVE), 'S')); 177 fSaveItem->SetEnabled(false); 178 menu->AddItem(menuItem = new BMenuItem( 179 B_TRANSLATE("Save as" B_UTF8_ELLIPSIS), new BMessage(MENU_SAVEAS))); 180 menuItem->SetShortcut('S', B_SHIFT_KEY); 181 menuItem->SetEnabled(true); 182 183 menu->AddItem(fRevertItem = 184 new BMenuItem(B_TRANSLATE("Revert to saved" B_UTF8_ELLIPSIS), 185 new BMessage(MENU_REVERT))); 186 fRevertItem->SetEnabled(false); 187 menu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Close"), 188 new BMessage(MENU_CLOSE), 'W')); 189 190 menu->AddSeparatorItem(); 191 menu->AddItem(menuItem = new BMenuItem( 192 B_TRANSLATE("Page setup" B_UTF8_ELLIPSIS), 193 new BMessage(MENU_PAGESETUP))); 194 menu->AddItem(menuItem = new BMenuItem( 195 B_TRANSLATE("Print" B_UTF8_ELLIPSIS), 196 new BMessage(MENU_PRINT), 'P')); 197 198 menu->AddSeparatorItem(); 199 menu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Quit"), 200 new BMessage(MENU_QUIT), 'Q')); 201 202 // Add the "Edit"-menu: 203 menu = new BMenu(B_TRANSLATE("Edit")); 204 fMenuBar->AddItem(menu); 205 206 menu->AddItem(fUndoItem = new BMenuItem(B_TRANSLATE("Can't undo"), 207 new BMessage(B_UNDO), 'Z')); 208 fUndoItem->SetEnabled(false); 209 210 menu->AddSeparatorItem(); 211 menu->AddItem(fCutItem = new BMenuItem(B_TRANSLATE("Cut"), 212 new BMessage(B_CUT), 'X')); 213 fCutItem->SetEnabled(false); 214 fCutItem->SetTarget(fTextView); 215 216 menu->AddItem(fCopyItem = new BMenuItem(B_TRANSLATE("Copy"), 217 new BMessage(B_COPY), 'C')); 218 fCopyItem->SetEnabled(false); 219 fCopyItem->SetTarget(fTextView); 220 221 menu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Paste"), 222 new BMessage(B_PASTE), 'V')); 223 menuItem->SetTarget(fTextView); 224 menu->AddItem(fClearItem = new BMenuItem(B_TRANSLATE("Clear"), 225 new BMessage(MENU_CLEAR))); 226 fClearItem->SetEnabled(false); 227 fClearItem->SetTarget(fTextView); 228 229 menu->AddSeparatorItem(); 230 menu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Select all"), 231 new BMessage(B_SELECT_ALL), 'A')); 232 menuItem->SetTarget(fTextView); 233 234 menu->AddSeparatorItem(); 235 menu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Find" B_UTF8_ELLIPSIS), 236 new BMessage(MENU_FIND), 'F')); 237 menu->AddItem(fFindAgainItem= new BMenuItem(B_TRANSLATE("Find again"), 238 new BMessage(MENU_FIND_AGAIN), 'G')); 239 fFindAgainItem->SetEnabled(false); 240 241 menu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Find selection"), 242 new BMessage(MENU_FIND_SELECTION), 'H')); 243 menu->AddItem(menuItem = new BMenuItem( 244 B_TRANSLATE("Replace" B_UTF8_ELLIPSIS), 245 new BMessage(MENU_REPLACE), 'R')); 246 menu->AddItem(fReplaceSameItem = new BMenuItem(B_TRANSLATE("Replace same"), 247 new BMessage(MENU_REPLACE_SAME), 'T')); 248 fReplaceSameItem->SetEnabled(false); 249 250 // Add the "Font"-menu: 251 fFontMenu = new BMenu(B_TRANSLATE("Font")); 252 fMenuBar->AddItem(fFontMenu); 253 254 //"Size"-subMenu 255 fFontSizeMenu = new BMenu(B_TRANSLATE("Size")); 256 fFontSizeMenu->SetRadioMode(true); 257 fFontMenu->AddItem(fFontSizeMenu); 258 259 const int32 fontSizes[] = {9, 10, 11, 12, 14, 18, 24, 36, 48, 72}; 260 for (uint32 i = 0; i < sizeof(fontSizes) / sizeof(fontSizes[0]); i++) { 261 BMessage* fontMessage = new BMessage(FONT_SIZE); 262 fontMessage->AddFloat("size", fontSizes[i]); 263 264 char label[64]; 265 snprintf(label, sizeof(label), "%ld", fontSizes[i]); 266 fFontSizeMenu->AddItem(menuItem = new BMenuItem(label, fontMessage)); 267 268 if (fontSizes[i] == (int32)be_plain_font->Size()) 269 menuItem->SetMarked(true); 270 } 271 272 // "Color"-subMenu 273 fFontColorMenu = new BMenu(B_TRANSLATE("Color")); 274 fFontColorMenu->SetRadioMode(true); 275 fFontMenu->AddItem(fFontColorMenu); 276 277 fFontColorMenu->AddItem(fBlackItem = new BMenuItem(B_TRANSLATE("Black"), 278 new BMessage(FONT_COLOR))); 279 fBlackItem->SetMarked(true); 280 fFontColorMenu->AddItem(fRedItem = new ColorMenuItem(B_TRANSLATE("Red"), 281 RED, new BMessage(FONT_COLOR))); 282 fFontColorMenu->AddItem(fGreenItem = new ColorMenuItem(B_TRANSLATE("Green"), 283 GREEN, new BMessage(FONT_COLOR))); 284 fFontColorMenu->AddItem(fBlueItem = new ColorMenuItem(B_TRANSLATE("Blue"), 285 BLUE, new BMessage(FONT_COLOR))); 286 fFontColorMenu->AddItem(fCyanItem = new ColorMenuItem(B_TRANSLATE("Cyan"), 287 CYAN, new BMessage(FONT_COLOR))); 288 fFontColorMenu->AddItem(fMagentaItem = new ColorMenuItem(B_TRANSLATE("Magenta"), 289 MAGENTA, new BMessage(FONT_COLOR))); 290 fFontColorMenu->AddItem(fYellowItem = new ColorMenuItem(B_TRANSLATE("Yellow"), 291 YELLOW, new BMessage(FONT_COLOR))); 292 fFontMenu->AddSeparatorItem(); 293 294 // Available fonts 295 296 fCurrentFontItem = 0; 297 fCurrentStyleItem = 0; 298 299 BMenu* subMenu; 300 int32 numFamilies = count_font_families(); 301 for (int32 i = 0; i < numFamilies; i++) { 302 font_family family; 303 if (get_font_family(i, &family) == B_OK) { 304 subMenu = new BMenu(family); 305 subMenu->SetRadioMode(true); 306 fFontMenu->AddItem(menuItem = new BMenuItem(subMenu, 307 new BMessage(FONT_FAMILY))); 308 309 int32 numStyles = count_font_styles(family); 310 for (int32 j = 0; j < numStyles; j++) { 311 font_style style; 312 uint32 flags; 313 if (get_font_style(family, j, &style, &flags) == B_OK) { 314 subMenu->AddItem(menuItem = new BMenuItem(style, 315 new BMessage(FONT_STYLE))); 316 } 317 } 318 } 319 } 320 321 // Add the "Document"-menu: 322 menu = new BMenu(B_TRANSLATE("Document")); 323 fMenuBar->AddItem(menu); 324 325 // "Align"-subMenu: 326 subMenu = new BMenu(B_TRANSLATE("Align")); 327 subMenu->SetRadioMode(true); 328 329 subMenu->AddItem(fAlignLeft = new BMenuItem(B_TRANSLATE("Left"), 330 new BMessage(ALIGN_LEFT))); 331 fAlignLeft->SetMarked(true); 332 333 subMenu->AddItem(fAlignCenter = new BMenuItem(B_TRANSLATE("Center"), 334 new BMessage(ALIGN_CENTER))); 335 subMenu->AddItem(fAlignRight = new BMenuItem(B_TRANSLATE("Right"), 336 new BMessage(ALIGN_RIGHT))); 337 menu->AddItem(subMenu); 338 menu->AddItem(fWrapItem = new BMenuItem(B_TRANSLATE("Wrap lines"), 339 new BMessage(WRAP_LINES))); 340 fWrapItem->SetMarked(true); 341 342 fSavePanel = NULL; 343 fSavePanelEncodingMenu = NULL; 344 // build lazily 345 } 346 347 348 void 349 StyledEditWindow::LoadAttrs() 350 { 351 entry_ref dir; 352 const char* name; 353 if (fSaveMessage->FindRef("directory", &dir) != B_OK 354 || fSaveMessage->FindString("name", &name) != B_OK) 355 return; 356 357 BPath documentPath(&dir); 358 documentPath.Append(name); 359 360 BNode documentNode(documentPath.Path()); 361 if (documentNode.InitCheck() != B_OK) 362 return; 363 364 BRect newFrame; 365 ssize_t bytesRead = documentNode.ReadAttr(kInfoAttributeName, B_RECT_TYPE, 366 0, &newFrame, sizeof(BRect)); 367 if (bytesRead != sizeof(BRect)) 368 return; 369 370 swap_data(B_RECT_TYPE, &newFrame, sizeof(BRect), B_SWAP_BENDIAN_TO_HOST); 371 372 // Check if the frame in on screen, otherwise, ignore it 373 BScreen screen(this); 374 if (newFrame.Width() > 32 && newFrame.Height() > 32 375 && screen.Frame().Contains(newFrame)) { 376 MoveTo(newFrame.left, newFrame.top); 377 ResizeTo(newFrame.Width(), newFrame.Height()); 378 } 379 } 380 381 382 void 383 StyledEditWindow::SaveAttrs() 384 { 385 if (!fSaveMessage) 386 return; 387 388 entry_ref dir; 389 const char* name; 390 if (fSaveMessage->FindRef("directory", &dir) != B_OK 391 || fSaveMessage->FindString("name", &name) != B_OK) 392 return; 393 394 BPath documentPath(&dir); 395 documentPath.Append(name); 396 397 BNode documentNode(documentPath.Path()); 398 if (documentNode.InitCheck() != B_OK) 399 return; 400 401 BRect frame(Frame()); 402 swap_data(B_RECT_TYPE, &frame, sizeof(BRect), B_SWAP_HOST_TO_BENDIAN); 403 404 documentNode.WriteAttr(kInfoAttributeName, B_RECT_TYPE, 0, &frame, 405 sizeof(BRect)); 406 } 407 408 409 void 410 StyledEditWindow::MessageReceived(BMessage* message) 411 { 412 if (message->WasDropped()) { 413 entry_ref ref; 414 if (message->FindRef("refs", 0, &ref)==B_OK) { 415 message->what = B_REFS_RECEIVED; 416 be_app->PostMessage(message); 417 } 418 } 419 420 switch (message->what) { 421 // File menu 422 case MENU_SAVE: 423 if (!fSaveMessage) 424 SaveAs(); 425 else 426 Save(fSaveMessage); 427 break; 428 429 case MENU_SAVEAS: 430 SaveAs(); 431 break; 432 433 case B_SAVE_REQUESTED: 434 Save(message); 435 break; 436 437 case SAVE_THEN_QUIT: 438 if (Save(message) == B_OK) 439 Quit(); 440 break; 441 442 case MENU_REVERT: 443 RevertToSaved(); 444 break; 445 446 case MENU_CLOSE: 447 if (QuitRequested()) 448 Quit(); 449 break; 450 451 case MENU_PAGESETUP: 452 PageSetup(fTextView->Window()->Title()); 453 break; 454 case MENU_PRINT: 455 Print(fTextView->Window()->Title()); 456 break; 457 case MENU_QUIT: 458 be_app->PostMessage(B_QUIT_REQUESTED); 459 break; 460 461 // Edit menu 462 463 case B_UNDO: 464 ASSERT(fCanUndo || fCanRedo); 465 ASSERT(!(fCanUndo && fCanRedo)); 466 if (fCanUndo) 467 fUndoFlag = true; 468 if (fCanRedo) 469 fRedoFlag = true; 470 471 fTextView->Undo(be_clipboard); 472 break; 473 case B_CUT: 474 fTextView->Cut(be_clipboard); 475 break; 476 case B_COPY: 477 fTextView->Copy(be_clipboard); 478 break; 479 case B_PASTE: 480 fTextView->Paste(be_clipboard); 481 break; 482 case MENU_CLEAR: 483 fTextView->Clear(); 484 break; 485 case MENU_FIND: 486 { 487 BRect findWindowFrame(100, 100, 400, 235); 488 BWindow* window = new FindWindow(findWindowFrame, this, 489 &fStringToFind, fCaseSens, fWrapAround, fBackSearch); 490 window->Show(); 491 break; 492 } 493 case MSG_SEARCH: 494 message->FindString("findtext", &fStringToFind); 495 fFindAgainItem->SetEnabled(true); 496 message->FindBool("casesens", &fCaseSens); 497 message->FindBool("wrap", &fWrapAround); 498 message->FindBool("backsearch", &fBackSearch); 499 500 Search(fStringToFind, fCaseSens, fWrapAround, fBackSearch); 501 break; 502 case MENU_FIND_AGAIN: 503 Search(fStringToFind, fCaseSens, fWrapAround, fBackSearch); 504 break; 505 case MENU_FIND_SELECTION: 506 FindSelection(); 507 break; 508 case MENU_REPLACE: 509 { 510 BRect replaceWindowFrame(100, 100, 400, 284); 511 BWindow* window = new ReplaceWindow(replaceWindowFrame, this, 512 &fStringToFind, &fReplaceString, fCaseSens, fWrapAround, fBackSearch); 513 window->Show(); 514 break; 515 } 516 case MSG_REPLACE: 517 { 518 message->FindBool("casesens", &fCaseSens); 519 message->FindBool("wrap", &fWrapAround); 520 message->FindBool("backsearch", &fBackSearch); 521 522 message->FindString("FindText", &fStringToFind); 523 message->FindString("ReplaceText", &fReplaceString); 524 525 fFindAgainItem->SetEnabled(true); 526 fReplaceSameItem->SetEnabled(true); 527 528 Replace(fStringToFind, fReplaceString, fCaseSens, fWrapAround, fBackSearch); 529 break; 530 } 531 case MENU_REPLACE_SAME: 532 Replace(fStringToFind, fReplaceString, fCaseSens, fWrapAround, fBackSearch); 533 break; 534 535 case MSG_REPLACE_ALL: 536 { 537 message->FindBool("casesens", &fCaseSens); 538 message->FindString("FindText",&fStringToFind); 539 message->FindString("ReplaceText",&fReplaceString); 540 541 bool allWindows; 542 message->FindBool("allwindows", &allWindows); 543 544 fFindAgainItem->SetEnabled(true); 545 fReplaceSameItem->SetEnabled(true); 546 547 if (allWindows) 548 SearchAllWindows(fStringToFind, fReplaceString, fCaseSens); 549 else 550 ReplaceAll(fStringToFind, fReplaceString, fCaseSens); 551 break; 552 } 553 554 // Font menu 555 556 case FONT_SIZE: 557 { 558 float fontSize; 559 if (message->FindFloat("size", &fontSize) == B_OK) 560 SetFontSize(fontSize); 561 break; 562 } 563 case FONT_FAMILY: 564 { 565 const char* fontFamily = NULL; 566 const char* fontStyle = NULL; 567 void* ptr; 568 if (message->FindPointer("source", &ptr) == B_OK) { 569 BMenuItem* item = static_cast<BMenuItem*>(ptr); 570 fontFamily = item->Label(); 571 } 572 SetFontStyle(fontFamily, fontStyle); 573 break; 574 } 575 case FONT_STYLE: 576 { 577 const char* fontFamily = NULL; 578 const char* fontStyle = NULL; 579 void* ptr; 580 if (message->FindPointer("source", &ptr) == B_OK) { 581 BMenuItem* item = static_cast<BMenuItem*>(ptr); 582 fontStyle = item->Label(); 583 BMenu* menu = item->Menu(); 584 if (menu != NULL) { 585 BMenuItem* super_item = menu->Superitem(); 586 if (super_item != NULL) 587 fontFamily = super_item->Label(); 588 } 589 } 590 SetFontStyle(fontFamily, fontStyle); 591 break; 592 } 593 case FONT_COLOR: 594 { 595 void* ptr; 596 if (message->FindPointer("source", &ptr) == B_OK) { 597 if (ptr == fBlackItem) 598 SetFontColor(&BLACK); 599 else if (ptr == fRedItem) 600 SetFontColor(&RED); 601 else if (ptr == fGreenItem) 602 SetFontColor(&GREEN); 603 else if (ptr == fBlueItem) 604 SetFontColor(&BLUE); 605 else if (ptr == fCyanItem) 606 SetFontColor(&CYAN); 607 else if (ptr == fMagentaItem) 608 SetFontColor(&MAGENTA); 609 else if (ptr == fYellowItem) 610 SetFontColor(&YELLOW); 611 } 612 break; 613 } 614 615 // Document menu 616 617 case ALIGN_LEFT: 618 fTextView->SetAlignment(B_ALIGN_LEFT); 619 _UpdateCleanUndoRedoSaveRevert(); 620 break; 621 case ALIGN_CENTER: 622 fTextView->SetAlignment(B_ALIGN_CENTER); 623 _UpdateCleanUndoRedoSaveRevert(); 624 break; 625 case ALIGN_RIGHT: 626 fTextView->SetAlignment(B_ALIGN_RIGHT); 627 _UpdateCleanUndoRedoSaveRevert(); 628 break; 629 case WRAP_LINES: 630 { 631 BRect textRect(fTextView->Bounds()); 632 textRect.OffsetTo(B_ORIGIN); 633 textRect.InsetBy(TEXT_INSET, TEXT_INSET); 634 if (fTextView->DoesWordWrap()) { 635 fTextView->SetWordWrap(false); 636 fWrapItem->SetMarked(false); 637 // the width comes from stylededit R5. TODO: find a better way 638 textRect.SetRightBottom(BPoint(1500.0, textRect.RightBottom().y)); 639 } else { 640 fTextView->SetWordWrap(true); 641 fWrapItem->SetMarked(true); 642 } 643 fTextView->SetTextRect(textRect); 644 645 _UpdateCleanUndoRedoSaveRevert(); 646 break; 647 } 648 case ENABLE_ITEMS: 649 fCutItem->SetEnabled(true); 650 fCopyItem->SetEnabled(true); 651 fClearItem->SetEnabled(true); 652 break; 653 case DISABLE_ITEMS: 654 fCutItem->SetEnabled(false); 655 fCopyItem->SetEnabled(false); 656 fClearItem->SetEnabled(false); 657 break; 658 case TEXT_CHANGED: 659 if (fUndoFlag) { 660 if (fUndoCleans) { 661 // we cleaned! 662 fClean = true; 663 fUndoCleans = false; 664 } else if (fClean) { 665 // if we were clean 666 // then a redo will make us clean again 667 fRedoCleans = true; 668 fClean = false; 669 } 670 // set mode 671 fCanUndo = false; 672 fCanRedo = true; 673 fUndoItem->SetLabel(B_TRANSLATE("Redo typing")); 674 fUndoItem->SetEnabled(true); 675 fUndoFlag = false; 676 } else { 677 if (fRedoFlag && fRedoCleans) { 678 // we cleaned! 679 fClean = true; 680 fRedoCleans = false; 681 } else if (fClean) { 682 // if we were clean 683 // then an undo will make us clean again 684 fUndoCleans = true; 685 fClean = false; 686 } else { 687 // no more cleaning from undo now... 688 fUndoCleans = false; 689 } 690 // set mode 691 fCanUndo = true; 692 fCanRedo = false; 693 fUndoItem->SetLabel(B_TRANSLATE("Undo typing")); 694 fUndoItem->SetEnabled(true); 695 fRedoFlag = false; 696 } 697 if (fClean) { 698 fRevertItem->SetEnabled(false); 699 fSaveItem->SetEnabled(fSaveMessage == NULL); 700 } else { 701 fRevertItem->SetEnabled(fSaveMessage != NULL); 702 fSaveItem->SetEnabled(true); 703 } 704 break; 705 706 case SAVE_AS_ENCODING: 707 void* ptr; 708 if (message->FindPointer("source", &ptr) == B_OK 709 && fSavePanelEncodingMenu != NULL) { 710 fTextView->SetEncoding( 711 (uint32)fSavePanelEncodingMenu->IndexOf((BMenuItem*)ptr)); 712 } 713 break; 714 715 default: 716 BWindow::MessageReceived(message); 717 break; 718 } 719 } 720 721 722 void 723 StyledEditWindow::MenusBeginning() 724 { 725 // set up the recent documents menu 726 BMessage documents; 727 be_roster->GetRecentDocuments(&documents, 9, NULL, APP_SIGNATURE); 728 729 // delete old items.. 730 // shatty: it would be preferable to keep the old 731 // menu around instead of continuously thrashing 732 // the menu, but unfortunately there does not 733 // seem to be a straightforward way to update it 734 // going backwards may simplify memory management 735 for (int i = fRecentMenu->CountItems(); i-- > 0;) { 736 delete fRecentMenu->RemoveItem(i); 737 } 738 739 // add new items 740 int count = 0; 741 entry_ref ref; 742 while (documents.FindRef("refs", count++, &ref) == B_OK) { 743 if (ref.device != -1 && ref.directory != -1) { 744 // sanity check passed 745 BMessage* openRecent = new BMessage(B_REFS_RECEIVED); 746 openRecent->AddRef("refs", &ref); 747 BMenuItem* item = new BMenuItem(ref.name, openRecent); 748 item->SetTarget(be_app); 749 fRecentMenu->AddItem(item); 750 } 751 } 752 753 // update the font menu 754 // unselect the old values 755 if (fCurrentFontItem != NULL) { 756 fCurrentFontItem->SetMarked(false); 757 BMenu* menu = fCurrentFontItem->Submenu(); 758 if (menu != NULL) { 759 BMenuItem* item = menu->FindMarked(); 760 if (item != NULL) { 761 item->SetMarked(false); 762 } 763 } 764 } 765 766 if (fCurrentStyleItem != NULL) { 767 fCurrentStyleItem->SetMarked(false); 768 } 769 770 BMenuItem* oldColorItem = fFontColorMenu->FindMarked(); 771 if (oldColorItem != NULL) 772 oldColorItem->SetMarked(false); 773 774 BMenuItem* oldSizeItem = fFontSizeMenu->FindMarked(); 775 if (oldSizeItem != NULL) 776 oldSizeItem->SetMarked(false); 777 778 // find the current font, color, size 779 BFont font; 780 uint32 sameProperties; 781 rgb_color color = BLACK; 782 bool sameColor; 783 fTextView->GetFontAndColor(&font, &sameProperties, &color, &sameColor); 784 785 if (sameColor && color.alpha == 255) { 786 // select the current color 787 if (color.red == 0) { 788 if (color.green == 0) { 789 if (color.blue == 0) { 790 fBlackItem->SetMarked(true); 791 } else if (color.blue == 255) { 792 fBlueItem->SetMarked(true); 793 } 794 } else if (color.green == 255) { 795 if (color.blue == 0) { 796 fGreenItem->SetMarked(true); 797 } else if (color.blue == 255) { 798 fCyanItem->SetMarked(true); 799 } 800 } 801 } else if (color.red == 255) { 802 if (color.green == 0) { 803 if (color.blue == 0) { 804 fRedItem->SetMarked(true); 805 } else if (color.blue == 255) { 806 fMagentaItem->SetMarked(true); 807 } 808 } else if (color.green == 255) { 809 if (color.blue == 0) { 810 fYellowItem->SetMarked(true); 811 } 812 } 813 } 814 } 815 816 if (sameProperties & B_FONT_SIZE) { 817 if ((int)font.Size() == font.Size()) { 818 // select the current font size 819 char fontSizeStr[16]; 820 snprintf(fontSizeStr, 15, "%i", (int)font.Size()); 821 BMenuItem* item = fFontSizeMenu->FindItem(fontSizeStr); 822 if (item != NULL) 823 item->SetMarked(true); 824 } 825 } 826 827 font_family family; 828 font_style style; 829 font.GetFamilyAndStyle(&family, &style); 830 831 fCurrentFontItem = fFontMenu->FindItem(family); 832 833 if (fCurrentFontItem != NULL) { 834 fCurrentFontItem->SetMarked(true); 835 BMenu* menu = fCurrentFontItem->Submenu(); 836 if (menu != NULL) { 837 BMenuItem* item = menu->FindItem(style); 838 fCurrentStyleItem = item; 839 if (fCurrentStyleItem != NULL) { 840 item->SetMarked(true); 841 } 842 } 843 } 844 845 switch (fTextView->Alignment()) { 846 case B_ALIGN_LEFT: 847 default: 848 fAlignLeft->SetMarked(true); 849 break; 850 case B_ALIGN_CENTER: 851 fAlignCenter->SetMarked(true); 852 break; 853 case B_ALIGN_RIGHT: 854 fAlignRight->SetMarked(true); 855 break; 856 } 857 } 858 859 860 void 861 StyledEditWindow::Quit() 862 { 863 SaveAttrs(); 864 styled_edit_app->CloseDocument(); 865 BWindow::Quit(); 866 } 867 868 869 #undef B_TRANSLATE_CONTEXT 870 #define B_TRANSLATE_CONTEXT "QuitAlert" 871 872 873 bool 874 StyledEditWindow::QuitRequested() 875 { 876 if (fClean) 877 return true; 878 879 BString alertText; 880 bs_printf(&alertText, 881 B_TRANSLATE("Save changes to the document \"%s\"? "), Title()); 882 883 int32 index = _ShowAlert(alertText, B_TRANSLATE("Cancel"), 884 B_TRANSLATE("Don't save"), B_TRANSLATE("Save"), B_WARNING_ALERT); 885 886 if (index == 0) 887 return false; // "cancel": dont save, dont close the window 888 889 if (index == 1) 890 return true; // "don't save": just close the window 891 892 if (!fSaveMessage) { 893 SaveAs(new BMessage(SAVE_THEN_QUIT)); 894 return false; 895 } 896 897 return Save() == B_OK; 898 } 899 900 901 #undef B_TRANSLATE_CONTEXT 902 #define B_TRANSLATE_CONTEXT "SaveAlert" 903 904 905 status_t 906 StyledEditWindow::Save(BMessage* message) 907 { 908 if (!message) 909 message = fSaveMessage; 910 911 if (!message) 912 return B_ERROR; 913 914 entry_ref dirRef; 915 const char* name; 916 if (message->FindRef("directory", &dirRef) != B_OK 917 || message->FindString("name", &name) != B_OK) 918 return B_BAD_VALUE; 919 920 BDirectory dir(&dirRef); 921 BEntry entry(&dir, name); 922 923 status_t status = B_ERROR; 924 if (dir.InitCheck() == B_OK && entry.InitCheck() == B_OK) { 925 struct stat st; 926 BFile file(&entry, B_READ_WRITE | B_CREATE_FILE); 927 if (file.InitCheck() == B_OK 928 && (status = file.GetStat(&st)) == B_OK) { 929 // check the file permissions 930 if (!((getuid() == st.st_uid && (S_IWUSR & st.st_mode)) 931 || (getgid() == st.st_gid && (S_IWGRP & st.st_mode)) 932 || (S_IWOTH & st.st_mode))) { 933 BString alertText; 934 bs_printf(&alertText, B_TRANSLATE("This file is marked " 935 "Read-Only. Save changes to the document \"%s\"? "), name); 936 switch (_ShowAlert(alertText, B_TRANSLATE("Cancel"), 937 B_TRANSLATE("Don't save"), 938 B_TRANSLATE("Save"), B_WARNING_ALERT)) { 939 case 0: 940 return B_CANCELED; 941 case 1: 942 return B_OK; 943 default: 944 break; 945 } 946 } 947 948 status = fTextView->WriteStyledEditFile(&file); 949 } 950 } 951 952 if (status != B_OK) { 953 BString alertText; 954 bs_printf(&alertText, B_TRANSLATE("Error saving \"%s\":\n%s"), name, 955 strerror(status)); 956 957 _ShowAlert(alertText, B_TRANSLATE("OK"), "", "", B_STOP_ALERT); 958 return status; 959 } 960 961 SetTitle(name); 962 963 if (fSaveMessage != message) { 964 delete fSaveMessage; 965 fSaveMessage = new BMessage(*message); 966 } 967 968 entry_ref ref; 969 if (entry.GetRef(&ref) == B_OK) 970 be_roster->AddToRecentDocuments(&ref, APP_SIGNATURE); 971 972 // clear clean modes 973 fSaveItem->SetEnabled(false); 974 fRevertItem->SetEnabled(false); 975 fUndoCleans = false; 976 fRedoCleans = false; 977 fClean = true; 978 return status; 979 } 980 981 982 #undef B_TRANSLATE_CONTEXT 983 #define B_TRANSLATE_CONTEXT "Open_and_SaveAsPanel" 984 985 986 status_t 987 StyledEditWindow::SaveAs(BMessage* message) 988 { 989 if (fSavePanel == NULL) { 990 entry_ref* directory = NULL; 991 if (fSaveMessage != NULL) { 992 entry_ref dirRef; 993 if (fSaveMessage->FindRef("directory", &dirRef) == B_OK) 994 directory = &dirRef; 995 } 996 997 BMessenger target(this); 998 fSavePanel = new BFilePanel(B_SAVE_PANEL, &target, 999 directory, B_FILE_NODE, false); 1000 1001 BMenuBar* menuBar = dynamic_cast<BMenuBar*>( 1002 fSavePanel->Window()->FindView("MenuBar")); 1003 1004 fSavePanelEncodingMenu= new BMenu(B_TRANSLATE("Encoding")); 1005 menuBar->AddItem(fSavePanelEncodingMenu); 1006 fSavePanelEncodingMenu->SetRadioMode(true); 1007 1008 BCharacterSetRoster roster; 1009 BCharacterSet charset; 1010 while (roster.GetNextCharacterSet(&charset) == B_NO_ERROR) { 1011 BString name(charset.GetPrintName()); 1012 const char* mime = charset.GetMIMEName(); 1013 if (mime) { 1014 name.Append(" ("); 1015 name.Append(mime); 1016 name.Append(")"); 1017 } 1018 BMenuItem * item = new BMenuItem(name.String(), 1019 new BMessage(SAVE_AS_ENCODING)); 1020 item->SetTarget(this); 1021 fSavePanelEncodingMenu->AddItem(item); 1022 if (charset.GetFontID() == fTextView->GetEncoding()) 1023 item->SetMarked(true); 1024 } 1025 } 1026 1027 fSavePanel->SetSaveText(Title()); 1028 if (message != NULL) 1029 fSavePanel->SetMessage(message); 1030 1031 fSavePanel->Show(); 1032 return B_OK; 1033 } 1034 1035 1036 #undef B_TRANSLATE_CONTEXT 1037 #define B_TRANSLATE_CONTEXT "LoadAlert" 1038 1039 1040 status_t 1041 StyledEditWindow::_LoadFile(entry_ref* ref) 1042 { 1043 BEntry entry(ref, true); 1044 // traverse an eventual link 1045 1046 status_t status = entry.InitCheck(); 1047 if (status == B_OK && entry.IsDirectory()) 1048 status = B_IS_A_DIRECTORY; 1049 1050 BFile file; 1051 if (status == B_OK) 1052 status = file.SetTo(&entry, B_READ_ONLY); 1053 if (status == B_OK) 1054 status = fTextView->GetStyledText(&file); 1055 1056 if (status == B_ENTRY_NOT_FOUND) { 1057 // Treat non-existing files consideratley; we just want to get an 1058 // empty window for them - to create this new document 1059 status = B_OK; 1060 } 1061 1062 if (status != B_OK) { 1063 // If an error occured, bail out and tell the user what happened 1064 BEntry entry(ref, true); 1065 char name[B_FILE_NAME_LENGTH]; 1066 if (entry.GetName(name) != B_OK) 1067 strcpy(name, B_TRANSLATE("???")); 1068 1069 BString text; 1070 if (status == B_BAD_TYPE) 1071 bs_printf(&text, 1072 B_TRANSLATE("Error loading \"%s\":\n\tUnsupported format"), name); 1073 else 1074 bs_printf(&text, B_TRANSLATE("Error loading \"%s\":\n\t%s"), 1075 name, strerror(status)); 1076 1077 _ShowAlert(text, B_TRANSLATE("OK"), "", "", B_STOP_ALERT); 1078 return status; 1079 } 1080 1081 // update alignment 1082 switch (fTextView->Alignment()) { 1083 case B_ALIGN_LEFT: 1084 default: 1085 fAlignLeft->SetMarked(true); 1086 break; 1087 case B_ALIGN_CENTER: 1088 fAlignCenter->SetMarked(true); 1089 break; 1090 case B_ALIGN_RIGHT: 1091 fAlignRight->SetMarked(true); 1092 break; 1093 } 1094 1095 // update word wrapping 1096 fWrapItem->SetMarked(fTextView->DoesWordWrap()); 1097 return B_OK; 1098 } 1099 1100 1101 void 1102 StyledEditWindow::OpenFile(entry_ref* ref) 1103 { 1104 if (_LoadFile(ref) != B_OK) { 1105 fSaveItem->SetEnabled(true); 1106 // allow saving new files 1107 return; 1108 } 1109 1110 be_roster->AddToRecentDocuments(ref, APP_SIGNATURE); 1111 fSaveMessage = new BMessage(B_SAVE_REQUESTED); 1112 if (fSaveMessage) { 1113 BEntry entry(ref, true); 1114 BEntry parent; 1115 entry_ref parentRef; 1116 char name[B_FILE_NAME_LENGTH]; 1117 1118 entry.GetParent(&parent); 1119 entry.GetName(name); 1120 parent.GetRef(&parentRef); 1121 fSaveMessage->AddRef("directory", &parentRef); 1122 fSaveMessage->AddString("name", name); 1123 SetTitle(name); 1124 1125 LoadAttrs(); 1126 } 1127 fTextView->Select(0, 0); 1128 } 1129 1130 1131 #undef B_TRANSLATE_CONTEXT 1132 #define B_TRANSLATE_CONTEXT "RevertToSavedAlert" 1133 1134 1135 void 1136 StyledEditWindow::RevertToSaved() 1137 { 1138 entry_ref ref; 1139 const char* name; 1140 1141 fSaveMessage->FindRef("directory", &ref); 1142 fSaveMessage->FindString("name", &name); 1143 1144 BDirectory dir(&ref); 1145 status_t status = dir.InitCheck(); 1146 BEntry entry; 1147 if (status == B_OK) 1148 status = entry.SetTo(&dir, name); 1149 1150 if (status == B_OK) 1151 status = entry.GetRef(&ref); 1152 1153 if (status != B_OK || !entry.Exists()) { 1154 BString alertText; 1155 bs_printf(&alertText, 1156 B_TRANSLATE("Cannot revert, file not found: \"%s\"."), name); 1157 _ShowAlert(alertText, B_TRANSLATE("OK"), "", "", B_STOP_ALERT); 1158 return; 1159 } 1160 1161 BString alertText; 1162 bs_printf(&alertText, 1163 B_TRANSLATE("Revert to the last version of \"%s\"? "), Title()); 1164 if (_ShowAlert(alertText, B_TRANSLATE("Cancel"), B_TRANSLATE("OK"), 1165 "", B_WARNING_ALERT) != 1) 1166 return; 1167 1168 fTextView->Reset(); 1169 if (_LoadFile(&ref) != B_OK) 1170 return; 1171 1172 #undef B_TRANSLATE_CONTEXT 1173 #define B_TRANSLATE_CONTEXT "Menus" 1174 1175 // clear undo modes 1176 fUndoItem->SetLabel(B_TRANSLATE("Can't undo")); 1177 fUndoItem->SetEnabled(false); 1178 fUndoFlag = false; 1179 fCanUndo = false; 1180 fRedoFlag = false; 1181 fCanRedo = false; 1182 1183 // clear clean modes 1184 fSaveItem->SetEnabled(false); 1185 fRevertItem->SetEnabled(false); 1186 fUndoCleans = false; 1187 fRedoCleans = false; 1188 fClean = true; 1189 } 1190 1191 1192 status_t 1193 StyledEditWindow::PageSetup(const char* documentName) 1194 { 1195 BPrintJob printJob(documentName); 1196 1197 if (fPrintSettings != NULL) 1198 printJob.SetSettings(new BMessage(*fPrintSettings)); 1199 1200 status_t result = printJob.ConfigPage(); 1201 if (result == B_OK) { 1202 delete fPrintSettings; 1203 fPrintSettings = printJob.Settings(); 1204 } 1205 1206 return result; 1207 } 1208 1209 1210 void 1211 StyledEditWindow::Print(const char* documentName) 1212 { 1213 BPrintJob printJob(documentName); 1214 if (fPrintSettings) 1215 printJob.SetSettings(new BMessage(*fPrintSettings)); 1216 1217 if (printJob.ConfigJob() != B_OK) 1218 return; 1219 1220 delete fPrintSettings; 1221 fPrintSettings = printJob.Settings(); 1222 1223 // information from printJob 1224 BRect printableRect = printJob.PrintableRect(); 1225 int32 firstPage = printJob.FirstPage(); 1226 int32 lastPage = printJob.LastPage(); 1227 1228 // lines eventually to be used to compute pages to print 1229 int32 firstLine = 0; 1230 int32 lastLine = fTextView->CountLines(); 1231 1232 // values to be computed 1233 int32 pagesInDocument = 1; 1234 int32 linesInDocument = fTextView->CountLines(); 1235 1236 int32 currentLine = 0; 1237 while (currentLine < linesInDocument) { 1238 float currentHeight = 0; 1239 while (currentHeight < printableRect.Height() && currentLine < linesInDocument) { 1240 currentHeight += fTextView->LineHeight(currentLine); 1241 if (currentHeight < printableRect.Height()) 1242 currentLine++; 1243 } 1244 if (pagesInDocument == lastPage) 1245 lastLine = currentLine - 1; 1246 1247 if (currentHeight >= printableRect.Height()) { 1248 pagesInDocument++; 1249 if (pagesInDocument == firstPage) 1250 firstLine = currentLine; 1251 } 1252 } 1253 1254 if (lastPage > pagesInDocument - 1) { 1255 lastPage = pagesInDocument - 1; 1256 lastLine = currentLine - 1; 1257 } 1258 1259 1260 printJob.BeginJob(); 1261 if (fTextView->CountLines() > 0 && fTextView->TextLength() > 0) { 1262 int32 printLine = firstLine; 1263 while (printLine <= lastLine) { 1264 float currentHeight = 0; 1265 int32 firstLineOnPage = printLine; 1266 while (currentHeight < printableRect.Height() && printLine <= lastLine) { 1267 currentHeight += fTextView->LineHeight(printLine); 1268 if (currentHeight < printableRect.Height()) 1269 printLine++; 1270 } 1271 1272 float top = 0; 1273 if (firstLineOnPage != 0) 1274 top = fTextView->TextHeight(0, firstLineOnPage - 1); 1275 1276 float bottom = fTextView->TextHeight(0, printLine - 1); 1277 BRect textRect(0.0, top + TEXT_INSET, 1278 printableRect.Width(), bottom + TEXT_INSET); 1279 printJob.DrawView(fTextView, textRect, B_ORIGIN); 1280 printJob.SpoolPage(); 1281 } 1282 } 1283 1284 1285 printJob.CommitJob(); 1286 } 1287 1288 1289 bool 1290 StyledEditWindow::Search(BString string, bool caseSensitive, bool wrap, bool backsearch) 1291 { 1292 int32 start; 1293 int32 finish; 1294 1295 start = B_ERROR; 1296 1297 int32 length = string.Length(); 1298 if (length == 0) 1299 return false; 1300 1301 BString viewText(fTextView->Text()); 1302 int32 textStart, textFinish; 1303 fTextView->GetSelection(&textStart, &textFinish); 1304 if (backsearch) { 1305 if (caseSensitive) { 1306 start = viewText.FindLast(string, textStart); 1307 } else { 1308 start = viewText.IFindLast(string, textStart); 1309 } 1310 } else { 1311 if (caseSensitive == true) { 1312 start = viewText.FindFirst(string, textFinish); 1313 } else { 1314 start = viewText.IFindFirst(string, textFinish); 1315 } 1316 } 1317 if (start == B_ERROR && wrap) { 1318 if (backsearch) { 1319 if (caseSensitive) { 1320 start = viewText.FindLast(string, viewText.Length()); 1321 } else { 1322 start = viewText.IFindLast(string, viewText.Length()); 1323 } 1324 } else { 1325 if (caseSensitive) { 1326 start = viewText.FindFirst(string, 0); 1327 } else { 1328 start = viewText.IFindFirst(string, 0); 1329 } 1330 } 1331 } 1332 1333 if (start != B_ERROR) { 1334 finish = start + length; 1335 fTextView->Select(start, finish); 1336 fTextView->ScrollToSelection(); 1337 return true; 1338 } 1339 1340 return false; 1341 } 1342 1343 1344 void 1345 StyledEditWindow::FindSelection() 1346 { 1347 int32 selectionStart, selectionFinish; 1348 fTextView->GetSelection(&selectionStart, &selectionFinish); 1349 1350 int32 selectionLength = selectionFinish- selectionStart; 1351 1352 BString viewText = fTextView->Text(); 1353 viewText.CopyInto(fStringToFind, selectionStart, selectionLength); 1354 fFindAgainItem->SetEnabled(true); 1355 Search(fStringToFind, fCaseSens, fWrapAround, fBackSearch); 1356 } 1357 1358 1359 bool 1360 StyledEditWindow::Replace(BString findthis, BString replaceWith, bool caseSensitive, 1361 bool wrap, bool backsearch) 1362 { 1363 if (Search(findthis, caseSensitive, wrap, backsearch)) { 1364 int32 start, finish; 1365 fTextView->GetSelection(&start, &finish); 1366 1367 _UpdateCleanUndoRedoSaveRevert(); 1368 fTextView->SetSuppressChanges(true); 1369 fTextView->Delete(start, start + findthis.Length()); 1370 fTextView->Insert(start, replaceWith.String(), replaceWith.Length()); 1371 fTextView->SetSuppressChanges(false); 1372 fTextView->Select(start, start + replaceWith.Length()); 1373 fTextView->ScrollToSelection(); 1374 return true; 1375 } 1376 1377 return false; 1378 } 1379 1380 1381 void 1382 StyledEditWindow::ReplaceAll(BString findthis, BString replaceWith, bool caseSensitive) 1383 { 1384 bool first = true; 1385 fTextView->SetSuppressChanges(true); 1386 while (Search(findthis, caseSensitive, true, false)) { 1387 if (first) { 1388 _UpdateCleanUndoRedoSaveRevert(); 1389 first = false; 1390 } 1391 int32 start, finish; 1392 fTextView->GetSelection(&start, &finish); 1393 1394 fTextView->Delete(start, start + findthis.Length()); 1395 fTextView->Insert(start, replaceWith.String(), replaceWith.Length()); 1396 } 1397 fTextView->SetSuppressChanges(false); 1398 } 1399 1400 1401 void 1402 StyledEditWindow::SearchAllWindows(BString find, BString replace, bool caseSensitive) 1403 { 1404 int32 numWindows; 1405 numWindows = be_app->CountWindows(); 1406 1407 BMessage* message; 1408 message= new BMessage(MSG_REPLACE_ALL); 1409 message->AddString("FindText", find); 1410 message->AddString("ReplaceText", replace); 1411 message->AddBool("casesens", caseSensitive); 1412 1413 while (numWindows >= 0) { 1414 StyledEditWindow* window = dynamic_cast<StyledEditWindow *>( 1415 be_app->WindowAt(numWindows)); 1416 1417 BMessenger messenger(window); 1418 messenger.SendMessage(message); 1419 1420 numWindows--; 1421 } 1422 } 1423 1424 1425 void 1426 StyledEditWindow::SetFontSize(float fontSize) 1427 { 1428 uint32 sameProperties; 1429 BFont font; 1430 1431 fTextView->GetFontAndColor(&font, &sameProperties); 1432 font.SetSize(fontSize); 1433 fTextView->SetFontAndColor(&font, B_FONT_SIZE); 1434 1435 _UpdateCleanUndoRedoSaveRevert(); 1436 } 1437 1438 1439 void 1440 StyledEditWindow::SetFontColor(const rgb_color* color) 1441 { 1442 uint32 sameProperties; 1443 BFont font; 1444 1445 fTextView->GetFontAndColor(&font, &sameProperties, NULL, NULL); 1446 fTextView->SetFontAndColor(&font, 0, color); 1447 1448 _UpdateCleanUndoRedoSaveRevert(); 1449 } 1450 1451 1452 void 1453 StyledEditWindow::SetFontStyle(const char* fontFamily, const char* fontStyle) 1454 { 1455 BFont font; 1456 uint32 sameProperties; 1457 1458 // find out what the old font was 1459 font_family oldFamily; 1460 font_style oldStyle; 1461 fTextView->GetFontAndColor(&font, &sameProperties); 1462 font.GetFamilyAndStyle(&oldFamily, &oldStyle); 1463 1464 // clear that family's bit on the menu, if necessary 1465 if (strcmp(oldFamily, fontFamily)) { 1466 BMenuItem* oldItem = fFontMenu->FindItem(oldFamily); 1467 if (oldItem != NULL) { 1468 oldItem->SetMarked(false); 1469 BMenu* menu = oldItem->Submenu(); 1470 if (menu != NULL) { 1471 oldItem = menu->FindItem(oldStyle); 1472 if (oldItem != NULL) 1473 oldItem->SetMarked(false); 1474 } 1475 } 1476 } 1477 1478 font.SetFamilyAndStyle(fontFamily, fontStyle); 1479 fTextView->SetFontAndColor(&font); 1480 1481 BMenuItem* superItem; 1482 superItem = fFontMenu->FindItem(fontFamily); 1483 if (superItem != NULL) { 1484 superItem->SetMarked(true); 1485 fCurrentFontItem = superItem; 1486 } 1487 1488 _UpdateCleanUndoRedoSaveRevert(); 1489 } 1490 1491 1492 #undef B_TRANSLATE_CONTEXT 1493 #define B_TRANSLATE_CONTEXT "Menus" 1494 1495 1496 void 1497 StyledEditWindow::_UpdateCleanUndoRedoSaveRevert() 1498 { 1499 fClean = false; 1500 fUndoCleans = false; 1501 fRedoCleans = false; 1502 fRevertItem->SetEnabled(fSaveMessage != NULL); 1503 fSaveItem->SetEnabled(true); 1504 fUndoItem->SetLabel(B_TRANSLATE("Can't Undo")); 1505 fUndoItem->SetEnabled(false); 1506 fCanUndo = false; 1507 fCanRedo = false; 1508 } 1509 1510 1511 int32 1512 StyledEditWindow::_ShowAlert(const BString& text, const BString& label, 1513 const BString& label2, const BString& label3, alert_type type) const 1514 { 1515 const char* button2 = NULL; 1516 if (label2.Length() > 0) 1517 button2 = label2.String(); 1518 1519 const char* button3 = NULL; 1520 button_spacing spacing = B_EVEN_SPACING; 1521 if (label3.Length() > 0) { 1522 button3 = label3.String(); 1523 spacing = B_OFFSET_SPACING; 1524 } 1525 1526 BAlert* alert = new BAlert("Alert", text.String(), label.String(), button2, 1527 button3, B_WIDTH_AS_USUAL, spacing, type); 1528 alert->SetShortcut(0, B_ESCAPE); 1529 1530 return alert->Go(); 1531 } 1532 1533 1534 bool 1535 StyledEditWindow::IsDocumentEntryRef(const entry_ref* ref) 1536 { 1537 if (ref == NULL) 1538 return false; 1539 1540 if (fSaveMessage == NULL) 1541 return false; 1542 1543 entry_ref dir; 1544 const char* name; 1545 if (fSaveMessage->FindRef("directory", &dir) != B_OK 1546 || fSaveMessage->FindString("name", &name) != B_OK) 1547 return false; 1548 1549 entry_ref documentRef; 1550 BPath documentPath(&dir); 1551 documentPath.Append(name); 1552 get_ref_for_path(documentPath.Path(), &documentRef); 1553 1554 if (*ref == documentRef) 1555 return true; 1556 1557 return false; 1558 } 1559 1560