xref: /haiku/src/preferences/mail/ConfigViews.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
1 /* ConfigViews - config views for the account, protocols, and filters
2 **
3 ** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
4 */
5 
6 
7 #include "ConfigViews.h"
8 #include "Account.h"
9 #include "CenterContainer.h"
10 
11 #include <TextControl.h>
12 #include <ListView.h>
13 #include <ScrollView.h>
14 #include <PopUpMenu.h>
15 #include <MenuField.h>
16 #include <MenuItem.h>
17 #include <Button.h>
18 #include <Bitmap.h>
19 #include <Looper.h>
20 #include <Path.h>
21 #include <Alert.h>
22 #include <Entry.h>
23 #include <FindDirectory.h>
24 #include <Directory.h>
25 
26 #include <string.h>
27 
28 #include <MailSettings.h>
29 
30 #include <MDRLanguage.h>
31 
32 // AccountConfigView
33 const uint32 kMsgAccountTypeChanged = 'atch';
34 const uint32 kMsgAccountNameChanged = 'anmc';
35 
36 // ProtocolsConfigView
37 const uint32 kMsgProtocolChanged = 'prch';
38 
39 // FiltersConfigView
40 const uint32 kMsgItemDragged = 'itdr';
41 const uint32 kMsgFilterMoved = 'flmv';
42 const uint32 kMsgChainSelected = 'chsl';
43 const uint32 kMsgAddFilter = 'addf';
44 const uint32 kMsgRemoveFilter = 'rmfi';
45 const uint32 kMsgFilterSelected = 'fsel';
46 
47 
48 AccountConfigView::AccountConfigView(BRect rect,Account *account)
49 	:	BBox(rect),
50 		fAccount(account)
51 {
52 	SetLabel(MDR_DIALECT_CHOICE ("Account Configuration","アカウント設定"));
53 
54 	rect = Bounds().InsetByCopy(8,8);
55 	rect.top += 10;
56 	CenterContainer *view = new CenterContainer(rect,false);
57 	view->SetSpacing(5);
58 
59 	// determine font height
60 	font_height fontHeight;
61 	view->GetFontHeight(&fontHeight);
62 	int32 height = (int32)(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 5;
63 
64 	rect = view->Bounds();
65 	rect.bottom = height + 5;
66 
67 	float labelWidth = view->StringWidth(MDR_DIALECT_CHOICE ("Account Name:","アカウント名:")) + 6;
68 
69 	view->AddChild(fNameControl = new BTextControl(rect,NULL,MDR_DIALECT_CHOICE ("Account Name:","アカウント名:"),NULL,new BMessage(kMsgAccountNameChanged)));
70 	fNameControl->SetDivider(labelWidth);
71 	view->AddChild(fRealNameControl = new BTextControl(rect,NULL,MDR_DIALECT_CHOICE ("Real Name:","名前    :"),NULL,NULL));
72 	fRealNameControl->SetDivider(labelWidth);
73 	view->AddChild(fReturnAddressControl = new BTextControl(rect,NULL,MDR_DIALECT_CHOICE ("Return Address:","返信アドレス:"),NULL,NULL));
74 	fReturnAddressControl->SetDivider(labelWidth);
75 //			control->TextView()->HideTyping(true);
76 
77 	BPopUpMenu *chainsPopUp = new BPopUpMenu(B_EMPTY_STRING);
78 	const char *chainModes[] = {
79 		MDR_DIALECT_CHOICE ("Inbound Only","受信のみ"),
80 		MDR_DIALECT_CHOICE ("Outbound Only","送信のみ"),
81 		MDR_DIALECT_CHOICE ("Inbound & Outbound","送受信")};
82 	BMenuItem *item;
83 	for (int32 i = 0;i < 3;i++)
84 		chainsPopUp->AddItem(item = new BMenuItem(chainModes[i],new BMessage(kMsgAccountTypeChanged)));
85 
86 	fTypeField = new BMenuField(rect,NULL,MDR_DIALECT_CHOICE ("Account Type:","用途    :"),chainsPopUp);
87 	fTypeField->SetDivider(labelWidth + 3);
88 	view->AddChild(fTypeField);
89 
90 	float w,h;
91 	view->GetPreferredSize(&w,&h);
92 	ResizeTo(w + 15,h + 22);
93 	view->ResizeTo(w,h);
94 
95 	AddChild(view);
96 }
97 
98 
99 void AccountConfigView::DetachedFromWindow()
100 {
101 	fAccount->SetName(fNameControl->Text());
102 	fAccount->SetRealName(fRealNameControl->Text());
103 	fAccount->SetReturnAddress(fReturnAddressControl->Text());
104 }
105 
106 
107 void AccountConfigView::AttachedToWindow()
108 {
109 	UpdateViews();
110 	fNameControl->SetTarget(this);
111 	fTypeField->Menu()->SetTargetForItems(this);
112 }
113 
114 
115 void AccountConfigView::MessageReceived(BMessage *msg)
116 {
117 	switch (msg->what)
118 	{
119 		case kMsgAccountTypeChanged:
120 		{
121 			int32 index;
122 			if (msg->FindInt32("index",&index) < B_OK)
123 				break;
124 
125 			if (fAccount->Type() < 0)
126 			{
127 				fNameControl->SetEnabled(true);
128 				fRealNameControl->SetEnabled(true);
129 				fReturnAddressControl->SetEnabled(true);
130 			}
131 			fAccount->SetType(index);
132 			UpdateViews();
133 			break;
134 		}
135 		case kMsgAccountNameChanged:
136 			fAccount->SetName(fNameControl->Text());
137 			break;
138 
139 		default:
140 			BView::MessageReceived(msg);
141 	}
142 }
143 
144 
145 void AccountConfigView::UpdateViews()
146 {
147 	if (!fAccount->Inbound() && !fAccount->Outbound())
148 	{
149 		if (BMenuItem *item = fTypeField->Menu()->FindMarked())
150 			item->SetMarked(false);
151 		fTypeField->Menu()->Superitem()->SetLabel(MDR_DIALECT_CHOICE ("<select account type>","<用途を選択してください>"));
152 
153 		fNameControl->SetEnabled(false);
154 		fRealNameControl->SetEnabled(false);
155 		fReturnAddressControl->SetEnabled(false);
156 		return;
157 	}
158 	fNameControl->SetText(fAccount->Name());
159 	fRealNameControl->SetText(fAccount->RealName());
160 	fReturnAddressControl->SetText(fAccount->ReturnAddress());
161 
162 	if (BMenuItem *item = fTypeField->Menu()->ItemAt(fAccount->Type()))
163 		item->SetMarked(true);
164 }
165 
166 
167 //---------------------------------------------------------------------------------------
168 //	#pragma mark -
169 
170 #include <stdio.h>
171 FilterConfigView::FilterConfigView(BMailChain *chain,int32 index,BMessage *msg,entry_ref *ref)
172 	:	BBox(BRect(0,0,100,100)),
173 		fConfigView(NULL),
174 		fChain(chain),
175 		fIndex(index),
176 		fMessage(msg),
177 		fEntryRef(ref)
178 {
179 	Load(msg,ref);
180 	BPath addon(ref);
181 	SetLabel(addon.Leaf());
182 }
183 
184 
185 FilterConfigView::~FilterConfigView()
186 {
187 	Remove();
188 }
189 
190 
191 void FilterConfigView::Load(BMessage *msg,entry_ref *ref)
192 {
193 	ResizeTo(264,30);
194 
195 	BView *(* instantiate_config)(BMessage *,BMessage *);
196 	BPath addon(ref);
197 	fImage = load_add_on(addon.Path());
198 	if (fImage < B_OK)
199 		return;
200 
201 	if (get_image_symbol(fImage,"instantiate_config_panel",B_SYMBOL_TYPE_TEXT,(void **)&instantiate_config) < B_OK)
202 	{
203 		unload_add_on(fImage);
204 		fImage = B_MISSING_SYMBOL;
205 		return;
206 	}
207 
208 	fConfigView = (*instantiate_config)(msg,fChain->MetaData());
209 
210 	float w = fConfigView->Bounds().Width();
211 	float h = fConfigView->Bounds().Height();
212 	fConfigView->MoveTo(3,13);
213 	ResizeTo(w + 6,h + 16);
214 	AddChild(fConfigView);
215 }
216 
217 
218 void FilterConfigView::Remove(bool deleteMessage)
219 {
220 	// remove config view here, because they may not be available
221 	// anymore, if the add-on is unloaded
222 	if (fConfigView && RemoveChild(fConfigView))
223 	{
224 		delete fConfigView;
225 		fConfigView = NULL;
226 	}
227 	unload_add_on(fImage);
228 
229 	if (deleteMessage)
230 	{
231 		delete fMessage;
232 		fMessage = NULL;
233 	}
234 	delete fEntryRef;
235 	fEntryRef = NULL;
236 }
237 
238 
239 status_t FilterConfigView::InitCheck()
240 {
241 	return fImage;
242 }
243 
244 
245 void FilterConfigView::DetachedFromWindow()
246 {
247 	if (fConfigView == NULL)
248 		return;
249 
250 	if (fConfigView->Archive(fMessage) >= B_OK)
251 		fChain->SetFilter(fIndex,*fMessage,*fEntryRef);
252 }
253 
254 
255 void FilterConfigView::AttachedToWindow()
256 {
257 }
258 
259 
260 //---------------------------------------------------------------------------------------
261 //	#pragma mark -
262 
263 
264 ProtocolsConfigView::ProtocolsConfigView(BMailChain *chain,int32 index,BMessage *msg,entry_ref *ref)
265 	:	FilterConfigView(chain,index,msg,ref)
266 {
267 	BPopUpMenu *menu = new BPopUpMenu("<choose protocol>");
268 
269 	for (int i = 0; i < 2; i++) {
270 		BPath path;
271 		status_t status = find_directory((i == 0) ? B_USER_ADDONS_DIRECTORY : B_BEOS_ADDONS_DIRECTORY,&path);
272 		if (status != B_OK)
273 		{
274 			fImage = status;
275 			return;
276 		}
277 
278 		path.Append("mail_daemon");
279 
280 		if (chain->ChainDirection() == inbound)
281 			path.Append("inbound_protocols");
282 		else
283 			path.Append("outbound_protocols");
284 
285 		BDirectory dir(path.Path());
286 		entry_ref protocolRef;
287 		while (dir.GetNextRef(&protocolRef) == B_OK)
288 		{
289 			char name[B_FILE_NAME_LENGTH];
290 			BEntry entry(&protocolRef);
291 			entry.GetName(name);
292 
293 			BMenuItem *item;
294 			BMessage *msg;
295 			menu->AddItem(item = new BMenuItem(name,msg = new BMessage(kMsgProtocolChanged)));
296 			msg->AddRef("protocol",&protocolRef);
297 
298 			if (*ref == protocolRef)
299 				item->SetMarked(true);
300 		}
301 	}
302 
303 	fProtocolsMenuField = new BMenuField(BRect(0,0,200,40),NULL,NULL,menu);
304 	fProtocolsMenuField->ResizeToPreferred();
305 	SetLabel(fProtocolsMenuField);
306 
307 	if (fConfigView)
308 	{
309 		fConfigView->MoveTo(3,21);
310 		ResizeBy(0,8);
311 	}
312 	else
313 		fImage = B_OK;
314 }
315 
316 
317 void ProtocolsConfigView::AttachedToWindow()
318 {
319 	FilterConfigView::AttachedToWindow();
320 	fProtocolsMenuField->Menu()->SetTargetForItems(this);
321 }
322 
323 
324 void ProtocolsConfigView::MessageReceived(BMessage *msg)
325 {
326 	switch (msg->what)
327 	{
328 		case kMsgProtocolChanged:
329 		{
330 			entry_ref ref;
331 			if (msg->FindRef("protocol",&ref) < B_OK)
332 				break;
333 
334 			DetachedFromWindow();
335 			Remove(false);
336 
337 			fEntryRef = new entry_ref(ref);
338 			Load(fMessage,fEntryRef);
339 			fChain->SetFilter(fIndex,*fMessage,*fEntryRef);
340 
341 			// resize view
342 			if (LockLooperWithTimeout(1000000L) == B_OK)
343 			{
344 				if (fConfigView)
345 				{
346 					fConfigView->MoveTo(3,21);
347 					ResizeBy(0,8);
348 				}
349 				UnlockLooper();
350 
351 				if (CenterContainer *container = dynamic_cast<CenterContainer *>(Parent()))
352 					container->Layout();
353 			}
354 			break;
355 		}
356 		default:
357 			BView::MessageReceived(msg);
358 			break;
359 	}
360 }
361 
362 
363 //---------------------------------------------------------------------------------------
364 //	#pragma mark -
365 
366 #include <stdio.h>
367 class DragListView : public BListView
368 {
369 	public:
370 		DragListView(BRect frame,const char *name,list_view_type type = B_SINGLE_SELECTION_LIST,
371 					 uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP,BMessage *itemMovedMsg = NULL)
372 			: BListView(frame,name,type,resizingMode),
373 			fDragging(false),
374 			fItemMovedMessage(itemMovedMsg)
375 		{
376 		}
377 
378 		virtual bool InitiateDrag(BPoint point,int32 index,bool wasSelected)
379 		{
380 			BRect frame(ItemFrame(index));
381 			BBitmap *bitmap = new BBitmap(frame.OffsetToCopy(B_ORIGIN),B_RGBA32,true);
382 			BView *view = new BView(bitmap->Bounds(),NULL,0,0);
383 			bitmap->AddChild(view);
384 
385 			if (view->LockLooper())
386 			{
387 				BListItem *item = ItemAt(index);
388 				bool selected = item->IsSelected();
389 
390 				view->SetLowColor(225,225,225,128);
391 				view->FillRect(view->Bounds());
392 
393 				if (selected)
394 					item->Deselect();
395 				ItemAt(index)->DrawItem(view,view->Bounds(),true);
396 				if (selected)
397 					item->Select();
398 
399 				view->UnlockLooper();
400 			}
401 			fLastDragTarget = -1;
402 			fDragIndex = index;
403 			fDragging = true;
404 
405 			BMessage drag(kMsgItemDragged);
406 			drag.AddInt32("index",index);
407 			DragMessage(&drag,bitmap,B_OP_ALPHA,point - frame.LeftTop(),this);
408 
409 			return true;
410 		}
411 
412 		void DrawDragTargetIndicator(int32 target)
413 		{
414 			PushState();
415 			SetDrawingMode(B_OP_INVERT);
416 
417 			bool last = false;
418 			if (target >= CountItems())
419 				target = CountItems() - 1, last = true;
420 
421 			BRect frame = ItemFrame(target);
422 			if (last)
423 				frame.OffsetBy(0,frame.Height());
424 			frame.bottom = frame.top + 1;
425 
426 			FillRect(frame);
427 
428 			PopState();
429 		}
430 
431 		virtual void MouseMoved(BPoint point,uint32 transit,const BMessage *msg)
432 		{
433 			BListView::MouseMoved(point,transit,msg);
434 
435 			if ((transit != B_ENTERED_VIEW && transit != B_INSIDE_VIEW) || !fDragging)
436 				return;
437 
438 			int32 target = IndexOf(point);
439 			if (target == -1)
440 				target = CountItems();
441 
442 			// correct the target insertion index
443 			if (target == fDragIndex || target == fDragIndex + 1)
444 				target = -1;
445 
446 			if (target == fLastDragTarget)
447 				return;
448 
449 			// remove old target indicator
450 			if (fLastDragTarget != -1)
451 				DrawDragTargetIndicator(fLastDragTarget);
452 
453 			// draw new one
454 			fLastDragTarget = target;
455 			if (target != -1)
456 				DrawDragTargetIndicator(target);
457 		}
458 
459 		virtual void MouseUp(BPoint point)
460 		{
461 			if (fDragging)
462 			{
463 				fDragging = false;
464 				if (fLastDragTarget != -1)
465 					DrawDragTargetIndicator(fLastDragTarget);
466 			}
467 			BListView::MouseUp(point);
468 		}
469 
470 		virtual void MessageReceived(BMessage *msg)
471 		{
472 			switch(msg->what)
473 			{
474 				case kMsgItemDragged:
475 				{
476 					int32 source = msg->FindInt32("index");
477 					BPoint point = msg->FindPoint("_drop_point_");
478 					ConvertFromScreen(&point);
479 					int32 to = IndexOf(point);
480 					if (to > fDragIndex)
481 						to--;
482 					if (to == -1)
483 						to = CountItems() - 1;
484 
485 					if (source != to)
486 					{
487 						MoveItem(source,to);
488 
489 						if (fItemMovedMessage != NULL)
490 						{
491 							BMessage msg(fItemMovedMessage->what);
492 							msg.AddInt32("from",source);
493 							msg.AddInt32("to",to);
494 							Messenger().SendMessage(&msg);
495 						}
496 					}
497 					break;
498 				}
499 			}
500 			BListView::MessageReceived(msg);
501 		}
502 
503 	private:
504 		bool		fDragging;
505 		int32		fLastDragTarget,fDragIndex;
506 		BMessage	*fItemMovedMessage;
507 };
508 
509 
510 void GetPrettyDescriptiveName(BPath &path, char *name, BMessage *msg = NULL)
511 {
512 	strcpy(name, path.Leaf());
513 
514 	image_id image = load_add_on(path.Path());
515 	if (image < B_OK)
516 		return;
517 
518 	if (msg)
519 	{
520 		status_t (* descriptive_name)(BMessage *,char *);
521 		if (get_image_symbol(image,"descriptive_name",B_SYMBOL_TYPE_TEXT,(void **)&descriptive_name) == B_OK)
522 			(*descriptive_name)(msg,name);
523 	}
524 	unload_add_on(image);
525 }
526 
527 
528 //	#pragma mark -
529 
530 
531 FiltersConfigView::FiltersConfigView(BRect rect,Account *account)
532 	:	BBox(rect),
533 		fAccount(account),
534 		fFilterView(NULL)
535 {
536 	BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING);
537 
538 	BMenuItem *item;
539 	BMessage *msg;
540 	if ((fChain = fAccount->Inbound()))
541 	{
542 		menu->AddItem(item = new BMenuItem(MDR_DIALECT_CHOICE ("Incoming E-mail Filters","受信フィルタ"),msg = new BMessage(kMsgChainSelected)));
543 		msg->AddPointer("chain",fChain);
544 		item->SetMarked(true);
545 	}
546 	if (BMailChain *chain = fAccount->Outbound())
547 	{
548 		menu->AddItem(item = new BMenuItem(MDR_DIALECT_CHOICE ("Outgoing E-mail Filters","送信フィルタ"),msg = new BMessage(kMsgChainSelected)));
549 		msg->AddPointer("chain",chain);
550 		if (fChain == NULL)
551 		{
552 			item->SetMarked(true);
553 			fChain = chain;
554 		}
555 	}
556 
557 	fChainsField = new BMenuField(BRect(0,0,200,40),NULL,NULL,menu);
558 	fChainsField->ResizeToPreferred();
559 	SetLabel(fChainsField);
560 
561 	// determine font height
562 	font_height fontHeight;
563 	fChainsField->GetFontHeight(&fontHeight);
564 	int32 height = (int32)(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 5;
565 
566 	rect = Bounds().InsetByCopy(10,10);
567 	rect.top += 18;
568 	rect.right -= B_V_SCROLL_BAR_WIDTH;
569 	rect.bottom = rect.top + 4 * height + 2;
570 	fListView = new DragListView(rect,NULL,B_SINGLE_SELECTION_LIST,B_FOLLOW_ALL,new BMessage(kMsgFilterMoved));
571 	AddChild(new BScrollView(NULL,fListView,B_FOLLOW_ALL,0,false,true));
572 	rect.right += B_V_SCROLL_BAR_WIDTH;
573 
574 //	fListView->Select(gSettings.formats.IndexOf(format));
575 	fListView->SetSelectionMessage(new BMessage(kMsgFilterSelected));
576 
577 	rect.top = rect.bottom + 8;  rect.bottom = rect.top + height;
578 	BRect sizeRect = rect;	sizeRect.right = sizeRect.left + 30 + fChainsField->StringWidth(MDR_DIALECT_CHOICE ("Add Filter","フィルタの追加"));
579 
580 	menu = new BPopUpMenu(MDR_DIALECT_CHOICE ("Add Filter","フィルタの追加"));
581 	menu->SetRadioMode(false);
582 
583 	fAddField = new BMenuField(rect,NULL,NULL,menu);
584 	fAddField->ResizeToPreferred();
585 	AddChild(fAddField);
586 
587 	sizeRect.left = sizeRect.right + 5;	sizeRect.right = sizeRect.left + 30 + fChainsField->StringWidth(MDR_DIALECT_CHOICE ("Remove","削除"));
588 	sizeRect.top--;
589 	AddChild(fRemoveButton = new BButton(sizeRect,NULL,MDR_DIALECT_CHOICE ("Remove","削除"),new BMessage(kMsgRemoveFilter),B_FOLLOW_BOTTOM));
590 
591 	ResizeTo(Bounds().Width(),sizeRect.bottom + 10);
592 	SetTo(fChain);
593 }
594 
595 
596 FiltersConfigView::~FiltersConfigView()
597 {
598 }
599 
600 
601 void FiltersConfigView::SelectFilter(int32 index)
602 {
603 	if (Parent())
604 		Parent()->Hide();
605 
606 	// remove old config view
607 	if (fFilterView)
608 	{
609 		Parent()->RemoveChild(fFilterView);
610 
611 		// update the name in the list
612 		BStringItem *item = (BStringItem *)fListView->ItemAt(fFilterView->fIndex - fFirst);
613 
614 		char name[B_FILE_NAME_LENGTH];
615 		BPath path(fFilterView->fEntryRef);
616 		GetPrettyDescriptiveName(path, name, fFilterView->fMessage);
617 		item->SetText(name);
618 
619 		delete fFilterView;
620 		fFilterView = NULL;
621 	}
622 
623 	if (index >= 0)
624 	{
625 		// add new config view
626 		BMessage *msg = new BMessage();
627 		entry_ref *ref = new entry_ref();
628 		if (fChain->GetFilter(index + fFirst,msg,ref) >= B_OK && Parent())
629 		{
630 			fFilterView = new FilterConfigView(fChain,index + fFirst,msg,ref);
631 			if (fFilterView->InitCheck() >= B_OK)
632 				Parent()->AddChild(fFilterView);
633 			else
634 			{
635 				delete fFilterView;
636 				fFilterView = NULL;
637 			}
638 		}
639 		else
640 		{
641 			delete msg;
642 			delete ref;
643 		}
644 	}
645 
646 	// re-layout the view containing the config view
647 	if (CenterContainer *container = dynamic_cast<CenterContainer *>(Parent()))
648 		container->Layout();
649 
650 	if (Parent())
651 		Parent()->Show();
652 }
653 
654 
655 void FiltersConfigView::SetTo(BMailChain *chain)
656 {
657 	// remove the filter config view
658 	SelectFilter(-1);
659 
660 	for (int32 i = fListView->CountItems();i-- > 0;)
661 	{
662 		BStringItem *item = (BStringItem *)fListView->RemoveItem(i);
663 		delete item;
664 	}
665 
666 	if (chain->ChainDirection() == inbound)
667 	{
668 		fFirst = 2;		// skip protocol (e.g. POP3), and Parser
669 		fLast = 2;		// skip Notifier, and Folder
670 	}
671 	else
672 	{
673 		fFirst = 1;		// skip Producer
674 		fLast = 1;		// skip protocol (e.g. SMTP)
675 	}
676 	int32 last = chain->CountFilters() - fLast;
677 	for (int32 i = fFirst;i < last;i++)
678 	{
679 		BMessage msg;
680 		entry_ref ref;
681 		if (chain->GetFilter(i,&msg,&ref) == B_OK)
682 		{
683 			char name[B_FILE_NAME_LENGTH];
684 			BPath addon(&ref);
685 			GetPrettyDescriptiveName(addon, name, &msg);
686 
687 			fListView->AddItem(new BStringItem(name));
688 		}
689 	}
690 	fChain = chain;
691 
692 	/*** search inbound/outbound filters ***/
693 
694 	// remove old filter items
695 	BMenu *menu = fAddField->Menu();
696 	for (int32 i = menu->CountItems();i-- > 0;)
697 	{
698 		BMenuItem *item = menu->RemoveItem(i);
699 		delete item;
700 	}
701 
702 	for (int i = 0; i < 2; i++) {
703 		BPath path;
704 		status_t status = find_directory((i == 0) ? B_USER_ADDONS_DIRECTORY : B_BEOS_ADDONS_DIRECTORY,&path);
705 		if (status != B_OK)
706 			return;
707 
708 		path.Append("mail_daemon");
709 
710 		if (fChain->ChainDirection() == inbound)
711 			path.Append("inbound_filters");
712 		else
713 			path.Append("outbound_filters");
714 
715 		BDirectory dir(path.Path());
716 		entry_ref ref;
717 		while (dir.GetNextRef(&ref) == B_OK)
718 		{
719 			char name[B_FILE_NAME_LENGTH];
720 			BPath path(&ref);
721 			GetPrettyDescriptiveName(path, name);
722 
723 			BMenuItem *item;
724 			BMessage *msg;
725 			menu->AddItem(item = new BMenuItem(name,msg = new BMessage(kMsgAddFilter)));
726 			msg->AddRef("filter",&ref);
727 		}
728 	}
729 	menu->SetTargetForItems(this);
730 }
731 
732 
733 void FiltersConfigView::AttachedToWindow()
734 {
735 	fChainsField->Menu()->SetTargetForItems(this);
736 	fListView->SetTarget(this);
737 	fAddField->Menu()->SetTargetForItems(this);
738 	fRemoveButton->SetTarget(this);
739 }
740 
741 
742 void FiltersConfigView::MessageReceived(BMessage *msg)
743 {
744 	switch (msg->what)
745 	{
746 		case kMsgChainSelected:
747 		{
748 			BMailChain *chain;
749 			if (msg->FindPointer("chain",(void **)&chain) < B_OK)
750 				break;
751 
752 			SetTo(chain);
753 			break;
754 		}
755 		case kMsgAddFilter:
756 		{
757 			entry_ref ref;
758 			if (msg->FindRef("filter",&ref) < B_OK)
759 				break;
760 
761 			BMessage msg;
762 			if (fChain->AddFilter(fChain->CountFilters() - fLast, msg, ref) >= B_OK)
763 			{
764 				char name[B_FILE_NAME_LENGTH];
765 				BPath path(&ref);
766 				GetPrettyDescriptiveName(path, name, &msg);
767 				fListView->AddItem(new BStringItem(name));
768 			}
769 			break;
770 		}
771 		case kMsgRemoveFilter:
772 		{
773 			int32 index = fListView->CurrentSelection();
774 			if (index < 0)
775 				break;
776 
777 			SelectFilter(-1);
778 			if (BStringItem *item = (BStringItem *)fListView->RemoveItem(index))
779 			{
780 				fChain->RemoveFilter(index + fFirst);
781 				delete item;
782 			}
783 			break;
784 		}
785 		case kMsgFilterSelected:
786 		{
787 			int32 index;
788 			if (msg->FindInt32("index",&index) < B_OK)
789 				break;
790 
791 			SelectFilter(index);
792 			break;
793 		}
794 		case kMsgFilterMoved:
795 		{
796 			int32 from = msg->FindInt32("from");
797 			int32 to = msg->FindInt32("to");
798 			if (from == to)
799 				break;
800 
801 			from += fFirst;
802 			to += fFirst;
803 
804 			entry_ref ref;
805 			BMessage settings;
806 			if (fChain->GetFilter(from,&settings,&ref) == B_OK)
807 			{
808 				// disable filter view saving
809 				if (fFilterView && fFilterView->fIndex == from)
810 					fFilterView->fIndex = -1;
811 
812 				fChain->RemoveFilter(from);
813 
814 				if (fChain->AddFilter(to,settings,ref) < B_OK)
815 				{
816 					(new BAlert("E-mail",MDR_DIALECT_CHOICE (
817 					"Could not move filter, filter deleted.",
818 					"フィルタが削除された為、移動できません"),"Ok"))->Go();
819 
820 					// the filter view belongs to the moved filter
821 					if (fFilterView && fFilterView->fIndex == -1)
822 						SelectFilter(-1);
823 
824 					fListView->RemoveItem(msg->FindInt32("to"));
825 				}
826 				else if (fFilterView)
827 				{
828 					int32 index = fFilterView->fIndex;
829 					if (index == -1)
830 						// the view belongs to the moved filter
831 						fFilterView->fIndex = to;
832 					else if (index > from && index < to)
833 						// the view belongs to another filter (between the
834 						// 'from' & 'to' positions) - all others can keep
835 						// their index value
836 						fFilterView->fIndex--;
837 				}
838 			}
839 			break;
840 		}
841 		default:
842 			BView::MessageReceived(msg);
843 			break;
844 	}
845 }
846 
847