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