xref: /haiku/src/apps/mail/Prefs.cpp (revision ac078a5b110045de12089052a685a6a080545db1)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN
23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or
30 registered trademarks of Be Incorporated in the United States and other
31 countries. Other brand product names are registered trademarks or trademarks
32 of their respective holders. All rights reserved.
33 */
34 
35 
36 #include "Prefs.h"
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #include <Application.h>
43 #include <CharacterSet.h>
44 #include <CharacterSetRoster.h>
45 #include <E-mail.h>
46 #include <GridView.h>
47 #include <GroupLayoutBuilder.h>
48 #include <InterfaceKit.h>
49 #include <Locale.h>
50 #include <MailSettings.h>
51 #include <mail_encoding.h>
52 #include <StorageKit.h>
53 #include <String.h>
54 
55 using namespace BPrivate;
56 
57 #include "MailApp.h"
58 #include "MailSupport.h"
59 #include "MailWindow.h"
60 #include "Messages.h"
61 #include "Signature.h"
62 
63 
64 #define B_TRANSLATE_CONTEXT "Mail"
65 
66 #define BUTTON_WIDTH		70
67 #define BUTTON_HEIGHT		20
68 #define ITEM_SPACE			6
69 
70 #define OK_BUTTON_X1		(PREF_WIDTH - BUTTON_WIDTH - 6)
71 #define OK_BUTTON_X2		(OK_BUTTON_X1 + BUTTON_WIDTH)
72 
73 #define REVERT_BUTTON_X1	8
74 #define REVERT_BUTTON_X2	(REVERT_BUTTON_X1 + BUTTON_WIDTH)
75 
76 enum	P_MESSAGES			{P_OK = 128, P_CANCEL, P_REVERT, P_FONT,
77 							 P_SIZE, P_LEVEL, P_WRAP, P_ATTACH_ATTRIBUTES,
78 							 P_SIG, P_ENC, P_WARN_UNENCODABLE,
79 							 P_SPELL_CHECK_START_ON, P_BUTTON_BAR,
80 							 P_ACCOUNT, P_REPLYTO, P_REPLY_PREAMBLE,
81 							 P_COLORED_QUOTES, P_MARK_READ};
82 
83 extern BPoint	prefs_window;
84 
85 //#pragma mark -
86 
87 
88 static inline void
89 add_menu_to_layout(BMenuField* menu, BGridLayout* layout, int32& row)
90 {
91 	menu->SetAlignment(B_ALIGN_RIGHT);
92 	layout->AddItem(menu->CreateLabelLayoutItem(), 0, row);
93 	layout->AddItem(menu->CreateMenuBarLayoutItem(), 1, row, 2);
94 	row++;
95 }
96 
97 
98 TPrefsWindow::TPrefsWindow(BRect rect, BFont* font, int32* level, bool* wrap,
99 	bool* attachAttributes, bool* cquotes, int32* account, int32* replyTo,
100 	char** preamble, char** sig, uint32* encoding, bool* warnUnencodable,
101 	bool* spellCheckStartOn, bool* autoMarkRead, uint8* buttonBar)
102 	:
103 	BWindow(rect, B_TRANSLATE("Mail preferences"),
104 		B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE
105 			| B_AUTO_UPDATE_SIZE_LIMITS),
106 
107 	fNewWrap(wrap),
108 	fWrap(*fNewWrap),
109 
110 	fNewAttachAttributes(attachAttributes),
111 	fAttachAttributes(*fNewAttachAttributes),
112 
113 	fNewButtonBar(buttonBar),
114 	fButtonBar(*fNewButtonBar),
115 
116 	fNewColoredQuotes(cquotes),
117 	fColoredQuotes(*fNewColoredQuotes),
118 
119 	fNewAccount(account),
120 	fAccount(*fNewAccount),
121 
122 	fNewReplyTo(replyTo),
123 	fReplyTo(*fNewReplyTo),
124 
125 	fNewPreamble(preamble),
126 
127 	fNewSignature(sig),
128 	fSignature((char*)malloc(strlen(*fNewSignature) + 1)),
129 
130 	fNewFont(font),
131 	fFont(*fNewFont),
132 
133 	fNewEncoding(encoding),
134 	fEncoding(*fNewEncoding),
135 
136 	fNewWarnUnencodable(warnUnencodable),
137 	fWarnUnencodable(*fNewWarnUnencodable),
138 
139 	fNewSpellCheckStartOn(spellCheckStartOn),
140 	fSpellCheckStartOn(*fNewSpellCheckStartOn),
141 
142 	fNewAutoMarkRead(autoMarkRead),
143 	fAutoMarkRead(*autoMarkRead)
144 {
145 	strcpy(fSignature, *fNewSignature);
146 
147 	BMenuField* menu;
148 
149 	// group boxes
150 
151 	const float kSpacing = 8;
152 
153 	BGridView* interfaceView = new BGridView(kSpacing, kSpacing);
154 	BGridLayout* interfaceLayout = interfaceView->GridLayout();
155 	interfaceLayout->SetInsets(kSpacing, kSpacing, kSpacing, kSpacing);
156 	BGridView* mailView = new BGridView(kSpacing, kSpacing);
157 	BGridLayout* mailLayout = mailView->GridLayout();
158 	mailLayout->SetInsets(kSpacing, kSpacing, kSpacing, kSpacing);
159 
160 	interfaceLayout->AlignLayoutWith(mailLayout, B_HORIZONTAL);
161 
162 	BBox* interfaceBox = new BBox(B_FANCY_BORDER, interfaceView);
163 	interfaceBox->SetLabel(B_TRANSLATE("User interface"));
164 	BBox* mailBox = new BBox(B_FANCY_BORDER, mailView);
165 	mailBox->SetLabel(B_TRANSLATE("Mailing"));
166 
167 	// revert, ok & cancel
168 
169 	BButton* okButton = new BButton("ok", B_TRANSLATE("OK"),
170 		new BMessage(P_OK));
171 	okButton->MakeDefault(true);
172 
173 	BButton* cancelButton = new BButton("cancel", B_TRANSLATE("Cancel"),
174 		new BMessage(P_CANCEL));
175 
176 	fRevert = new BButton("revert", B_TRANSLATE("Revert"),
177 		new BMessage(P_REVERT));
178 	fRevert->SetEnabled(false);
179 
180 	// User Interface
181 	int32 layoutRow = 0;
182 
183 	fButtonBarMenu = _BuildButtonBarMenu(*buttonBar);
184 	menu = new BMenuField("bar", B_TRANSLATE("Button bar:"),
185 		fButtonBarMenu, NULL);
186 	add_menu_to_layout(menu, interfaceLayout, layoutRow);
187 
188 	fFontMenu = _BuildFontMenu(font);
189 	menu = new BMenuField("font", B_TRANSLATE("Font:"),
190 		fFontMenu, NULL);
191 	add_menu_to_layout(menu, interfaceLayout, layoutRow);
192 
193 	fSizeMenu = _BuildSizeMenu(font);
194 	menu = new BMenuField("size", B_TRANSLATE("Size:"), fSizeMenu, NULL);
195 	add_menu_to_layout(menu, interfaceLayout, layoutRow);
196 
197 	fColoredQuotesMenu = _BuildColoredQuotesMenu(fColoredQuotes);
198 	menu = new BMenuField("cquotes", B_TRANSLATE("Colored quotes:"),
199 		fColoredQuotesMenu, NULL);
200 	add_menu_to_layout(menu, interfaceLayout, layoutRow);
201 
202 	fSpellCheckStartOnMenu = _BuildSpellCheckStartOnMenu(fSpellCheckStartOn);
203 	menu = new BMenuField("spellCheckStartOn",
204 		B_TRANSLATE("Initial spell check mode:"),
205 		fSpellCheckStartOnMenu, NULL);
206 	add_menu_to_layout(menu, interfaceLayout, layoutRow);
207 
208 	fAutoMarkReadMenu = _BuildAutoMarkReadMenu(fAutoMarkRead);
209 	menu = new BMenuField("autoMarkRead",
210 		B_TRANSLATE("Automatically mark mail as read:"),
211 		fAutoMarkReadMenu,	NULL);
212 	add_menu_to_layout(menu, interfaceLayout, layoutRow);
213 	// Mail Accounts
214 
215 	layoutRow = 0;
216 
217 	fAccountMenu = _BuildAccountMenu(fAccount);
218 	menu = new BMenuField("account", B_TRANSLATE("Default account:"),
219 		fAccountMenu, NULL);
220 	add_menu_to_layout(menu, mailLayout, layoutRow);
221 
222 	fReplyToMenu = _BuildReplyToMenu(fReplyTo);
223 	menu = new BMenuField("replyTo", B_TRANSLATE("Reply account:"),
224 		fReplyToMenu, NULL);
225 	add_menu_to_layout(menu, mailLayout, layoutRow);
226 
227 	// Mail Contents
228 
229 	fReplyPreamble = new BTextControl("replytext",
230 		B_TRANSLATE("Reply preamble:"),
231 		*preamble, new BMessage(P_REPLY_PREAMBLE));
232 	fReplyPreamble->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
233 
234 	fReplyPreambleMenu = _BuildReplyPreambleMenu();
235 	menu = new BMenuField("replyPreamble", NULL, fReplyPreambleMenu, NULL);
236 	menu->SetExplicitMaxSize(BSize(27, B_SIZE_UNSET));
237 
238 	mailLayout->AddItem(fReplyPreamble->CreateLabelLayoutItem(), 0, layoutRow);
239 	mailLayout->AddItem(fReplyPreamble->CreateTextViewLayoutItem(), 1,
240 		layoutRow);
241 	mailLayout->AddView(menu, 2, layoutRow);
242 	layoutRow++;
243 
244 	fSignatureMenu = _BuildSignatureMenu(*sig);
245 	menu = new BMenuField("sig", B_TRANSLATE("Auto signature:"),
246 		fSignatureMenu, NULL);
247 	add_menu_to_layout(menu, mailLayout, layoutRow);
248 
249 	fEncodingMenu = _BuildEncodingMenu(fEncoding);
250 	menu = new BMenuField("enc", B_TRANSLATE("Encoding:"),
251 		fEncodingMenu, NULL);
252 	add_menu_to_layout(menu, mailLayout, layoutRow);
253 
254 	fWarnUnencodableMenu = _BuildWarnUnencodableMenu(fWarnUnencodable);
255 	menu = new BMenuField("warnUnencodable", B_TRANSLATE("Warn unencodable:"),
256 		fWarnUnencodableMenu, NULL);
257 	add_menu_to_layout(menu, mailLayout, layoutRow);
258 
259 	fWrapMenu = _BuildWrapMenu(*wrap);
260 	menu = new BMenuField("wrap", B_TRANSLATE("Text wrapping:"),
261 		fWrapMenu, NULL);
262 	add_menu_to_layout(menu, mailLayout, layoutRow);
263 
264 	fAttachAttributesMenu = _BuildAttachAttributesMenu(*attachAttributes);
265 	menu = new BMenuField("attachAttributes",
266 		B_TRANSLATE("Attach attributes:"),
267 		fAttachAttributesMenu, NULL);
268 	add_menu_to_layout(menu, mailLayout, layoutRow);
269 
270 	SetLayout(new BGroupLayout(B_HORIZONTAL));
271 
272 	AddChild(BGroupLayoutBuilder(B_VERTICAL, kSpacing)
273 		.Add(interfaceBox)
274 		.Add(mailBox)
275 		.Add(BGroupLayoutBuilder(B_HORIZONTAL, kSpacing)
276 			.Add(fRevert)
277 			.AddGlue()
278 			.Add(cancelButton)
279 			.Add(okButton)
280 		)
281 		.SetInsets(kSpacing, kSpacing, kSpacing, kSpacing)
282 	);
283 
284 	Show();
285 }
286 
287 
288 TPrefsWindow::~TPrefsWindow()
289 {
290 	BMessage msg(WINDOW_CLOSED);
291 	msg.AddInt32("kind", PREFS_WINDOW);
292 	msg.AddPoint("window pos", Frame().LeftTop());
293 	be_app->PostMessage(&msg);
294 }
295 
296 
297 void
298 TPrefsWindow::MessageReceived(BMessage* msg)
299 {
300 	bool revert = true;
301 	const char* family;
302 	const char* signature;
303 	const char* style;
304 	char label[256];
305 	int32 new_size;
306 	int32 old_size;
307 	font_family new_family;
308 	font_family old_family;
309 	font_style new_style;
310 	font_style old_style;
311 	BMenuItem* item;
312 	BMessage message;
313 
314 	switch (msg->what) {
315 		case P_OK:
316 			if (strcmp(fReplyPreamble->Text(), *fNewPreamble)) {
317 				free(*fNewPreamble);
318 				*fNewPreamble
319 					= (char *)malloc(strlen(fReplyPreamble->Text()) + 1);
320 				strcpy(*fNewPreamble, fReplyPreamble->Text());
321 			}
322 			be_app->PostMessage(PREFS_CHANGED);
323 			Quit();
324 			break;
325 
326 		case P_CANCEL:
327 			revert = false;
328 			// supposed to fall through
329 		case P_REVERT:
330 			fFont.GetFamilyAndStyle(&old_family, &old_style);
331 			fNewFont->GetFamilyAndStyle(&new_family, &new_style);
332 			old_size = (int32)fFont.Size();
333 			new_size = (int32)fNewFont->Size();
334 			if (strcmp(old_family, new_family) || strcmp(old_style, new_style)
335 				|| old_size != new_size) {
336 				fNewFont->SetFamilyAndStyle(old_family, old_style);
337 				if (revert) {
338 					sprintf(label, "%s %s", old_family, old_style);
339 					item = fFontMenu->FindItem(label);
340 					if (item != NULL)
341 						item->SetMarked(true);
342 				}
343 
344 				fNewFont->SetSize(old_size);
345 				if (revert) {
346 					sprintf(label, "%ld", old_size);
347 					item = fSizeMenu->FindItem(label);
348 					if (item != NULL)
349 						item->SetMarked(true);
350 				}
351 				message.what = M_FONT;
352 				be_app->PostMessage(&message);
353 			}
354 			*fNewWrap = fWrap;
355 			*fNewAttachAttributes = fAttachAttributes;
356 
357 			if (strcmp(fSignature, *fNewSignature)) {
358 				free(*fNewSignature);
359 				*fNewSignature = (char*)malloc(strlen(fSignature) + 1);
360 				strcpy(*fNewSignature, fSignature);
361 			}
362 
363 			*fNewEncoding = fEncoding;
364 			*fNewWarnUnencodable = fWarnUnencodable;
365 			*fNewSpellCheckStartOn = fSpellCheckStartOn;
366 			*fNewAutoMarkRead = fAutoMarkRead;
367 			*fNewButtonBar = fButtonBar;
368 
369 			be_app->PostMessage(PREFS_CHANGED);
370 
371 			if (revert) {
372 				for (int i = fAccountMenu->CountItems(); --i > 0;) {
373 					BMenuItem *item = fAccountMenu->ItemAt(i);
374 					BMessage* itemMessage = item->Message();
375 					if (itemMessage != NULL
376 						&& itemMessage->FindInt32("id") == *(int32 *)&fAccount) {
377 						item->SetMarked(true);
378 						break;
379 					}
380 				}
381 
382 				strcpy(label,fReplyTo == ACCOUNT_USE_DEFAULT
383 					? B_TRANSLATE("Use default account")
384 					: B_TRANSLATE("Account from mail"));
385 				if ((item = fReplyToMenu->FindItem(label)) != NULL)
386 					item->SetMarked(true);
387 
388 				strcpy(label, fWrap ? B_TRANSLATE("On") : B_TRANSLATE("Off"));
389 				if ((item = fWrapMenu->FindItem(label)) != NULL)
390 					item->SetMarked(true);
391 
392 				strcpy(label, fAttachAttributes
393 					? B_TRANSLATE("Include file attributes in attachments")
394 					: B_TRANSLATE("No file attributes, just plain data"));
395 				if ((item = fAttachAttributesMenu->FindItem(label)) != NULL)
396 					item->SetMarked(true);
397 
398 				strcpy(label, fColoredQuotes ? B_TRANSLATE("On") : B_TRANSLATE("Off"));
399 				if ((item = fColoredQuotesMenu->FindItem(label)) != NULL)
400 					item->SetMarked(true);
401 
402 				if (strcmp(fReplyPreamble->Text(), *fNewPreamble))
403 					fReplyPreamble->SetText(*fNewPreamble);
404 
405 				item = fSignatureMenu->FindItem(fSignature);
406 				if (item)
407 					item->SetMarked(true);
408 
409 				uint32 index = 0;
410 				while ((item = fEncodingMenu->ItemAt(index++)) != NULL) {
411 					BMessage* itemMessage = item->Message();
412 					if (itemMessage == NULL)
413 						continue;
414 
415 					int32 encoding;
416 					if (itemMessage->FindInt32("encoding", &encoding) == B_OK
417 						&& (uint32)encoding == *fNewEncoding) {
418 						item->SetMarked(true);
419 						break;
420 					}
421 				}
422 
423 				strcpy(label, fWarnUnencodable ? B_TRANSLATE("On") : B_TRANSLATE("Off"));
424 				if ((item = fWarnUnencodableMenu->FindItem(label)) != NULL)
425 					item->SetMarked(true);
426 
427 				strcpy(label, fSpellCheckStartOn ? B_TRANSLATE("On") : B_TRANSLATE("Off"));
428 				if ((item = fSpellCheckStartOnMenu->FindItem(label)) != NULL)
429 					item->SetMarked(true);
430 			} else
431 				Quit();
432 			break;
433 
434 		case P_FONT:
435 			family = NULL;
436 			style = NULL;
437 			int32 family_menu_index;
438 			if (msg->FindString("font", &family) == B_OK) {
439 				msg->FindString("style", &style);
440 				fNewFont->SetFamilyAndStyle(family, style);
441 				message.what = M_FONT;
442 				be_app->PostMessage(&message);
443 			}
444 
445 			/* grab this little tidbit so we can set the correct Family */
446 			if (msg->FindInt32("parent_index", &family_menu_index) == B_OK)
447 				fFontMenu->ItemAt(family_menu_index)->SetMarked(true);
448 			break;
449 
450 		case P_SIZE:
451 			old_size = (int32) fNewFont->Size();
452 			msg->FindInt32("size", &new_size);
453 			if (old_size != new_size) {
454 				fNewFont->SetSize(new_size);
455 				message.what = M_FONT;
456 				be_app->PostMessage(&message);
457 			}
458 			break;
459 
460 		case P_WRAP:
461 			msg->FindBool("wrap", fNewWrap);
462 			break;
463 		case P_ATTACH_ATTRIBUTES:
464 			msg->FindBool("attachAttributes", fNewAttachAttributes);
465 			break;
466 		case P_COLORED_QUOTES:
467 			msg->FindBool("cquotes", fNewColoredQuotes);
468 			break;
469 		case P_ACCOUNT:
470 			msg->FindInt32("id",(int32*)fNewAccount);
471 			break;
472 		case P_REPLYTO:
473 			msg->FindInt32("replyTo", fNewReplyTo);
474 			break;
475 		case P_REPLY_PREAMBLE:
476 		{
477 			int32 index = -1;
478 			if (msg->FindInt32("index", &index) < B_OK)
479 				break;
480 			BMenuItem *item = fReplyPreambleMenu->ItemAt(index);
481 			if (item == NULL) {
482 				msg->PrintToStream();
483 				break;
484 			}
485 
486 			BTextView *text = fReplyPreamble->TextView();
487 			int32 selectionStart;
488 			int32 selectionEnd;
489 			text->GetSelection(&selectionStart, &selectionEnd);
490 			if (selectionStart != selectionEnd)
491 				text->Delete(selectionStart, selectionEnd);
492 			text->Insert(item->Label(), 2);
493 		}
494 		case P_SIG:
495 			free(*fNewSignature);
496 			if (msg->FindString("signature", &signature) == B_NO_ERROR) {
497 				*fNewSignature = (char*)malloc(strlen(signature) + 1);
498 				strcpy(*fNewSignature, signature);
499 			} else {
500 				*fNewSignature = (char*)malloc(
501 					strlen(B_TRANSLATE("None")) + 1);
502 				strcpy(*fNewSignature, B_TRANSLATE("None"));
503 			}
504 			break;
505 		case P_ENC:
506 			msg->FindInt32("encoding", (int32*)fNewEncoding);
507 			break;
508 		case P_WARN_UNENCODABLE:
509 			msg->FindBool("warnUnencodable", fNewWarnUnencodable);
510 			break;
511 		case P_SPELL_CHECK_START_ON:
512 			msg->FindBool("spellCheckStartOn", fNewSpellCheckStartOn);
513 			break;
514 		case P_MARK_READ:
515 			msg->FindBool("autoMarkRead", fNewAutoMarkRead);
516 			be_app->PostMessage(PREFS_CHANGED);
517 			break;
518 		case P_BUTTON_BAR:
519 			msg->FindInt8("bar", (int8*)fNewButtonBar);
520 			be_app->PostMessage(PREFS_CHANGED);
521 			break;
522 
523 		default:
524 			BWindow::MessageReceived(msg);
525 	}
526 
527 	fFont.GetFamilyAndStyle(&old_family, &old_style);
528 	fNewFont->GetFamilyAndStyle(&new_family, &new_style);
529 	old_size = (int32) fFont.Size();
530 	new_size = (int32) fNewFont->Size();
531 	bool changed = old_size != new_size
532 		|| fWrap != *fNewWrap
533 		|| fAttachAttributes != *fNewAttachAttributes
534 		|| fColoredQuotes != *fNewColoredQuotes
535 		|| fAccount != *fNewAccount
536 		|| fReplyTo != *fNewReplyTo
537 		|| strcmp(old_family, new_family)
538 		|| strcmp(old_style, new_style)
539 		|| strcmp(fReplyPreamble->Text(), *fNewPreamble)
540 		|| strcmp(fSignature, *fNewSignature)
541 		|| fEncoding != *fNewEncoding
542 		|| fWarnUnencodable != *fNewWarnUnencodable
543 		|| fSpellCheckStartOn != *fNewSpellCheckStartOn
544 		|| fAutoMarkRead != *fNewAutoMarkRead
545 		|| fButtonBar != *fNewButtonBar;
546 	fRevert->SetEnabled(changed);
547 }
548 
549 
550 BPopUpMenu*
551 TPrefsWindow::_BuildFontMenu(BFont* font)
552 {
553 	font_family	def_family;
554 	font_style	def_style;
555 	font_family	f_family;
556 	font_style	f_style;
557 
558 	BPopUpMenu *menu = new BPopUpMenu("");
559 	font->GetFamilyAndStyle(&def_family, &def_style);
560 
561 	int32 family_menu_index = 0;
562 	int family_count = count_font_families();
563 	for (int family_loop = 0; family_loop < family_count; family_loop++) {
564 		get_font_family(family_loop, &f_family);
565 		BMenu *family_menu = new BMenu(f_family);
566 
567 		int style_count = count_font_styles(f_family);
568 		for (int style_loop = 0; style_loop < style_count; style_loop++) {
569 			get_font_style(f_family, style_loop, &f_style);
570 
571 			BMessage *msg = new BMessage(P_FONT);
572 			msg->AddString("font", f_family);
573 			msg->AddString("style", f_style);
574 			// we send this to make setting the Family easier when things
575 			// change
576 			msg->AddInt32("parent_index", family_menu_index);
577 
578 			BMenuItem *item = new BMenuItem(f_style, msg);
579 			family_menu->AddItem(item);
580 			if ((strcmp(def_family, f_family) == 0)
581 				&& (strcmp(def_style, f_style) == 0)) {
582 				item->SetMarked(true);
583 			}
584 
585 			item->SetTarget(this);
586 		}
587 
588 		menu->AddItem(family_menu);
589 		BMenuItem *item = menu->ItemAt(family_menu_index);
590 		BMessage *msg = new BMessage(P_FONT);
591 		msg->AddString("font", f_family);
592 
593 		item->SetMessage(msg);
594 		item->SetTarget(this);
595 		if (strcmp(def_family, f_family) == 0)
596 			item->SetMarked(true);
597 
598 		family_menu_index++;
599 	}
600 	return menu;
601 }
602 
603 
604 BPopUpMenu*
605 TPrefsWindow::_BuildLevelMenu(int32 level)
606 {
607 	BMenuItem* item;
608 	BMessage* msg;
609 	BPopUpMenu* menu;
610 
611 	menu = new BPopUpMenu("");
612 	msg = new BMessage(P_LEVEL);
613 	msg->AddInt32("level", L_BEGINNER);
614 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Beginner"), msg));
615 	if (level == L_BEGINNER)
616 		item->SetMarked(true);
617 
618 	msg = new BMessage(P_LEVEL);
619 	msg->AddInt32("level", L_EXPERT);
620 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Expert"), msg));
621 	if (level == L_EXPERT)
622 		item->SetMarked(true);
623 
624 	return menu;
625 }
626 
627 
628 BPopUpMenu*
629 TPrefsWindow::_BuildAccountMenu(int32 account)
630 {
631 	BPopUpMenu* menu = new BPopUpMenu("");
632 	BMenuItem* item;
633 
634 	//menu->SetRadioMode(true);
635 	BMailAccounts accounts;
636 	if (accounts.CountAccounts() == 0) {
637 		menu->AddItem(item = new BMenuItem("<no account found>", NULL));
638 		item->SetEnabled(false);
639 		return menu;
640 	}
641 
642 	BMessage* msg;
643 	for (int32 i = 0; i < accounts.CountAccounts(); i++) {
644 		BMailAccountSettings* settings = accounts.AccountAt(i);
645 		item = new BMenuItem(settings->Name(), msg = new BMessage(P_ACCOUNT));
646 
647 		msg->AddInt32("id", settings->AccountID());
648 
649 		if (account == settings->AccountID())
650 			item->SetMarked(true);
651 
652 		menu->AddItem(item);
653 	}
654 	return menu;
655 }
656 
657 
658 BPopUpMenu*
659 TPrefsWindow::_BuildReplyToMenu(int32 account)
660 {
661 	BPopUpMenu* menu = new BPopUpMenu(B_EMPTY_STRING);
662 
663 	BMenuItem* item;
664 	BMessage* msg;
665 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Use default account"),
666 		msg = new BMessage(P_REPLYTO)));
667 	msg->AddInt32("replyTo", ACCOUNT_USE_DEFAULT);
668 	if (account == ACCOUNT_USE_DEFAULT)
669 		item->SetMarked(true);
670 
671 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Account from mail"),
672 		msg = new BMessage(P_REPLYTO)));
673 	msg->AddInt32("replyTo", ACCOUNT_FROM_MAIL);
674 	if (account == ACCOUNT_FROM_MAIL)
675 		item->SetMarked(true);
676 
677 	return menu;
678 }
679 
680 
681 BMenu*
682 TPrefsWindow::_BuildReplyPreambleMenu()
683 {
684 	BMenu *menu = new BMenu(B_EMPTY_STRING);
685 
686 	menu->AddItem(new BMenuItem(B_TRANSLATE("%n - Full name"),
687 		new BMessage(P_REPLY_PREAMBLE)));
688 
689 	menu->AddItem(new BMenuItem(B_TRANSLATE("%e - E-mail address"),
690 		new BMessage(P_REPLY_PREAMBLE)));
691 
692 	menu->AddItem(new BMenuItem(B_TRANSLATE("%d - Date"),
693 		new BMessage(P_REPLY_PREAMBLE)));
694 
695 	menu->AddSeparatorItem();
696 
697 	menu->AddItem(new BMenuItem(B_TRANSLATE("\\n - Newline"),
698 		new BMessage(P_REPLY_PREAMBLE)));
699 
700 	return menu;
701 }
702 
703 
704 BPopUpMenu*
705 TPrefsWindow::_BuildSignatureMenu(char* sig)
706 {
707 	char name[B_FILE_NAME_LENGTH];
708 	BEntry entry;
709 	BFile file;
710 	BMenuItem* item;
711 	BMessage* msg;
712 	BQuery query;
713 	BVolume vol;
714 	BVolumeRoster volume;
715 
716 	BPopUpMenu* menu = new BPopUpMenu("");
717 
718 	msg = new BMessage(P_SIG);
719 	msg->AddString("signature", B_TRANSLATE("None"));
720 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("None"), msg));
721 	if (!strcmp(sig, B_TRANSLATE("None")))
722 		item->SetMarked(true);
723 
724 	msg = new BMessage(P_SIG);
725 	msg->AddString("signature", B_TRANSLATE("Random"));
726 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Random"), msg));
727 	if (!strcmp(sig, B_TRANSLATE("Random")))
728 		item->SetMarked(true);
729 	menu->AddSeparatorItem();
730 
731 	volume.GetBootVolume(&vol);
732 	query.SetVolume(&vol);
733 	query.SetPredicate("_signature = *");
734 	query.Fetch();
735 
736 	while (query.GetNextEntry(&entry) == B_NO_ERROR) {
737 		file.SetTo(&entry, O_RDONLY);
738 		if (file.InitCheck() == B_NO_ERROR) {
739 			msg = new BMessage(P_SIG);
740 			file.ReadAttr("_signature", B_STRING_TYPE, 0, name, sizeof(name));
741 			msg->AddString("signature", name);
742 			menu->AddItem(item = new BMenuItem(name, msg));
743 			if (!strcmp(sig, name))
744 				item->SetMarked(true);
745 		}
746 	}
747 	return menu;
748 }
749 
750 
751 BPopUpMenu*
752 TPrefsWindow::_BuildSizeMenu(BFont* font)
753 {
754 	char label[16];
755 	uint32 loop;
756 	int32 sizes[] = {9, 10, 11, 12, 14, 18, 24};
757 	float size;
758 	BMenuItem* item;
759 	BMessage* msg;
760 	BPopUpMenu* menu;
761 
762 	menu = new BPopUpMenu("");
763 	size = font->Size();
764 	for (loop = 0; loop < sizeof(sizes) / sizeof(int32); loop++) {
765 		msg = new BMessage(P_SIZE);
766 		msg->AddInt32("size", sizes[loop]);
767 		sprintf(label, "%ld", sizes[loop]);
768 		menu->AddItem(item = new BMenuItem(label, msg));
769 		if (sizes[loop] == (int32)size)
770 			item->SetMarked(true);
771 	}
772 	return menu;
773 }
774 
775 
776 BPopUpMenu*
777 TPrefsWindow::_BuildBoolMenu(uint32 what, const char* boolItem, bool isTrue)
778 {
779 	BMenuItem* item;
780 	BMessage* msg;
781 	BPopUpMenu* menu;
782 
783 	menu = new BPopUpMenu("");
784 	msg = new BMessage(what);
785 	msg->AddBool(boolItem, true);
786 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("On"), msg));
787 	if (isTrue)
788 		item->SetMarked(true);
789 
790 	msg = new BMessage(what);
791 	msg->AddInt32(boolItem, false);
792 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Off"), msg));
793 	if (!isTrue)
794 		item->SetMarked(true);
795 
796 	return menu;
797 }
798 
799 
800 BPopUpMenu*
801 TPrefsWindow::_BuildWrapMenu(bool wrap)
802 {
803 	return _BuildBoolMenu(P_WRAP, "wrap", wrap);
804 }
805 
806 
807 BPopUpMenu*
808 TPrefsWindow::_BuildAttachAttributesMenu(bool attachAttributes)
809 {
810 	BMenuItem* item;
811 	BMessage* msg;
812 	BPopUpMenu* menu;
813 
814 	menu = new BPopUpMenu("");
815 	msg = new BMessage(P_ATTACH_ATTRIBUTES);
816 	msg->AddBool("attachAttributes", true);
817 	menu->AddItem(item = new BMenuItem(
818 		B_TRANSLATE("Include file attributes in attachments"), msg));
819 	if (attachAttributes)
820 		item->SetMarked(true);
821 
822 	msg = new BMessage(P_ATTACH_ATTRIBUTES);
823 	msg->AddInt32("attachAttributes", false);
824 	menu->AddItem(item = new BMenuItem(
825 		B_TRANSLATE("No file attributes, just plain data"), msg));
826 	if (!attachAttributes)
827 		item->SetMarked(true);
828 
829 	return menu;
830 }
831 
832 
833 BPopUpMenu*
834 TPrefsWindow::_BuildColoredQuotesMenu(bool quote)
835 {
836 	return _BuildBoolMenu(P_COLORED_QUOTES, "cquotes", quote);
837 }
838 
839 
840 BPopUpMenu*
841 TPrefsWindow::_BuildEncodingMenu(uint32 encoding)
842 {
843 	BMenuItem* item;
844 	BMessage* msg;
845 	BPopUpMenu* menu;
846 
847 	menu = new BPopUpMenu("");
848 
849 	BCharacterSetRoster roster;
850 	BCharacterSet charset;
851 	while (roster.GetNextCharacterSet(&charset) == B_NO_ERROR) {
852 		BString name(charset.GetPrintName());
853 		const char* mime = charset.GetMIMEName();
854 		if (mime)
855 			name << " (" << mime << ")";
856 		msg = new BMessage(P_ENC);
857 		uint32 convert_id;
858 		if ((mime == 0) || (strcasecmp(mime, "UTF-8") != 0))
859 			convert_id = charset.GetConversionID();
860 		else
861 			convert_id = B_MAIL_UTF8_CONVERSION;
862 		msg->AddInt32("encoding", convert_id);
863 		menu->AddItem(item = new BMenuItem(name.String(), msg));
864 		if (convert_id == encoding)
865 			item->SetMarked(true);
866 	}
867 
868 	msg = new BMessage(P_ENC);
869 	msg->AddInt32("encoding", B_MAIL_US_ASCII_CONVERSION);
870 	menu->AddItem(item = new BMenuItem("US-ASCII", msg));
871 	if (encoding == B_MAIL_US_ASCII_CONVERSION)
872 		item->SetMarked(true);
873 
874 	return menu;
875 }
876 
877 
878 BPopUpMenu*
879 TPrefsWindow::_BuildWarnUnencodableMenu(bool warnUnencodable)
880 {
881 	return _BuildBoolMenu(P_WARN_UNENCODABLE, "warnUnencodable",
882 		warnUnencodable);
883 }
884 
885 
886 BPopUpMenu*
887 TPrefsWindow::_BuildSpellCheckStartOnMenu(bool spellCheckStartOn)
888 {
889 	return _BuildBoolMenu(P_SPELL_CHECK_START_ON, "spellCheckStartOn",
890 		spellCheckStartOn);
891 }
892 
893 
894 BPopUpMenu*
895 TPrefsWindow::_BuildAutoMarkReadMenu(bool autoMarkRead)
896 {
897 	return _BuildBoolMenu(P_MARK_READ, "autoMarkRead",
898 		autoMarkRead);
899 }
900 
901 
902 BPopUpMenu*
903 TPrefsWindow::_BuildButtonBarMenu(uint8 show)
904 {
905 	BMenuItem* item;
906 	BMessage* msg;
907 	BPopUpMenu* menu = new BPopUpMenu("");
908 
909 	msg = new BMessage(P_BUTTON_BAR);
910 	msg->AddInt8("bar", 1);
911 	menu->AddItem(item = new BMenuItem(
912 		B_TRANSLATE("Show icons & labels"), msg));
913 	if (show & 1)
914 		item->SetMarked(true);
915 
916 	msg = new BMessage(P_BUTTON_BAR);
917 	msg->AddInt8("bar", 2);
918 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Show icons only"), msg));
919 	if (show & 2)
920 		item->SetMarked(true);
921 
922 	msg = new BMessage(P_BUTTON_BAR);
923 	msg->AddInt8("bar", 0);
924 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Hide"), msg));
925 	if (!show)
926 		item->SetMarked(true);
927 
928 	return menu;
929 }
930 
931