xref: /haiku/src/apps/stylededit/StyledEditWindow.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
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 <stdlib.h>
30 #include <String.h>
31 #include <TextControl.h>
32 #include <TranslationUtils.h>
33 #include <Window.h>
34 
35 #include <CharacterSet.h>
36 #include <CharacterSetRoster.h>
37 
38 
39 using namespace BPrivate;
40 
41 
42 StyledEditWindow::StyledEditWindow(BRect frame, int32 id, uint32 encoding)
43 	: BWindow(frame,"untitled",B_DOCUMENT_WINDOW,0)
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,0)
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 	BFile file;
944 	status_t status = file.SetTo(ref, B_READ_ONLY);
945 	if (status == B_OK)
946 		status = fTextView->GetStyledText(&file);
947 
948 	if (status != B_OK) {
949 		BEntry entry(ref, true);
950 		char name[B_FILE_NAME_LENGTH];
951 		if (entry.GetName(name) != B_OK)
952 			strcpy(name, "???");
953 
954 		char text[B_PATH_NAME_LENGTH + 100];
955 		snprintf(text, sizeof(text), "Error loading \"%s\":\n\t%s", name,
956 			strerror(status));
957 
958 		BAlert* alert = new BAlert("StyledEdit Load Failed", text,
959 			"Bummer", 0, 0, B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_STOP_ALERT);
960 		alert->Go();
961 		return status;
962 	}
963 
964 	// update alignment
965 	switch (fTextView->Alignment()) {
966 		case B_ALIGN_LEFT:
967 		default:
968 			fAlignLeft->SetMarked(true);
969 			break;
970 		case B_ALIGN_CENTER:
971 			fAlignCenter->SetMarked(true);
972 			break;
973 		case B_ALIGN_RIGHT:
974 			fAlignRight->SetMarked(true);
975 			break;
976 	}
977 
978 	// update word wrapping
979 	fWrapItem->SetMarked(fTextView->DoesWordWrap());
980 	return B_OK;
981 }
982 
983 
984 void
985 StyledEditWindow::OpenFile(entry_ref* ref)
986 {
987 	if (_LoadFile(ref) != B_OK) {
988 		fSaveItem->SetEnabled(true);
989 			// allow saving new files
990 	}
991 
992 	be_roster->AddToRecentDocuments(ref, APP_SIGNATURE);
993 	fSaveMessage = new BMessage(B_SAVE_REQUESTED);
994 	if (fSaveMessage) {
995 		BEntry entry(ref, true);
996 		BEntry parent;
997 		entry_ref parentRef;
998 		char name[B_FILE_NAME_LENGTH];
999 
1000 		entry.GetParent(&parent);
1001 		entry.GetName(name);
1002 		parent.GetRef(&parentRef);
1003 		fSaveMessage->AddRef("directory", &parentRef);
1004 		fSaveMessage->AddString("name", name);
1005 		SetTitle(name);
1006 	}
1007 	fTextView->Select(0, 0);
1008 }
1009 
1010 
1011 void
1012 StyledEditWindow::RevertToSaved()
1013 {
1014 	entry_ref ref;
1015 	const char *name;
1016 
1017 	fSaveMessage->FindRef("directory", &ref);
1018 	fSaveMessage->FindString("name", &name);
1019 
1020 	BDirectory dir(&ref);
1021 	status_t status = dir.InitCheck();
1022 	BEntry entry;
1023 	if (status == B_OK)
1024 		status = entry.SetTo(&dir, name);
1025 	if (status == B_OK)
1026 		status = entry.GetRef(&ref);
1027  	if (status != B_OK || !entry.Exists()) {
1028  		BAlert *vanishedAlert;
1029 		BString alertText;
1030 		alertText.SetTo("Cannot revert, file not found: \"");
1031 		alertText << name;
1032 		alertText << "\".";
1033 		vanishedAlert = new BAlert("vanishedAlert", alertText.String(), "Bummer", 0, 0,
1034 			B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_STOP_ALERT);
1035 		vanishedAlert->SetShortcut(0, B_ESCAPE);
1036 		vanishedAlert->Go();
1037 		return;
1038 	}
1039 
1040 	int32 buttonIndex = 0;
1041 	BAlert* revertAlert;
1042 	BString alertText;
1043 	alertText.SetTo("Revert to the last version of \"");
1044 	alertText << Title();
1045 	alertText << "\"? ";
1046 	revertAlert= new BAlert("revertAlert", alertText.String(), "Cancel", "OK", 0,
1047 		B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT);
1048 	revertAlert->SetShortcut(0, B_ESCAPE);
1049 	revertAlert->SetShortcut(1, 'o');
1050 	buttonIndex = revertAlert->Go();
1051 
1052 	if (buttonIndex != 1) {
1053 		// some sort of cancel, don't revert
1054 		return;
1055 	}
1056 
1057 	fTextView->Reset();
1058 
1059 	if (_LoadFile(&ref) != B_OK)
1060 		return;
1061 
1062 	// clear undo modes
1063 	fUndoItem->SetLabel("Can't Undo");
1064 	fUndoItem->SetEnabled(false);
1065 	fUndoFlag = false;
1066 	fCanUndo = false;
1067 	fRedoFlag = false;
1068 	fCanRedo = false;
1069 
1070 	// clear clean modes
1071 	fSaveItem->SetEnabled(false);
1072 	fRevertItem->SetEnabled(false);
1073 	fUndoCleans = false;
1074 	fRedoCleans = false;
1075 	fClean = true;
1076 }
1077 
1078 
1079 status_t
1080 StyledEditWindow::PageSetup(const char* documentName)
1081 {
1082 	BPrintJob printJob(documentName);
1083 
1084 	if (fPrintSettings != NULL)
1085 		printJob.SetSettings(new BMessage(*fPrintSettings));
1086 
1087 	status_t result = printJob.ConfigPage();
1088 	if (result == B_OK) {
1089 		delete fPrintSettings;
1090 		fPrintSettings = printJob.Settings();
1091 	}
1092 
1093 	return result;
1094 }
1095 
1096 
1097 void
1098 StyledEditWindow::Print(const char* documentName)
1099 {
1100 	status_t result;
1101 
1102 	if (fPrintSettings == NULL) {
1103 		result = PageSetup(documentName);
1104 		if (result != B_OK)
1105 			return;
1106 	}
1107 
1108 	BPrintJob printJob(documentName);
1109 	printJob.SetSettings(new BMessage(*fPrintSettings));
1110 	result = printJob.ConfigJob();
1111 	if (result != B_OK)
1112 		return;
1113 
1114 	// information from printJob
1115 	BRect printableRect = printJob.PrintableRect();
1116 	int32 firstPage = printJob.FirstPage();
1117 	int32 lastPage = printJob.LastPage();
1118 
1119 	// lines eventually to be used to compute pages to print
1120 	int32 firstLine = 0;
1121 	int32 lastLine = fTextView->CountLines();
1122 
1123 	// values to be computed
1124 	int32 pagesInDocument = 1;
1125 	int32 linesInDocument = fTextView->CountLines();
1126 
1127 	int32 currentLine = 0;
1128 	while (currentLine < linesInDocument) {
1129 		float currentHeight = 0;
1130 		while (currentHeight < printableRect.Height() && currentLine < linesInDocument) {
1131 			currentHeight += fTextView->LineHeight(currentLine);
1132 			if (currentHeight < printableRect.Height())
1133 				currentLine++;
1134 		}
1135 		if (pagesInDocument == lastPage)
1136 			lastLine = currentLine;
1137 
1138 		if (currentHeight >= printableRect.Height()) {
1139 			pagesInDocument++;
1140 			if (pagesInDocument == firstPage)
1141 				firstLine = currentLine;
1142 		}
1143 	}
1144 
1145 	if (lastPage > pagesInDocument - 1) {
1146 		lastPage = pagesInDocument - 1;
1147 		lastLine = currentLine - 1;
1148 	}
1149 
1150 	printJob.BeginJob();
1151 	int32 printLine = firstLine;
1152 	while (printLine < lastLine) {
1153 		float currentHeight = 0;
1154 		int32 firstLineOnPage = printLine;
1155 		while (currentHeight < printableRect.Height() && printLine < lastLine) {
1156 			currentHeight += fTextView->LineHeight(printLine);
1157 			if (currentHeight < printableRect.Height())
1158 				printLine++;
1159 		}
1160 
1161 		float top = 0;
1162 		if (firstLineOnPage != 0)
1163 			top = fTextView->TextHeight(0, firstLineOnPage - 1);
1164 
1165 		float bottom = fTextView->TextHeight(0, printLine - 1);
1166 		BRect textRect(0.0, top + TEXT_INSET, printableRect.Width(), bottom + TEXT_INSET);
1167 		printJob.DrawView(fTextView, textRect, BPoint(0.0,0.0));
1168 		printJob.SpoolPage();
1169 	}
1170 
1171 	printJob.CommitJob();
1172 }
1173 
1174 
1175 bool
1176 StyledEditWindow::Search(BString string, bool caseSensitive, bool wrap, bool backsearch)
1177 {
1178 	int32 start;
1179 	int32 finish;
1180 
1181 	start = B_ERROR;
1182 
1183 	int32 length = string.Length();
1184 	if (length == 0)
1185 		return false;
1186 
1187 	BString viewText(fTextView->Text());
1188 	int32 textStart, textFinish;
1189 	fTextView->GetSelection(&textStart, &textFinish);
1190 	if (backsearch) {
1191 		if (caseSensitive) {
1192 			start = viewText.FindLast(string, textStart);
1193 		} else {
1194 			start = viewText.IFindLast(string, textStart);
1195 		}
1196 	} else {
1197 		if (caseSensitive == true) {
1198 			start = viewText.FindFirst(string, textFinish);
1199 		} else {
1200 			start = viewText.IFindFirst(string, textFinish);
1201 		}
1202 	}
1203 	if (start == B_ERROR && wrap) {
1204 		if (backsearch) {
1205 			if (caseSensitive) {
1206 				start = viewText.FindLast(string, viewText.Length());
1207 			} else {
1208 				start = viewText.IFindLast(string, viewText.Length());
1209 			}
1210 		} else {
1211 			if (caseSensitive) {
1212 				start = viewText.FindFirst(string, 0);
1213 			} else {
1214 				start = viewText.IFindFirst(string, 0);
1215 			}
1216 		}
1217 	}
1218 
1219 	if (start != B_ERROR) {
1220 		finish = start + length;
1221 		fTextView->Select(start, finish);
1222 		fTextView->ScrollToSelection();
1223 		return true;
1224 	}
1225 
1226 	return false;
1227 }
1228 
1229 
1230 void
1231 StyledEditWindow::FindSelection()
1232 {
1233 	int32 selectionStart, selectionFinish;
1234 	fTextView->GetSelection(&selectionStart, &selectionFinish);
1235 
1236 	int32 selectionLength = selectionFinish- selectionStart;
1237 
1238 	BString viewText = fTextView->Text();
1239 	viewText.CopyInto(fStringToFind, selectionStart, selectionLength);
1240 	fFindAgainItem->SetEnabled(true);
1241 	Search(fStringToFind, fCaseSens, fWrapAround, fBackSearch);
1242 }
1243 
1244 
1245 bool
1246 StyledEditWindow::Replace(BString findthis, BString replaceWith, bool caseSensitive,
1247 	bool wrap, bool backsearch)
1248 {
1249 	if (Search(findthis, caseSensitive, wrap, backsearch)) {
1250 		int32 start, finish;
1251 		fTextView->GetSelection(&start, &finish);
1252 
1253 		fTextView->Delete(start, start + findthis.Length());
1254 		fTextView->Insert(start, replaceWith.String(), replaceWith.Length());
1255 		fTextView->Select(start, start + replaceWith.Length());
1256 		fTextView->ScrollToSelection();
1257 		return true;
1258 	}
1259 
1260 	return false;
1261 }
1262 
1263 
1264 void
1265 StyledEditWindow::ReplaceAll(BString findIt, BString replaceWith, bool caseSensitive)
1266 {
1267 	BString viewText(fTextView->Text());
1268 	if (caseSensitive)
1269 		viewText.ReplaceAll(findIt.String(), replaceWith.String());
1270 	else
1271 		viewText.IReplaceAll(findIt.String(), replaceWith.String());
1272 
1273 	if (viewText.Compare(fTextView->Text()) == 0) {
1274 		// they are the same
1275 		return;
1276 	}
1277 
1278 	int32 textStart, textFinish;
1279 	fTextView->GetSelection(&textStart, &textFinish);
1280 
1281 	fTextView->SetText(viewText.String());
1282 
1283 	if (viewText.Length() < textStart)
1284 		textStart = viewText.Length();
1285 	if (viewText.Length() < textFinish)
1286 		textFinish = viewText.Length();
1287 
1288 	fTextView->Select(textStart,textFinish);
1289 	fTextView->ScrollToSelection();
1290 
1291 	fClean = false;
1292 	fUndoCleans = false;
1293 	fRedoCleans = false;
1294 	fRevertItem->SetEnabled(fSaveMessage != NULL);
1295 	fSaveItem->SetEnabled(true);
1296 	fUndoItem->SetLabel("Can't Undo");
1297 	fUndoItem->SetEnabled(false);
1298 	fCanUndo = false;
1299 	fCanRedo = false;
1300 }
1301 
1302 
1303 void
1304 StyledEditWindow::SearchAllWindows(BString find, BString replace, bool caseSensitive)
1305 {
1306 	int32 numWindows;
1307 	numWindows = be_app->CountWindows();
1308 
1309 	BMessage *message;
1310 	message= new BMessage(MSG_REPLACE_ALL);
1311 	message->AddString("FindText", find);
1312 	message->AddString("ReplaceText", replace);
1313 	message->AddBool("casesens", caseSensitive);
1314 
1315 	while (numWindows >= 0) {
1316 		StyledEditWindow *window = dynamic_cast<StyledEditWindow *>(
1317 			be_app->WindowAt(numWindows));
1318 
1319 		BMessenger messenger(window);
1320 		messenger.SendMessage(message);
1321 
1322 		numWindows--;
1323 	}
1324 }
1325 
1326 
1327 void
1328 StyledEditWindow::SetFontSize(float fontSize)
1329 {
1330 	uint32 sameProperties;
1331 	BFont font;
1332 
1333 	fTextView->GetFontAndColor(&font, &sameProperties);
1334 	font.SetSize(fontSize);
1335 	fTextView->SetFontAndColor(&font, B_FONT_SIZE);
1336 	fClean = false;
1337 	fUndoCleans = false;
1338 	fRedoCleans = false;
1339 	fRevertItem->SetEnabled(fSaveMessage != NULL);
1340 	fSaveItem->SetEnabled(true);
1341 	fUndoItem->SetLabel("Can't Undo");
1342 	fUndoItem->SetEnabled(false);
1343 	fCanUndo = false;
1344 	fCanRedo = false;
1345 }
1346 
1347 
1348 void
1349 StyledEditWindow::SetFontColor(const rgb_color *color)
1350 {
1351 	uint32 sameProperties;
1352 	BFont font;
1353 
1354 	fTextView->GetFontAndColor(&font, &sameProperties, NULL, NULL);
1355 	fTextView->SetFontAndColor(&font, 0, color);
1356 	fClean = false;
1357 	fUndoCleans = false;
1358 	fRedoCleans = false;
1359 	fRevertItem->SetEnabled(fSaveMessage != NULL);
1360 	fSaveItem->SetEnabled(true);
1361 	fUndoItem->SetLabel("Can't Undo");
1362 	fUndoItem->SetEnabled(false);
1363 	fCanUndo = false;
1364 	fCanRedo = false;
1365 }
1366 
1367 
1368 void
1369 StyledEditWindow::SetFontStyle(const char *fontFamily, const char *fontStyle)
1370 {
1371 	BFont font;
1372 	uint32 sameProperties;
1373 
1374 	// find out what the old font was
1375 	font_family oldFamily;
1376 	font_style oldStyle;
1377 	fTextView->GetFontAndColor(&font, &sameProperties);
1378 	font.GetFamilyAndStyle(&oldFamily, &oldStyle);
1379 
1380 	// clear that family's bit on the menu, if necessary
1381 	if (strcmp(oldFamily, fontFamily)) {
1382 		BMenuItem* oldItem = fFontMenu->FindItem(oldFamily);
1383 		if (oldItem != NULL)
1384 			oldItem->SetMarked(false);
1385 	}
1386 
1387 	font.SetFamilyAndStyle(fontFamily, fontStyle);
1388 	fTextView->SetFontAndColor(&font);
1389 
1390 	BMenuItem* superItem;
1391 	superItem = fFontMenu->FindItem(fontFamily);
1392 	if (superItem != NULL)
1393 		superItem->SetMarked(true);
1394 
1395 	fClean = false;
1396 	fUndoCleans = false;
1397 	fRedoCleans = false;
1398 	fRevertItem->SetEnabled(fSaveMessage != NULL);
1399 	fSaveItem->SetEnabled(true);
1400 	fUndoItem->SetLabel("Can't Undo");
1401 	fUndoItem->SetEnabled(false);
1402 	fCanUndo = false;
1403 	fCanRedo = false;
1404 }
1405