xref: /haiku/src/apps/mail/Prefs.cpp (revision 1294543de9ac0eff000eaea1b18368c36435d08e)
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, uint32* 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(*fNewAutoMarkRead)
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 ? "On" : "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 ? "On" : "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 ? "On" : "Off");
424 				if ((item = fWarnUnencodableMenu->FindItem(label)) != NULL)
425 					item->SetMarked(true);
426 
427 				strcpy(label, fSpellCheckStartOn ? "On" : "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 			// To do: insert at selection point rather than at the end.
488 			text->Insert(text->TextLength(), item->Label(), 2);
489 		}
490 		case P_SIG:
491 			free(*fNewSignature);
492 			if (msg->FindString("signature", &signature) == B_NO_ERROR) {
493 				*fNewSignature = (char*)malloc(strlen(signature) + 1);
494 				strcpy(*fNewSignature, signature);
495 			} else {
496 				*fNewSignature = (char*)malloc(
497 					strlen(B_TRANSLATE("None")) + 1);
498 				strcpy(*fNewSignature, B_TRANSLATE("None"));
499 			}
500 			break;
501 		case P_ENC:
502 			msg->FindInt32("encoding", (int32*)fNewEncoding);
503 			break;
504 		case P_WARN_UNENCODABLE:
505 			msg->FindBool("warnUnencodable", fNewWarnUnencodable);
506 			break;
507 		case P_SPELL_CHECK_START_ON:
508 			msg->FindBool("spellCheckStartOn", fNewSpellCheckStartOn);
509 			break;
510 		case P_MARK_READ:
511 			msg->FindBool("autoMarkRead", fNewAutoMarkRead);
512 			be_app->PostMessage(PREFS_CHANGED);
513 			break;
514 		case P_BUTTON_BAR:
515 			msg->FindInt8("bar", (int8*)fNewButtonBar);
516 			be_app->PostMessage(PREFS_CHANGED);
517 			break;
518 
519 		default:
520 			BWindow::MessageReceived(msg);
521 	}
522 
523 	fFont.GetFamilyAndStyle(&old_family, &old_style);
524 	fNewFont->GetFamilyAndStyle(&new_family, &new_style);
525 	old_size = (int32) fFont.Size();
526 	new_size = (int32) fNewFont->Size();
527 	bool changed = old_size != new_size
528 		|| fWrap != *fNewWrap
529 		|| fAttachAttributes != *fNewAttachAttributes
530 		|| fColoredQuotes != *fNewColoredQuotes
531 		|| fAccount != *fNewAccount
532 		|| fReplyTo != *fNewReplyTo
533 		|| strcmp(old_family, new_family)
534 		|| strcmp(old_style, new_style)
535 		|| strcmp(fReplyPreamble->Text(), *fNewPreamble)
536 		|| strcmp(fSignature, *fNewSignature)
537 		|| fEncoding != *fNewEncoding
538 		|| fWarnUnencodable != *fNewWarnUnencodable
539 		|| fSpellCheckStartOn != *fNewSpellCheckStartOn
540 		|| fAutoMarkRead != *fNewAutoMarkRead
541 		|| fButtonBar != *fNewButtonBar;
542 	fRevert->SetEnabled(changed);
543 }
544 
545 
546 BPopUpMenu*
547 TPrefsWindow::_BuildFontMenu(BFont* font)
548 {
549 	font_family	def_family;
550 	font_style	def_style;
551 	font_family	f_family;
552 	font_style	f_style;
553 
554 	BPopUpMenu *menu = new BPopUpMenu("");
555 	font->GetFamilyAndStyle(&def_family, &def_style);
556 
557 	int32 family_menu_index = 0;
558 	int family_count = count_font_families();
559 	for (int family_loop = 0; family_loop < family_count; family_loop++) {
560 		get_font_family(family_loop, &f_family);
561 		BMenu *family_menu = new BMenu(f_family);
562 
563 		int style_count = count_font_styles(f_family);
564 		for (int style_loop = 0; style_loop < style_count; style_loop++) {
565 			get_font_style(f_family, style_loop, &f_style);
566 
567 			BMessage *msg = new BMessage(P_FONT);
568 			msg->AddString("font", f_family);
569 			msg->AddString("style", f_style);
570 			// we send this to make setting the Family easier when things
571 			// change
572 			msg->AddInt32("parent_index", family_menu_index);
573 
574 			BMenuItem *item = new BMenuItem(f_style, msg);
575 			family_menu->AddItem(item);
576 			if ((strcmp(def_family, f_family) == 0)
577 				&& (strcmp(def_style, f_style) == 0)) {
578 				item->SetMarked(true);
579 			}
580 
581 			item->SetTarget(this);
582 		}
583 
584 		menu->AddItem(family_menu);
585 		BMenuItem *item = menu->ItemAt(family_menu_index);
586 		BMessage *msg = new BMessage(P_FONT);
587 		msg->AddString("font", f_family);
588 
589 		item->SetMessage(msg);
590 		item->SetTarget(this);
591 		if (strcmp(def_family, f_family) == 0)
592 			item->SetMarked(true);
593 
594 		family_menu_index++;
595 	}
596 	return menu;
597 }
598 
599 
600 BPopUpMenu*
601 TPrefsWindow::_BuildLevelMenu(int32 level)
602 {
603 	BMenuItem* item;
604 	BMessage* msg;
605 	BPopUpMenu* menu;
606 
607 	menu = new BPopUpMenu("");
608 	msg = new BMessage(P_LEVEL);
609 	msg->AddInt32("level", L_BEGINNER);
610 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Beginner"), msg));
611 	if (level == L_BEGINNER)
612 		item->SetMarked(true);
613 
614 	msg = new BMessage(P_LEVEL);
615 	msg->AddInt32("level", L_EXPERT);
616 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Expert"), msg));
617 	if (level == L_EXPERT)
618 		item->SetMarked(true);
619 
620 	return menu;
621 }
622 
623 
624 BPopUpMenu*
625 TPrefsWindow::_BuildAccountMenu(uint32 account)
626 {
627 	BPopUpMenu* menu = new BPopUpMenu("");
628 	BMenuItem* item;
629 
630 	//menu->SetRadioMode(true);
631 	BList chains;
632 	if (GetOutboundMailChains(&chains) < B_OK) {
633 		menu->AddItem(item = new BMenuItem("<no account found>", NULL));
634 		item->SetEnabled(false);
635 		return menu;
636 	}
637 
638 	BMessage* msg;
639 	for (int32 i = 0; i < chains.CountItems(); i++) {
640 		BMailChain* chain = (BMailChain*)chains.ItemAt(i);
641 		item = new BMenuItem(chain->Name(), msg = new BMessage(P_ACCOUNT));
642 
643 		msg->AddInt32("id",chain->ID());
644 
645 		if (account == chain->ID())
646 			item->SetMarked(true);
647 
648 		menu->AddItem(item);
649 		delete chain;
650 	}
651 	return menu;
652 }
653 
654 
655 BPopUpMenu*
656 TPrefsWindow::_BuildReplyToMenu(int32 account)
657 {
658 	BPopUpMenu* menu = new BPopUpMenu(B_EMPTY_STRING);
659 
660 	BMenuItem* item;
661 	BMessage* msg;
662 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Use default account"),
663 		msg = new BMessage(P_REPLYTO)));
664 	msg->AddInt32("replyTo", ACCOUNT_USE_DEFAULT);
665 	if (account == ACCOUNT_USE_DEFAULT)
666 		item->SetMarked(true);
667 
668 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Account from mail"),
669 		msg = new BMessage(P_REPLYTO)));
670 	msg->AddInt32("replyTo", ACCOUNT_FROM_MAIL);
671 	if (account == ACCOUNT_FROM_MAIL)
672 		item->SetMarked(true);
673 
674 	return menu;
675 }
676 
677 
678 BMenu*
679 TPrefsWindow::_BuildReplyPreambleMenu()
680 {
681 	const char *substitutes[] = {
682 /* To do: Not yet working, leave out for 2.0.0 beta 4:
683 		"%f - First name",
684 		"%l - Last name",
685 */
686 		B_TRANSLATE("%n - Full name"),
687 		B_TRANSLATE("%e - E-mail address"),
688 		B_TRANSLATE("%d - Date"),
689 		"",
690 		B_TRANSLATE("\\n - Newline"),
691 		NULL
692 	};
693 
694 	BMenu *menu = new BMenu(B_EMPTY_STRING);
695 
696 	for (int32 i = 0; substitutes[i]; i++) {
697 		if (*substitutes[i] == '\0') {
698 			menu->AddSeparatorItem();
699 		} else {
700 			menu->AddItem(new BMenuItem(substitutes[i],
701 				new BMessage(P_REPLY_PREAMBLE)));
702 		}
703 	}
704 
705 	return menu;
706 }
707 
708 
709 BPopUpMenu*
710 TPrefsWindow::_BuildSignatureMenu(char* sig)
711 {
712 	char name[B_FILE_NAME_LENGTH];
713 	BEntry entry;
714 	BFile file;
715 	BMenuItem* item;
716 	BMessage* msg;
717 	BQuery query;
718 	BVolume vol;
719 	BVolumeRoster volume;
720 
721 	BPopUpMenu* menu = new BPopUpMenu("");
722 
723 	msg = new BMessage(P_SIG);
724 	msg->AddString("signature", B_TRANSLATE("None"));
725 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("None"), msg));
726 	if (!strcmp(sig, B_TRANSLATE("None")))
727 		item->SetMarked(true);
728 
729 	msg = new BMessage(P_SIG);
730 	msg->AddString("signature", B_TRANSLATE("Random"));
731 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Random"), msg));
732 	if (!strcmp(sig, B_TRANSLATE("Random")))
733 		item->SetMarked(true);
734 	menu->AddSeparatorItem();
735 
736 	volume.GetBootVolume(&vol);
737 	query.SetVolume(&vol);
738 	query.SetPredicate("_signature = *");
739 	query.Fetch();
740 
741 	while (query.GetNextEntry(&entry) == B_NO_ERROR) {
742 		file.SetTo(&entry, O_RDONLY);
743 		if (file.InitCheck() == B_NO_ERROR) {
744 			msg = new BMessage(P_SIG);
745 			file.ReadAttr("_signature", B_STRING_TYPE, 0, name, sizeof(name));
746 			msg->AddString("signature", name);
747 			menu->AddItem(item = new BMenuItem(name, msg));
748 			if (!strcmp(sig, name))
749 				item->SetMarked(true);
750 		}
751 	}
752 	return menu;
753 }
754 
755 
756 BPopUpMenu*
757 TPrefsWindow::_BuildSizeMenu(BFont* font)
758 {
759 	char label[16];
760 	uint32 loop;
761 	int32 sizes[] = {9, 10, 11, 12, 14, 18, 24};
762 	float size;
763 	BMenuItem* item;
764 	BMessage* msg;
765 	BPopUpMenu* menu;
766 
767 	menu = new BPopUpMenu("");
768 	size = font->Size();
769 	for (loop = 0; loop < sizeof(sizes) / sizeof(int32); loop++) {
770 		msg = new BMessage(P_SIZE);
771 		msg->AddInt32("size", sizes[loop]);
772 		sprintf(label, "%ld", sizes[loop]);
773 		menu->AddItem(item = new BMenuItem(label, msg));
774 		if (sizes[loop] == (int32)size)
775 			item->SetMarked(true);
776 	}
777 	return menu;
778 }
779 
780 
781 BPopUpMenu*
782 TPrefsWindow::_BuildBoolMenu(uint32 what, const char* boolItem, bool isTrue)
783 {
784 	BMenuItem* item;
785 	BMessage* msg;
786 	BPopUpMenu* menu;
787 
788 	menu = new BPopUpMenu("");
789 	msg = new BMessage(what);
790 	msg->AddBool(boolItem, true);
791 	menu->AddItem(item = new BMenuItem("On", msg));
792 	if (isTrue)
793 		item->SetMarked(true);
794 
795 	msg = new BMessage(what);
796 	msg->AddInt32(boolItem, false);
797 	menu->AddItem(item = new BMenuItem("Off", msg));
798 	if (!isTrue)
799 		item->SetMarked(true);
800 
801 	return menu;
802 }
803 
804 
805 BPopUpMenu*
806 TPrefsWindow::_BuildWrapMenu(bool wrap)
807 {
808 	return _BuildBoolMenu(P_WRAP, "wrap", wrap);
809 }
810 
811 
812 BPopUpMenu*
813 TPrefsWindow::_BuildAttachAttributesMenu(bool attachAttributes)
814 {
815 	BMenuItem* item;
816 	BMessage* msg;
817 	BPopUpMenu* menu;
818 
819 	menu = new BPopUpMenu("");
820 	msg = new BMessage(P_ATTACH_ATTRIBUTES);
821 	msg->AddBool("attachAttributes", true);
822 	menu->AddItem(item = new BMenuItem(
823 		B_TRANSLATE("Include file attributes in attachments"), msg));
824 	if (attachAttributes)
825 		item->SetMarked(true);
826 
827 	msg = new BMessage(P_ATTACH_ATTRIBUTES);
828 	msg->AddInt32("attachAttributes", false);
829 	menu->AddItem(item = new BMenuItem(
830 		B_TRANSLATE("No file attributes, just plain data"), msg));
831 	if (!attachAttributes)
832 		item->SetMarked(true);
833 
834 	return menu;
835 }
836 
837 
838 BPopUpMenu*
839 TPrefsWindow::_BuildColoredQuotesMenu(bool quote)
840 {
841 	return _BuildBoolMenu(P_COLORED_QUOTES, "cquotes", quote);
842 }
843 
844 
845 BPopUpMenu*
846 TPrefsWindow::_BuildEncodingMenu(uint32 encoding)
847 {
848 	BMenuItem* item;
849 	BMessage* msg;
850 	BPopUpMenu* menu;
851 
852 	menu = new BPopUpMenu("");
853 
854 	BCharacterSetRoster roster;
855 	BCharacterSet charset;
856 	while (roster.GetNextCharacterSet(&charset) == B_NO_ERROR) {
857 		BString name(charset.GetPrintName());
858 		const char* mime = charset.GetMIMEName();
859 		if (mime)
860 			name << " (" << mime << ")";
861 		msg = new BMessage(P_ENC);
862 		uint32 convert_id;
863 		if ((mime == 0) || (strcasecmp(mime, "UTF-8") != 0))
864 			convert_id = charset.GetConversionID();
865 		else
866 			convert_id = B_MAIL_UTF8_CONVERSION;
867 		msg->AddInt32("encoding", convert_id);
868 		menu->AddItem(item = new BMenuItem(name.String(), msg));
869 		if (convert_id == encoding)
870 			item->SetMarked(true);
871 	}
872 
873 	msg = new BMessage(P_ENC);
874 	msg->AddInt32("encoding", B_MAIL_US_ASCII_CONVERSION);
875 	menu->AddItem(item = new BMenuItem("US-ASCII", msg));
876 	if (encoding == B_MAIL_US_ASCII_CONVERSION)
877 		item->SetMarked(true);
878 
879 	return menu;
880 }
881 
882 
883 BPopUpMenu*
884 TPrefsWindow::_BuildWarnUnencodableMenu(bool warnUnencodable)
885 {
886 	return _BuildBoolMenu(P_WARN_UNENCODABLE, "warnUnencodable",
887 		warnUnencodable);
888 }
889 
890 
891 BPopUpMenu*
892 TPrefsWindow::_BuildSpellCheckStartOnMenu(bool spellCheckStartOn)
893 {
894 	return _BuildBoolMenu(P_SPELL_CHECK_START_ON, "spellCheckStartOn",
895 		spellCheckStartOn);
896 }
897 
898 
899 BPopUpMenu*
900 TPrefsWindow::_BuildAutoMarkReadMenu(bool autoMarkRead)
901 {
902 	return _BuildBoolMenu(P_MARK_READ, "autoMarkRead",
903 		autoMarkRead);
904 }
905 
906 
907 BPopUpMenu*
908 TPrefsWindow::_BuildButtonBarMenu(uint8 show)
909 {
910 	BMenuItem* item;
911 	BMessage* msg;
912 	BPopUpMenu* menu = new BPopUpMenu("");
913 
914 	msg = new BMessage(P_BUTTON_BAR);
915 	msg->AddInt8("bar", 1);
916 	menu->AddItem(item = new BMenuItem(
917 		B_TRANSLATE("Show icons & labels"), msg));
918 	if (show & 1)
919 		item->SetMarked(true);
920 
921 	msg = new BMessage(P_BUTTON_BAR);
922 	msg->AddInt8("bar", 2);
923 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Show icons only"), msg));
924 	if (show & 2)
925 		item->SetMarked(true);
926 
927 	msg = new BMessage(P_BUTTON_BAR);
928 	msg->AddInt8("bar", 0);
929 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Hide"), msg));
930 	if (!show)
931 		item->SetMarked(true);
932 
933 	return menu;
934 }
935 
936