xref: /haiku/src/apps/mail/Prefs.cpp (revision e0ef64750f3169cd634bb2f7a001e22488b05231)
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