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