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