2 * Copyright 2007-2015 Haiku, Inc. All rights reserved.
3 * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
5 * Distributed under the terms of the MIT License.
9 //! Main E-Mail config window
12 #include "ConfigWindow.h"
19 #include <AppFileInfo.h>
20 #include <Application.h>
26 #include <ControlLook.h>
27 #include <Directory.h>
29 #include <FindDirectory.h>
30 #include <LayoutBuilder.h>
33 #include <MailDaemon.h>
34 #include <MailSettings.h>
36 #include <MenuField.h>
39 #include <PopUpMenu.h>
41 #include <Resources.h>
44 #include <ScrollView.h>
45 #include <StringView.h>
47 #include <TextControl.h>
50 #include <MailPrivate.h>
52 #include "AutoConfigWindow.h"
55 #undef B_TRANSLATION_CONTEXT
56 #define B_TRANSLATION_CONTEXT "Config Window"
61 // define if you want to have an apply button
62 //#define HAVE_APPLY_BUTTON
65 const uint32 kMsgAccountsRightClicked
= 'arcl';
66 const uint32 kMsgAccountSelected
= 'acsl';
67 const uint32 kMsgAddAccount
= 'adac';
68 const uint32 kMsgRemoveAccount
= 'rmac';
70 const uint32 kMsgIntervalUnitChanged
= 'iuch';
72 const uint32 kMsgShowStatusWindowChanged
= 'shst';
73 const uint32 kMsgStatusLookChanged
= 'lkch';
74 const uint32 kMsgStatusWorkspaceChanged
= 'wsch';
76 const uint32 kMsgSaveSettings
= 'svst';
77 const uint32 kMsgRevertSettings
= 'rvst';
78 const uint32 kMsgCancelSettings
= 'cnst';
82 AccountItem::AccountItem(const char* label
, BMailAccountSettings
* account
,
93 AccountItem::Update(BView
* owner
, const BFont
* font
)
95 if (fType
== ACCOUNT_ITEM
)
98 BStringItem::Update(owner
, font
);
103 AccountItem::DrawItem(BView
* owner
, BRect rect
, bool complete
)
106 if (fType
== ACCOUNT_ITEM
)
107 owner
->SetFont(be_bold_font
);
109 BStringItem::DrawItem(owner
, rect
, complete
);
117 class AccountsListView
: public BListView
{
119 AccountsListView(BHandler
* target
)
121 BListView(NULL
, B_SINGLE_SELECTION_LIST
),
127 KeyDown(const char *bytes
, int32 numBytes
)
132 if ((*bytes
== B_DELETE
) || (*bytes
== B_BACKSPACE
))
133 Window()->PostMessage(kMsgRemoveAccount
);
135 BListView::KeyDown(bytes
,numBytes
);
139 MouseDown(BPoint point
)
141 BListView::MouseDown(point
);
145 GetMouse(&dummy
, &buttons
);
146 if (buttons
!= B_SECONDARY_MOUSE_BUTTON
)
149 int32 index
= IndexOf(point
);
153 BMessage
message(kMsgAccountsRightClicked
);
154 ConvertToScreen(&point
);
155 message
.AddPoint("point", point
);
156 message
.AddInt32("index", index
);
157 BMessenger
messenger(fTarget
);
158 messenger
.SendMessage(&message
);
166 class BitmapView
: public BView
{
168 BitmapView(BBitmap
*bitmap
)
170 BView(NULL
, B_WILL_DRAW
)
174 SetDrawingMode(B_OP_ALPHA
);
175 SetBlendingMode(B_PIXEL_ALPHA
, B_ALPHA_OVERLAY
);
176 SetExplicitSize(bitmap
->Bounds().Size());
184 virtual void AttachedToWindow()
186 SetViewColor(Parent()->ViewColor());
189 virtual void Draw(BRect updateRect
)
191 DrawBitmap(fBitmap
, updateRect
, updateRect
);
202 ConfigWindow::ConfigWindow()
204 BWindow(BRect(100, 100, 600, 540), B_TRANSLATE_SYSTEM_NAME("E-mail"),
206 B_ASYNCHRONOUS_CONTROLS
| B_NOT_ZOOMABLE
| B_AUTO_UPDATE_SIZE_LIMITS
),
207 fLastSelectedAccount(NULL
),
210 BTabView
* tabView
= new BTabView("tab");
214 BView
* view
= new BView("accounts", 0);
215 tabView
->AddTab(view
);
216 tabView
->TabAt(0)->SetLabel(B_TRANSLATE("Accounts"));
218 fAccountsListView
= new AccountsListView(this);
220 BButton
* addButton
= new BButton(NULL
, B_TRANSLATE("Add"),
221 new BMessage(kMsgAddAccount
));
222 fRemoveButton
= new BButton(NULL
, B_TRANSLATE("Remove"),
223 new BMessage(kMsgRemoveAccount
));
225 fConfigView
= new BView(NULL
, 0);
226 fConfigView
->SetLayout(new BGroupLayout(B_VERTICAL
));
227 fConfigView
->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED
, B_SIZE_UNLIMITED
));
228 fConfigView
->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR
));
230 BScrollView
* scroller
= new BScrollView(NULL
, fAccountsListView
, 0,
233 BLayoutBuilder::Group
<>(view
, B_HORIZONTAL
)
234 .SetInsets(B_USE_DEFAULT_SPACING
)
235 .AddGroup(B_VERTICAL
)
237 .AddGroup(B_HORIZONTAL
)
242 .Add(fConfigView
, 2.0f
);
244 _ReplaceConfigView(_BuildHowToView());
248 view
= new BView("general", 0);
249 view
->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED
, B_SIZE_UNLIMITED
));
250 tabView
->AddTab(view
);
251 tabView
->TabAt(1)->SetLabel(B_TRANSLATE("Settings"));
253 fCheckMailCheckBox
= new BCheckBox("check", B_TRANSLATE("Check every"),
255 fIntervalControl
= new BTextControl("time", B_TRANSLATE("minutes"), NULL
,
258 BPopUpMenu
* statusPopUp
= new BPopUpMenu(B_EMPTY_STRING
);
259 const char* statusModes
[] = {
260 B_TRANSLATE_COMMENT("Never", "show status window"),
261 B_TRANSLATE("While sending"),
262 B_TRANSLATE("While sending and receiving")};
263 for (size_t i
= 0; i
< sizeof(statusModes
) / sizeof(statusModes
[0]); i
++) {
264 BMessage
* msg
= new BMessage(kMsgShowStatusWindowChanged
);
265 BMenuItem
* item
= new BMenuItem(statusModes
[i
], msg
);
266 statusPopUp
->AddItem(item
);
267 msg
->AddInt32("ShowStatusWindow", i
);
270 fStatusModeField
= new BMenuField("show status",
271 B_TRANSLATE("Show notifications:"), statusPopUp
);
273 BMessage
* msg
= new BMessage(B_REFS_RECEIVED
);
274 BButton
* editMenuButton
= new BButton(B_EMPTY_STRING
,
275 B_TRANSLATE("Edit mailbox menu…"), msg
);
276 editMenuButton
->SetTarget(BMessenger("application/x-vnd.Be-TRAK"));
279 find_directory(B_USER_SETTINGS_DIRECTORY
, &path
);
280 path
.Append("Mail/Menu Links");
281 BEntry
entry(path
.Path());
282 if (entry
.InitCheck() == B_OK
&& entry
.Exists()) {
285 msg
->AddRef("refs", &ref
);
287 editMenuButton
->SetEnabled(false);
289 BLayoutBuilder::Group
<>(view
, B_VERTICAL
)
290 .SetInsets(B_USE_DEFAULT_SPACING
)
292 .AddGroup(B_HORIZONTAL
, 0.f
)
294 .Add(fCheckMailCheckBox
)
295 .Add(fIntervalControl
->CreateTextViewLayoutItem())
296 .AddStrut(be_control_look
->DefaultLabelSpacing())
297 .Add(fIntervalControl
->CreateLabelLayoutItem())
300 .AddGroup(B_HORIZONTAL
, 0.f
)
302 .Add(fStatusModeField
->CreateLabelLayoutItem())
303 .Add(fStatusModeField
->CreateMenuBarLayoutItem())
309 // save/revert buttons
311 BButton
* applyButton
= new BButton("apply", B_TRANSLATE("Apply"),
312 new BMessage(kMsgSaveSettings
));
313 BButton
* revertButton
= new BButton("revert", B_TRANSLATE("Revert"),
314 new BMessage(kMsgRevertSettings
));
316 BLayoutBuilder::Group
<>(this, B_VERTICAL
)
317 .SetInsets(B_USE_DEFAULT_SPACING
)
319 .AddGroup(B_HORIZONTAL
)
325 // this will also move our window to the stored position
327 fAccountsListView
->SetSelectionMessage(new BMessage(kMsgAccountSelected
));
328 fAccountsListView
->MakeFocus(true);
332 ConfigWindow::~ConfigWindow()
334 while (fAccounts
.CountItems() > 0)
335 _RemoveAccount(fAccounts
.ItemAt(0));
336 for (int32 i
= 0; i
< fToDeleteAccounts
.CountItems(); i
++)
337 delete fToDeleteAccounts
.ItemAt(i
);
342 ConfigWindow::_BuildHowToView()
344 BView
* groupView
= new BView("howTo", 0);
346 BitmapView
* bitmapView
= NULL
;
348 if (be_app
->GetAppInfo(&info
) == B_OK
) {
349 BFile
appFile(&info
.ref
, B_READ_ONLY
);
350 BAppFileInfo
appFileInfo(&appFile
);
351 if (appFileInfo
.InitCheck() == B_OK
) {
352 BBitmap
* bitmap
= new (std::nothrow
) BBitmap(BRect(0, 0, 63, 63),
354 if (appFileInfo
.GetIcon(bitmap
, B_LARGE_ICON
) == B_OK
)
355 bitmapView
= new BitmapView(bitmap
);
361 BTextView
* text
= new BTextView(NULL
, B_WILL_DRAW
);
362 text
->SetAlignment(B_ALIGN_CENTER
);
363 text
->SetText(B_TRANSLATE(
364 "Create a new account with the Add button.\n\n"
365 "Remove an account with the Remove button on the selected item.\n\n"
366 "Select an item in the list to change its settings."));
367 text
->MakeEditable(false);
368 text
->MakeSelectable(false);
370 BLayoutBuilder::Group
<>(groupView
, B_VERTICAL
)
375 if (bitmapView
!= NULL
)
376 groupView
->GetLayout()->AddView(1, bitmapView
);
378 text
->SetViewColor(groupView
->ViewColor());
385 ConfigWindow::_LoadSettings()
388 for (int i
= 0; i
< fAccounts
.CountItems(); i
++)
389 delete fAccounts
.ItemAt(i
);
390 fAccounts
.MakeEmpty();
394 // load in general settings
395 BMailSettings settings
;
396 status_t status
= _SetToGeneralSettings(&settings
);
397 if (status
!= B_OK
) {
398 fprintf(stderr
, B_TRANSLATE("Error retrieving general settings: %s\n"),
407 ConfigWindow::_LoadAccounts()
409 BMailAccounts accounts
;
410 for (int32 i
= 0; i
< accounts
.CountAccounts(); i
++)
411 fAccounts
.AddItem(new BMailAccountSettings(*accounts
.AccountAt(i
)));
413 for (int i
= 0; i
< fAccounts
.CountItems(); i
++) {
414 BMailAccountSettings
* account
= fAccounts
.ItemAt(i
);
415 _AddAccountToView(account
);
421 ConfigWindow::_SaveSettings()
423 // collect changed accounts
424 BMessage
changedAccounts(BPrivate::kMsgAccountsChanged
);
425 for (int32 i
= 0; i
< fAccounts
.CountItems(); i
++) {
426 BMailAccountSettings
* account
= fAccounts
.ItemAt(i
);
427 if (account
&& account
->HasBeenModified())
428 changedAccounts
.AddInt32("account", account
->AccountID());
430 for (int32 i
= 0; i
< fToDeleteAccounts
.CountItems(); i
++) {
431 BMailAccountSettings
* account
= fToDeleteAccounts
.ItemAt(i
);
432 changedAccounts
.AddInt32("account", account
->AccountID());
435 // cleanup account directory
436 for (int32 i
= 0; i
< fToDeleteAccounts
.CountItems(); i
++) {
437 BMailAccountSettings
* account
= fToDeleteAccounts
.ItemAt(i
);
438 BEntry
entry(account
->AccountFile());
442 fToDeleteAccounts
.MakeEmpty();
444 // Apply and save general settings
446 BMailSettings settings
;
448 bigtime_t interval
= 0;
449 if (fCheckMailCheckBox
->Value() == B_CONTROL_ON
) {
450 // figure out time interval
452 sscanf(fIntervalControl
->Text(), "%f", &floatInterval
);
453 interval
= bigtime_t(60000000L * floatInterval
);
456 settings
.SetAutoCheckInterval(interval
);
457 settings
.SetDaemonAutoStarts(!fAccounts
.IsEmpty());
459 // status mode (alway, fetching/retrieving, ...)
460 int32 index
= fStatusModeField
->Menu()->IndexOf(
461 fStatusModeField
->Menu()->FindMarked());
462 settings
.SetShowStatusWindow(index
);
470 for (int i
= 0; i
< fAccounts
.CountItems(); i
++)
471 fAccounts
.ItemAt(i
)->Save();
474 BMessenger
messenger(B_MAIL_DAEMON_SIGNATURE
);
475 if (messenger
.IsValid()) {
476 // server should reload general settings
477 messenger
.SendMessage(BPrivate::kMsgSettingsUpdated
);
478 // notify server about changed accounts
479 messenger
.SendMessage(&changedAccounts
);
482 // Start the mail_daemon if auto start was selected
484 if (fSaveSettings
&& settings
.DaemonAutoStarts() && !daemon
.IsRunning())
490 ConfigWindow::QuitRequested()
494 be_app
->PostMessage(B_QUIT_REQUESTED
);
500 ConfigWindow::MessageReceived(BMessage
*msg
)
502 BRect
autoConfigRect(0, 0, 400, 300);
505 AutoConfigWindow
*autoConfigWindow
= NULL
;
507 case kMsgAccountsRightClicked
:
510 msg
->FindPoint("point", &point
);
511 int32 index
= msg
->FindInt32("index");
512 AccountItem
* clickedItem
= dynamic_cast<AccountItem
*>(
513 fAccountsListView
->ItemAt(index
));
514 if (clickedItem
== NULL
|| clickedItem
->Type() != ACCOUNT_ITEM
)
517 BPopUpMenu
rightClickMenu("accounts", false, false);
519 BMenuItem
* inMenuItem
= new BMenuItem(B_TRANSLATE("Incoming"),
521 BMenuItem
* outMenuItem
= new BMenuItem(B_TRANSLATE("Outgoing"),
523 rightClickMenu
.AddItem(inMenuItem
);
524 rightClickMenu
.AddItem(outMenuItem
);
526 BMailAccountSettings
* settings
= clickedItem
->Account();
527 if (settings
->IsInboundEnabled())
528 inMenuItem
->SetMarked(true);
529 if (settings
->IsOutboundEnabled())
530 outMenuItem
->SetMarked(true);
532 BMenuItem
* selectedItem
= rightClickMenu
.Go(point
);
533 if (selectedItem
== NULL
)
535 if (selectedItem
== inMenuItem
) {
536 AccountItem
* item
= dynamic_cast<AccountItem
*>(
537 fAccountsListView
->ItemAt(index
+ 1));
540 if (settings
->IsInboundEnabled()) {
541 settings
->SetInboundEnabled(false);
542 item
->SetEnabled(false);
544 settings
->SetInboundEnabled(true);
545 item
->SetEnabled(true);
548 AccountItem
* item
= dynamic_cast<AccountItem
*>(
549 fAccountsListView
->ItemAt(index
+ 2));
552 if (settings
->IsOutboundEnabled()) {
553 settings
->SetOutboundEnabled(false);
554 item
->SetEnabled(false);
556 settings
->SetOutboundEnabled(true);
557 item
->SetEnabled(true);
562 case kMsgAccountSelected
:
565 if (msg
->FindInt32("index", &index
) != B_OK
|| index
< 0) {
566 // deselect current item
567 _ReplaceConfigView(_BuildHowToView());
570 AccountItem
* item
= (AccountItem
*)fAccountsListView
->ItemAt(index
);
572 _AccountSelected(item
);
579 autoConfigRect
.OffsetTo(
580 frame
.left
+ (frame
.Width() - autoConfigRect
.Width()) / 2,
581 frame
.top
+ (frame
.Width() - autoConfigRect
.Height()) / 2);
582 autoConfigWindow
= new AutoConfigWindow(autoConfigRect
, this);
583 autoConfigWindow
->Show();
587 case kMsgRemoveAccount
:
589 int32 index
= fAccountsListView
->CurrentSelection();
591 AccountItem
*item
= (AccountItem
*)fAccountsListView
->ItemAt(
594 _RemoveAccount(item
->Account());
595 _ReplaceConfigView(_BuildHowToView());
601 case kMsgIntervalUnitChanged
:
604 if (msg
->FindInt32("index",&index
) == B_OK
)
605 fIntervalControl
->SetEnabled(index
!= 0);
609 case kMsgShowStatusWindowChanged
:
611 // the status window stuff is the only "live" setting
612 BMessenger
messenger("application/x-vnd.Be-POST");
613 if (messenger
.IsValid())
614 messenger
.SendMessage(msg
);
618 case kMsgRevertSettings
:
619 _RevertToLastSettings();
622 case kMsgSaveSettings
:
623 fSaveSettings
= true;
625 AccountUpdated(fLastSelectedAccount
);
626 _ReplaceConfigView(_BuildHowToView());
627 fAccountsListView
->DeselectAll();
631 BWindow::MessageReceived(msg
);
637 BMailAccountSettings
*
638 ConfigWindow::AddAccount()
640 BMailAccountSettings
* account
= new BMailAccountSettings
;
643 fAccounts
.AddItem(account
);
644 _AddAccountToView(account
);
650 ConfigWindow::AccountUpdated(BMailAccountSettings
* account
)
655 for (int i
= 0; i
< fAccountsListView
->CountItems(); i
++) {
656 AccountItem
* item
= (AccountItem
*)fAccountsListView
->ItemAt(i
);
657 if (item
->Account() == account
) {
658 if (item
->Type() == ACCOUNT_ITEM
) {
659 item
->SetText(account
->Name());
660 fAccountsListView
->Invalidate();
668 ConfigWindow::_SetToGeneralSettings(BMailSettings
* settings
)
670 if (settings
== NULL
)
673 status_t status
= settings
->InitCheck();
677 // retrieval frequency
678 uint32 interval
= uint32(settings
->AutoCheckInterval() / 60000000L);
679 fCheckMailCheckBox
->SetValue(interval
!= 0 ? B_CONTROL_ON
: B_CONTROL_OFF
);
684 BString intervalText
;
685 intervalText
.SetToFormat("%" B_PRIu32
, interval
);
686 fIntervalControl
->SetText(intervalText
.String());
688 int32 showStatusIndex
= settings
->ShowStatusWindow();
689 BMenuItem
* item
= fStatusModeField
->Menu()->ItemAt(showStatusIndex
);
691 item
->SetMarked(true);
692 // send live update to the server by simulating a menu click
693 BMessage
msg(kMsgShowStatusWindowChanged
);
694 msg
.AddInt32("ShowStatusWindow", showStatusIndex
);
703 ConfigWindow::_RevertToLastSettings()
705 // revert general settings
706 BMailSettings settings
;
708 status_t status
= _SetToGeneralSettings(&settings
);
709 if (status
!= B_OK
) {
711 sprintf(text
, B_TRANSLATE(
712 "\nThe general settings couldn't be reverted.\n\n"
713 "Error retrieving general settings:\n%s\n"),
715 BAlert
* alert
= new BAlert(B_TRANSLATE("Error"), text
,
716 B_TRANSLATE("OK"), NULL
, NULL
, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
717 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
721 // revert account data
723 if (fAccountsListView
->CurrentSelection() != -1)
724 _ReplaceConfigView(_BuildHowToView());
726 for (int32 i
= 0; i
< fAccounts
.CountItems(); i
++) {
727 BMailAccountSettings
* account
= fAccounts
.ItemAt(i
);
728 _RemoveAccountFromListView(account
);
732 fAccounts
.MakeEmpty();
738 ConfigWindow::_AddAccountToView(BMailAccountSettings
* account
)
741 label
<< account
->Name();
744 item
= new AccountItem(label
, account
, ACCOUNT_ITEM
);
745 fAccountsListView
->AddItem(item
);
747 item
= new AccountItem(B_TRANSLATE("\t\t· Incoming"), account
, INBOUND_ITEM
);
748 fAccountsListView
->AddItem(item
);
749 if (!account
->IsInboundEnabled())
750 item
->SetEnabled(false);
752 item
= new AccountItem(B_TRANSLATE("\t\t· Outgoing"), account
,
754 fAccountsListView
->AddItem(item
);
755 if (!account
->IsOutboundEnabled())
756 item
->SetEnabled(false);
758 item
= new AccountItem(B_TRANSLATE("\t\t· E-mail filters"), account
,
760 fAccountsListView
->AddItem(item
);
765 ConfigWindow::_RemoveAccount(BMailAccountSettings
* account
)
767 _RemoveAccountFromListView(account
);
768 fAccounts
.RemoveItem(account
);
769 fToDeleteAccounts
.AddItem(account
);
774 ConfigWindow::_RemoveAccountFromListView(BMailAccountSettings
* account
)
776 if (fLastSelectedAccount
== account
) {
777 _ReplaceConfigView(_BuildHowToView());
778 fLastSelectedAccount
= NULL
;
781 for (int i
= fAccountsListView
->CountItems(); i
-- > 0;) {
782 AccountItem
* item
= (AccountItem
*)fAccountsListView
->ItemAt(i
);
783 if (item
->Account() == account
) {
784 fAccountsListView
->RemoveItem(i
);
792 ConfigWindow::_AccountSelected(AccountItem
* item
)
794 AccountUpdated(fLastSelectedAccount
);
796 BMailAccountSettings
* account
= item
->Account();
797 fLastSelectedAccount
= account
;
800 switch (item
->Type()) {
802 view
= new AccountConfigView(account
);
806 view
= new ProtocolSettingsView(account
->InboundAddOnRef(),
807 *account
, account
->InboundSettings());
811 view
= new ProtocolSettingsView(account
->OutboundAddOnRef(),
812 *account
, account
->OutboundSettings());
816 view
= new FiltersConfigView(*account
);
820 _ReplaceConfigView(view
);
825 ConfigWindow::_ReplaceConfigView(BView
* view
)
827 while (BView
* child
= fConfigView
->ChildAt(0)) {
828 fConfigView
->RemoveChild(child
);
833 fConfigView
->AddChild(view
);