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 if (StyledEditApp* app = dynamic_cast<StyledEditApp*>(be_app)) 865 app->CloseDocument(); 866 BWindow::Quit(); 867 } 868 869 870 #undef B_TRANSLATE_CONTEXT 871 #define B_TRANSLATE_CONTEXT "QuitAlert" 872 873 874 bool 875 StyledEditWindow::QuitRequested() 876 { 877 if (fClean) 878 return true; 879 880 BString alertText; 881 bs_printf(&alertText, 882 B_TRANSLATE("Save changes to the document \"%s\"? "), Title()); 883 884 int32 index = _ShowAlert(alertText, B_TRANSLATE("Cancel"), 885 B_TRANSLATE("Don't save"), B_TRANSLATE("Save"), B_WARNING_ALERT); 886 887 if (index == 0) 888 return false; // "cancel": dont save, dont close the window 889 890 if (index == 1) 891 return true; // "don't save": just close the window 892 893 if (!fSaveMessage) { 894 SaveAs(new BMessage(SAVE_THEN_QUIT)); 895 return false; 896 } 897 898 return Save() == B_OK; 899 } 900 901 902 #undef B_TRANSLATE_CONTEXT 903 #define B_TRANSLATE_CONTEXT "SaveAlert" 904 905 906 status_t 907 StyledEditWindow::Save(BMessage* message) 908 { 909 if (!message) 910 message = fSaveMessage; 911 912 if (!message) 913 return B_ERROR; 914 915 entry_ref dirRef; 916 const char* name; 917 if (message->FindRef("directory", &dirRef) != B_OK 918 || message->FindString("name", &name) != B_OK) 919 return B_BAD_VALUE; 920 921 BDirectory dir(&dirRef); 922 BEntry entry(&dir, name); 923 924 status_t status = B_ERROR; 925 if (dir.InitCheck() == B_OK && entry.InitCheck() == B_OK) { 926 struct stat st; 927 BFile file(&entry, B_READ_WRITE | B_CREATE_FILE); 928 if (file.InitCheck() == B_OK 929 && (status = file.GetStat(&st)) == B_OK) { 930 // check the file permissions 931 if (!((getuid() == st.st_uid && (S_IWUSR & st.st_mode)) 932 || (getgid() == st.st_gid && (S_IWGRP & st.st_mode)) 933 || (S_IWOTH & st.st_mode))) { 934 BString alertText; 935 bs_printf(&alertText, B_TRANSLATE("This file is marked " 936 "Read-Only. Save changes to the document \"%s\"? "), name); 937 switch (_ShowAlert(alertText, B_TRANSLATE("Cancel"), 938 B_TRANSLATE("Don't save"), 939 B_TRANSLATE("Save"), B_WARNING_ALERT)) { 940 case 0: 941 return B_CANCELED; 942 case 1: 943 return B_OK; 944 default: 945 break; 946 } 947 } 948 949 status = fTextView->WriteStyledEditFile(&file); 950 } 951 } 952 953 if (status != B_OK) { 954 BString alertText; 955 bs_printf(&alertText, B_TRANSLATE("Error saving \"%s\":\n%s"), name, 956 strerror(status)); 957 958 _ShowAlert(alertText, B_TRANSLATE("OK"), "", "", B_STOP_ALERT); 959 return status; 960 } 961 962 SetTitle(name); 963 964 if (fSaveMessage != message) { 965 delete fSaveMessage; 966 fSaveMessage = new BMessage(*message); 967 } 968 969 entry_ref ref; 970 if (entry.GetRef(&ref) == B_OK) 971 be_roster->AddToRecentDocuments(&ref, APP_SIGNATURE); 972 973 // clear clean modes 974 fSaveItem->SetEnabled(false); 975 fRevertItem->SetEnabled(false); 976 fUndoCleans = false; 977 fRedoCleans = false; 978 fClean = true; 979 return status; 980 } 981 982 983 #undef B_TRANSLATE_CONTEXT 984 #define B_TRANSLATE_CONTEXT "Open_and_SaveAsPanel" 985 986 987 status_t 988 StyledEditWindow::SaveAs(BMessage* message) 989 { 990 if (fSavePanel == NULL) { 991 entry_ref* directory = NULL; 992 if (fSaveMessage != NULL) { 993 entry_ref dirRef; 994 if (fSaveMessage->FindRef("directory", &dirRef) == B_OK) 995 directory = &dirRef; 996 } 997 998 BMessenger target(this); 999 fSavePanel = new BFilePanel(B_SAVE_PANEL, &target, 1000 directory, B_FILE_NODE, false); 1001 1002 BMenuBar* menuBar = dynamic_cast<BMenuBar*>( 1003 fSavePanel->Window()->FindView("MenuBar")); 1004 if (menuBar != NULL) { 1005 fSavePanelEncodingMenu = new BMenu(B_TRANSLATE("Encoding")); 1006 fSavePanelEncodingMenu->SetRadioMode(true); 1007 menuBar->AddItem(fSavePanelEncodingMenu); 1008 1009 BCharacterSetRoster roster; 1010 BCharacterSet charset; 1011 while (roster.GetNextCharacterSet(&charset) == B_NO_ERROR) { 1012 BString name(charset.GetPrintName()); 1013 const char* mime = charset.GetMIMEName(); 1014 if (mime) { 1015 name.Append(" ("); 1016 name.Append(mime); 1017 name.Append(")"); 1018 } 1019 BMenuItem * item = new BMenuItem(name.String(), 1020 new BMessage(SAVE_AS_ENCODING)); 1021 item->SetTarget(this); 1022 fSavePanelEncodingMenu->AddItem(item); 1023 if (charset.GetFontID() == fTextView->GetEncoding()) 1024 item->SetMarked(true); 1025 } 1026 } 1027 } 1028 1029 fSavePanel->SetSaveText(Title()); 1030 if (message != NULL) 1031 fSavePanel->SetMessage(message); 1032 1033 fSavePanel->Show(); 1034 return B_OK; 1035 } 1036 1037 1038 #undef B_TRANSLATE_CONTEXT 1039 #define B_TRANSLATE_CONTEXT "LoadAlert" 1040 1041 1042 status_t 1043 StyledEditWindow::_LoadFile(entry_ref* ref) 1044 { 1045 BEntry entry(ref, true); 1046 // traverse an eventual link 1047 1048 status_t status = entry.InitCheck(); 1049 if (status == B_OK && entry.IsDirectory()) 1050 status = B_IS_A_DIRECTORY; 1051 1052 BFile file; 1053 if (status == B_OK) 1054 status = file.SetTo(&entry, B_READ_ONLY); 1055 if (status == B_OK) 1056 status = fTextView->GetStyledText(&file); 1057 1058 if (status == B_ENTRY_NOT_FOUND) { 1059 // Treat non-existing files consideratley; we just want to get an 1060 // empty window for them - to create this new document 1061 status = B_OK; 1062 } 1063 1064 if (status != B_OK) { 1065 // If an error occured, bail out and tell the user what happened 1066 BEntry entry(ref, true); 1067 char name[B_FILE_NAME_LENGTH]; 1068 if (entry.GetName(name) != B_OK) 1069 strcpy(name, B_TRANSLATE("???")); 1070 1071 BString text; 1072 if (status == B_BAD_TYPE) 1073 bs_printf(&text, 1074 B_TRANSLATE("Error loading \"%s\":\n\tUnsupported format"), name); 1075 else 1076 bs_printf(&text, B_TRANSLATE("Error loading \"%s\":\n\t%s"), 1077 name, strerror(status)); 1078 1079 _ShowAlert(text, B_TRANSLATE("OK"), "", "", B_STOP_ALERT); 1080 return status; 1081 } 1082 1083 // update alignment 1084 switch (fTextView->Alignment()) { 1085 case B_ALIGN_LEFT: 1086 default: 1087 fAlignLeft->SetMarked(true); 1088 break; 1089 case B_ALIGN_CENTER: 1090 fAlignCenter->SetMarked(true); 1091 break; 1092 case B_ALIGN_RIGHT: 1093 fAlignRight->SetMarked(true); 1094 break; 1095 } 1096 1097 // update word wrapping 1098 fWrapItem->SetMarked(fTextView->DoesWordWrap()); 1099 return B_OK; 1100 } 1101 1102 1103 void 1104 StyledEditWindow::OpenFile(entry_ref* ref) 1105 { 1106 if (_LoadFile(ref) != B_OK) { 1107 fSaveItem->SetEnabled(true); 1108 // allow saving new files 1109 return; 1110 } 1111 1112 be_roster->AddToRecentDocuments(ref, APP_SIGNATURE); 1113 fSaveMessage = new BMessage(B_SAVE_REQUESTED); 1114 if (fSaveMessage) { 1115 BEntry entry(ref, true); 1116 BEntry parent; 1117 entry_ref parentRef; 1118 char name[B_FILE_NAME_LENGTH]; 1119 1120 entry.GetParent(&parent); 1121 entry.GetName(name); 1122 parent.GetRef(&parentRef); 1123 fSaveMessage->AddRef("directory", &parentRef); 1124 fSaveMessage->AddString("name", name); 1125 SetTitle(name); 1126 1127 LoadAttrs(); 1128 } 1129 fTextView->Select(0, 0); 1130 } 1131 1132 1133 #undef B_TRANSLATE_CONTEXT 1134 #define B_TRANSLATE_CONTEXT "RevertToSavedAlert" 1135 1136 1137 void 1138 StyledEditWindow::RevertToSaved() 1139 { 1140 entry_ref ref; 1141 const char* name; 1142 1143 fSaveMessage->FindRef("directory", &ref); 1144 fSaveMessage->FindString("name", &name); 1145 1146 BDirectory dir(&ref); 1147 status_t status = dir.InitCheck(); 1148 BEntry entry; 1149 if (status == B_OK) 1150 status = entry.SetTo(&dir, name); 1151 1152 if (status == B_OK) 1153 status = entry.GetRef(&ref); 1154 1155 if (status != B_OK || !entry.Exists()) { 1156 BString alertText; 1157 bs_printf(&alertText, 1158 B_TRANSLATE("Cannot revert, file not found: \"%s\"."), name); 1159 _ShowAlert(alertText, B_TRANSLATE("OK"), "", "", B_STOP_ALERT); 1160 return; 1161 } 1162 1163 BString alertText; 1164 bs_printf(&alertText, 1165 B_TRANSLATE("Revert to the last version of \"%s\"? "), Title()); 1166 if (_ShowAlert(alertText, B_TRANSLATE("Cancel"), B_TRANSLATE("OK"), 1167 "", B_WARNING_ALERT) != 1) 1168 return; 1169 1170 fTextView->Reset(); 1171 if (_LoadFile(&ref) != B_OK) 1172 return; 1173 1174 #undef B_TRANSLATE_CONTEXT 1175 #define B_TRANSLATE_CONTEXT "Menus" 1176 1177 // clear undo modes 1178 fUndoItem->SetLabel(B_TRANSLATE("Can't undo")); 1179 fUndoItem->SetEnabled(false); 1180 fUndoFlag = false; 1181 fCanUndo = false; 1182 fRedoFlag = false; 1183 fCanRedo = false; 1184 1185 // clear clean modes 1186 fSaveItem->SetEnabled(false); 1187 fRevertItem->SetEnabled(false); 1188 fUndoCleans = false; 1189 fRedoCleans = false; 1190 fClean = true; 1191 } 1192 1193 1194 status_t 1195 StyledEditWindow::PageSetup(const char* documentName) 1196 { 1197 BPrintJob printJob(documentName); 1198 1199 if (fPrintSettings != NULL) 1200 printJob.SetSettings(new BMessage(*fPrintSettings)); 1201 1202 status_t result = printJob.ConfigPage(); 1203 if (result == B_OK) { 1204 delete fPrintSettings; 1205 fPrintSettings = printJob.Settings(); 1206 } 1207 1208 return result; 1209 } 1210 1211 1212 void 1213 StyledEditWindow::Print(const char* documentName) 1214 { 1215 BPrintJob printJob(documentName); 1216 if (fPrintSettings) 1217 printJob.SetSettings(new BMessage(*fPrintSettings)); 1218 1219 if (printJob.ConfigJob() != B_OK) 1220 return; 1221 1222 delete fPrintSettings; 1223 fPrintSettings = printJob.Settings(); 1224 1225 // information from printJob 1226 BRect printableRect = printJob.PrintableRect(); 1227 int32 firstPage = printJob.FirstPage(); 1228 int32 lastPage = printJob.LastPage(); 1229 1230 // lines eventually to be used to compute pages to print 1231 int32 firstLine = 0; 1232 int32 lastLine = fTextView->CountLines(); 1233 1234 // values to be computed 1235 int32 pagesInDocument = 1; 1236 int32 linesInDocument = fTextView->CountLines(); 1237 1238 int32 currentLine = 0; 1239 while (currentLine < linesInDocument) { 1240 float currentHeight = 0; 1241 while (currentHeight < printableRect.Height() && currentLine < linesInDocument) { 1242 currentHeight += fTextView->LineHeight(currentLine); 1243 if (currentHeight < printableRect.Height()) 1244 currentLine++; 1245 } 1246 if (pagesInDocument == lastPage) 1247 lastLine = currentLine - 1; 1248 1249 if (currentHeight >= printableRect.Height()) { 1250 pagesInDocument++; 1251 if (pagesInDocument == firstPage) 1252 firstLine = currentLine; 1253 } 1254 } 1255 1256 if (lastPage > pagesInDocument - 1) { 1257 lastPage = pagesInDocument - 1; 1258 lastLine = currentLine - 1; 1259 } 1260 1261 1262 printJob.BeginJob(); 1263 if (fTextView->CountLines() > 0 && fTextView->TextLength() > 0) { 1264 int32 printLine = firstLine; 1265 while (printLine <= lastLine) { 1266 float currentHeight = 0; 1267 int32 firstLineOnPage = printLine; 1268 while (currentHeight < printableRect.Height() && printLine <= lastLine) { 1269 currentHeight += fTextView->LineHeight(printLine); 1270 if (currentHeight < printableRect.Height()) 1271 printLine++; 1272 } 1273 1274 float top = 0; 1275 if (firstLineOnPage != 0) 1276 top = fTextView->TextHeight(0, firstLineOnPage - 1); 1277 1278 float bottom = fTextView->TextHeight(0, printLine - 1); 1279 BRect textRect(0.0, top + TEXT_INSET, 1280 printableRect.Width(), bottom + TEXT_INSET); 1281 printJob.DrawView(fTextView, textRect, B_ORIGIN); 1282 printJob.SpoolPage(); 1283 } 1284 } 1285 1286 1287 printJob.CommitJob(); 1288 } 1289 1290 1291 bool 1292 StyledEditWindow::Search(BString string, bool caseSensitive, bool wrap, bool backsearch) 1293 { 1294 int32 start; 1295 int32 finish; 1296 1297 start = B_ERROR; 1298 1299 int32 length = string.Length(); 1300 if (length == 0) 1301 return false; 1302 1303 BString viewText(fTextView->Text()); 1304 int32 textStart, textFinish; 1305 fTextView->GetSelection(&textStart, &textFinish); 1306 if (backsearch) { 1307 if (caseSensitive) { 1308 start = viewText.FindLast(string, textStart); 1309 } else { 1310 start = viewText.IFindLast(string, textStart); 1311 } 1312 } else { 1313 if (caseSensitive == true) { 1314 start = viewText.FindFirst(string, textFinish); 1315 } else { 1316 start = viewText.IFindFirst(string, textFinish); 1317 } 1318 } 1319 if (start == B_ERROR && wrap) { 1320 if (backsearch) { 1321 if (caseSensitive) { 1322 start = viewText.FindLast(string, viewText.Length()); 1323 } else { 1324 start = viewText.IFindLast(string, viewText.Length()); 1325 } 1326 } else { 1327 if (caseSensitive) { 1328 start = viewText.FindFirst(string, 0); 1329 } else { 1330 start = viewText.IFindFirst(string, 0); 1331 } 1332 } 1333 } 1334 1335 if (start != B_ERROR) { 1336 finish = start + length; 1337 fTextView->Select(start, finish); 1338 fTextView->ScrollToSelection(); 1339 return true; 1340 } 1341 1342 return false; 1343 } 1344 1345 1346 void 1347 StyledEditWindow::FindSelection() 1348 { 1349 int32 selectionStart, selectionFinish; 1350 fTextView->GetSelection(&selectionStart, &selectionFinish); 1351 1352 int32 selectionLength = selectionFinish- selectionStart; 1353 1354 BString viewText = fTextView->Text(); 1355 viewText.CopyInto(fStringToFind, selectionStart, selectionLength); 1356 fFindAgainItem->SetEnabled(true); 1357 Search(fStringToFind, fCaseSens, fWrapAround, fBackSearch); 1358 } 1359 1360 1361 bool 1362 StyledEditWindow::Replace(BString findthis, BString replaceWith, bool caseSensitive, 1363 bool wrap, bool backsearch) 1364 { 1365 if (Search(findthis, caseSensitive, wrap, backsearch)) { 1366 int32 start, finish; 1367 fTextView->GetSelection(&start, &finish); 1368 1369 _UpdateCleanUndoRedoSaveRevert(); 1370 fTextView->SetSuppressChanges(true); 1371 fTextView->Delete(start, start + findthis.Length()); 1372 fTextView->Insert(start, replaceWith.String(), replaceWith.Length()); 1373 fTextView->SetSuppressChanges(false); 1374 fTextView->Select(start, start + replaceWith.Length()); 1375 fTextView->ScrollToSelection(); 1376 return true; 1377 } 1378 1379 return false; 1380 } 1381 1382 1383 void 1384 StyledEditWindow::ReplaceAll(BString findthis, BString replaceWith, bool caseSensitive) 1385 { 1386 bool first = true; 1387 fTextView->SetSuppressChanges(true); 1388 while (Search(findthis, caseSensitive, true, false)) { 1389 if (first) { 1390 _UpdateCleanUndoRedoSaveRevert(); 1391 first = false; 1392 } 1393 int32 start, finish; 1394 fTextView->GetSelection(&start, &finish); 1395 1396 fTextView->Delete(start, start + findthis.Length()); 1397 fTextView->Insert(start, replaceWith.String(), replaceWith.Length()); 1398 } 1399 fTextView->SetSuppressChanges(false); 1400 } 1401 1402 1403 void 1404 StyledEditWindow::SearchAllWindows(BString find, BString replace, bool caseSensitive) 1405 { 1406 int32 numWindows; 1407 numWindows = be_app->CountWindows(); 1408 1409 BMessage* message; 1410 message= new BMessage(MSG_REPLACE_ALL); 1411 message->AddString("FindText", find); 1412 message->AddString("ReplaceText", replace); 1413 message->AddBool("casesens", caseSensitive); 1414 1415 while (numWindows >= 0) { 1416 StyledEditWindow* window = dynamic_cast<StyledEditWindow *>( 1417 be_app->WindowAt(numWindows)); 1418 1419 BMessenger messenger(window); 1420 messenger.SendMessage(message); 1421 1422 numWindows--; 1423 } 1424 } 1425 1426 1427 void 1428 StyledEditWindow::SetFontSize(float fontSize) 1429 { 1430 uint32 sameProperties; 1431 BFont font; 1432 1433 fTextView->GetFontAndColor(&font, &sameProperties); 1434 font.SetSize(fontSize); 1435 fTextView->SetFontAndColor(&font, B_FONT_SIZE); 1436 1437 _UpdateCleanUndoRedoSaveRevert(); 1438 } 1439 1440 1441 void 1442 StyledEditWindow::SetFontColor(const rgb_color* color) 1443 { 1444 uint32 sameProperties; 1445 BFont font; 1446 1447 fTextView->GetFontAndColor(&font, &sameProperties, NULL, NULL); 1448 fTextView->SetFontAndColor(&font, 0, color); 1449 1450 _UpdateCleanUndoRedoSaveRevert(); 1451 } 1452 1453 1454 void 1455 StyledEditWindow::SetFontStyle(const char* fontFamily, const char* fontStyle) 1456 { 1457 BFont font; 1458 uint32 sameProperties; 1459 1460 // find out what the old font was 1461 font_family oldFamily; 1462 font_style oldStyle; 1463 fTextView->GetFontAndColor(&font, &sameProperties); 1464 font.GetFamilyAndStyle(&oldFamily, &oldStyle); 1465 1466 // clear that family's bit on the menu, if necessary 1467 if (strcmp(oldFamily, fontFamily)) { 1468 BMenuItem* oldItem = fFontMenu->FindItem(oldFamily); 1469 if (oldItem != NULL) { 1470 oldItem->SetMarked(false); 1471 BMenu* menu = oldItem->Submenu(); 1472 if (menu != NULL) { 1473 oldItem = menu->FindItem(oldStyle); 1474 if (oldItem != NULL) 1475 oldItem->SetMarked(false); 1476 } 1477 } 1478 } 1479 1480 font.SetFamilyAndStyle(fontFamily, fontStyle); 1481 fTextView->SetFontAndColor(&font); 1482 1483 BMenuItem* superItem; 1484 superItem = fFontMenu->FindItem(fontFamily); 1485 if (superItem != NULL) { 1486 superItem->SetMarked(true); 1487 fCurrentFontItem = superItem; 1488 } 1489 1490 _UpdateCleanUndoRedoSaveRevert(); 1491 } 1492 1493 1494 #undef B_TRANSLATE_CONTEXT 1495 #define B_TRANSLATE_CONTEXT "Menus" 1496 1497 1498 void 1499 StyledEditWindow::_UpdateCleanUndoRedoSaveRevert() 1500 { 1501 fClean = false; 1502 fUndoCleans = false; 1503 fRedoCleans = false; 1504 fRevertItem->SetEnabled(fSaveMessage != NULL); 1505 fSaveItem->SetEnabled(true); 1506 fUndoItem->SetLabel(B_TRANSLATE("Can't Undo")); 1507 fUndoItem->SetEnabled(false); 1508 fCanUndo = false; 1509 fCanRedo = false; 1510 } 1511 1512 1513 int32 1514 StyledEditWindow::_ShowAlert(const BString& text, const BString& label, 1515 const BString& label2, const BString& label3, alert_type type) const 1516 { 1517 const char* button2 = NULL; 1518 if (label2.Length() > 0) 1519 button2 = label2.String(); 1520 1521 const char* button3 = NULL; 1522 button_spacing spacing = B_EVEN_SPACING; 1523 if (label3.Length() > 0) { 1524 button3 = label3.String(); 1525 spacing = B_OFFSET_SPACING; 1526 } 1527 1528 BAlert* alert = new BAlert("Alert", text.String(), label.String(), button2, 1529 button3, B_WIDTH_AS_USUAL, spacing, type); 1530 alert->SetShortcut(0, B_ESCAPE); 1531 1532 return alert->Go(); 1533 } 1534 1535 1536 bool 1537 StyledEditWindow::IsDocumentEntryRef(const entry_ref* ref) 1538 { 1539 if (ref == NULL) 1540 return false; 1541 1542 if (fSaveMessage == NULL) 1543 return false; 1544 1545 entry_ref dir; 1546 const char* name; 1547 if (fSaveMessage->FindRef("directory", &dir) != B_OK 1548 || fSaveMessage->FindString("name", &name) != B_OK) 1549 return false; 1550 1551 entry_ref documentRef; 1552 BPath documentPath(&dir); 1553 documentPath.Append(name); 1554 get_ref_for_path(documentPath.Path(), &documentRef); 1555 1556 if (*ref == documentRef) 1557 return true; 1558 1559 return false; 1560 } 1561 1562