6 Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
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:
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.
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.
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.
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.
40 #include <ControlLook.h>
41 #include <DateTimeFormat.h>
43 #include <LayoutBuilder.h>
46 #include <MenuField.h>
48 #include <ObjectList.h>
49 #include <PopUpMenu.h>
52 #include <StringView.h>
54 #include <VolumeRoster.h>
59 #include <MailSettings.h>
60 #include <MailMessage.h>
63 #include "MailSupport.h"
64 #include "MailWindow.h"
66 #include "Utilities.h"
67 #include "QueryMenu.h"
72 #define B_TRANSLATION_CONTEXT "Mail"
75 using namespace BPrivate
;
79 const uint32 kMsgFrom
= 'hFrm';
80 const uint32 kMsgAddressChosen
= 'acsn';
83 struct CompareBStrings
{
85 operator()(const BString
*s1
, const BString
*s2
) const
87 return (s1
->Compare(*s2
) < 0);
92 class LabelView
: public BStringView
{
94 LabelView(const char* label
);
96 bool IsEnabled() const
98 void SetEnabled(bool enabled
);
100 virtual void Draw(BRect updateRect
);
107 class HeaderTextControl
: public BTextControl
{
109 HeaderTextControl(const char* label
,
110 const char* name
, BMessage
* message
);
112 virtual void AttachedToWindow();
113 virtual void SetEnabled(bool enabled
);
114 virtual void Draw(BRect updateRect
);
115 virtual void MessageReceived(BMessage
* message
);
118 void _UpdateTextViewColors();
122 // #pragma mark - LabelView
125 LabelView::LabelView(const char* label
)
127 BStringView("label", label
),
130 SetAlignment(B_ALIGN_RIGHT
);
135 LabelView::SetEnabled(bool enabled
)
137 if (enabled
!= fEnabled
) {
145 LabelView::Draw(BRect updateRect
)
147 if (Text() != NULL
) {
148 BRect rect
= Bounds();
149 // TODO: solve this better (alignment of label and text)
152 rgb_color base
= ui_color(B_PANEL_BACKGROUND_COLOR
);
155 flags
|= BControlLook::B_DISABLED
;
157 be_control_look
->DrawLabel(this, Text(), rect
, updateRect
,
158 base
, flags
, BAlignment(Alignment(), B_ALIGN_MIDDLE
));
163 // #pragma mark - HeaderTextControl
166 HeaderTextControl::HeaderTextControl(const char* label
, const char* name
,
169 BTextControl(label
, name
, message
)
175 HeaderTextControl::AttachedToWindow()
177 BTextControl::AttachedToWindow();
178 _UpdateTextViewColors();
183 HeaderTextControl::SetEnabled(bool enabled
)
185 BTextControl::SetEnabled(enabled
);
186 _UpdateTextViewColors();
191 HeaderTextControl::Draw(BRect updateRect
)
193 bool enabled
= IsEnabled();
194 bool active
= TextView()->IsFocus() && Window()->IsActive();
196 BRect rect
= TextView()->Frame();
197 rect
.InsetBy(-2, -2);
199 rgb_color base
= ui_color(B_PANEL_BACKGROUND_COLOR
);
202 flags
= BControlLook::B_DISABLED
;
206 flags
|= BControlLook::B_FOCUSED
;
208 be_control_look
->DrawTextControlBorder(this, rect
, updateRect
, base
,
212 if (Label() != NULL
) {
213 rect
= CreateLabelLayoutItem()->Frame().OffsetByCopy(-Frame().left
,
215 // TODO: solve this better (alignment of label and text)
218 alignment labelAlignment
;
219 GetAlignment(&labelAlignment
, NULL
);
221 be_control_look
->DrawLabel(this, Label(), rect
, updateRect
,
222 base
, flags
, BAlignment(labelAlignment
, B_ALIGN_MIDDLE
));
228 HeaderTextControl::MessageReceived(BMessage
* message
)
230 switch (message
->what
) {
233 BTextView
* textView
= TextView();
234 if (textView
!= NULL
)
235 textView
->SelectAll();
240 BTextControl::MessageReceived(message
);
247 HeaderTextControl::_UpdateTextViewColors()
249 BTextView
* textView
= TextView();
252 textView
->GetFontAndColor(0, &font
);
255 if (!textView
->IsEditable() || IsEnabled())
256 textColor
= ui_color(B_DOCUMENT_TEXT_COLOR
);
258 textColor
= tint_color(ui_color(B_PANEL_BACKGROUND_COLOR
),
259 B_DISABLED_LABEL_TINT
);
262 textView
->SetFontAndColor(&font
, B_FONT_ALL
, &textColor
);
265 if (!textView
->IsEditable())
266 color
= ui_color(B_PANEL_BACKGROUND_COLOR
);
267 else if (IsEnabled())
268 color
= ui_color(B_DOCUMENT_BACKGROUND_COLOR
);
270 color
= tint_color(ui_color(B_PANEL_BACKGROUND_COLOR
),
274 textView
->SetViewColor(color
);
275 textView
->SetLowColor(color
);
279 // #pragma mark - THeaderView
282 THeaderView::THeaderView(bool incoming
, bool resending
, int32 defaultAccount
)
285 fAccountID(defaultAccount
),
290 fResending(resending
)
294 fFromControl
= new HeaderTextControl(B_TRANSLATE("From:"), NULL
, NULL
);
295 fFromControl
->SetAlignment(B_ALIGN_RIGHT
, B_ALIGN_LEFT
);
296 fFromControl
->SetEnabled(false);
299 // From accounts menu
300 BMenuField
* fromField
= NULL
;
301 if (!fIncoming
|| resending
) {
302 // And now the "from account" pop-up menu, on the left side, taking the
305 fAccountMenu
= new BPopUpMenu(B_EMPTY_STRING
);
307 BMailAccounts accounts
;
309 for (int32 i
= 0; i
< accounts
.CountAccounts(); i
++) {
310 BMailAccountSettings
* account
= accounts
.AccountAt(i
);
311 BString name
= account
->Name();
312 name
<< ": " << account
->RealName() << " <"
313 << account
->ReturnAddress() << ">";
315 BMessage
* msg
= new BMessage(kMsgFrom
);
316 BMenuItem
*item
= new BMenuItem(name
, msg
);
318 msg
->AddInt32("id", account
->AccountID());
320 if (defaultAccount
== account
->AccountID()) {
321 item
->SetMarked(true);
324 fAccountMenu
->AddItem(item
);
328 BMenuItem
*item
= fAccountMenu
->ItemAt(0);
330 item
->SetMarked(true);
331 fAccountID
= item
->Message()->FindInt32("id");
333 fAccountMenu
->AddItem(
334 item
= new BMenuItem(B_TRANSLATE("<none>"), NULL
));
335 item
->SetEnabled(false);
336 fAccountID
= ~(int32
)0;
338 // default account is invalid, set to marked
339 // TODO: do this differently, no casting and knowledge
340 // of TMailApp here....
341 if (TMailApp
* app
= dynamic_cast<TMailApp
*>(be_app
))
342 app
->SetDefaultAccount(fAccountID
);
345 fromField
= new BMenuField("account", B_TRANSLATE("From:"),
346 fAccountMenu
, B_WILL_DRAW
| B_NAVIGABLE
| B_NAVIGABLE_JUMP
);
347 fromField
->SetAlignment(B_ALIGN_RIGHT
);
351 fToLabel
= new LabelView(B_TRANSLATE("To:"));
352 fToControl
= new AddressTextControl(B_TRANSLATE("To:"),
353 new BMessage(TO_FIELD
));
354 if (fIncoming
|| resending
) {
355 fToLabel
->SetEnabled(false);
356 fToControl
->SetEditable(false);
357 fToControl
->SetEnabled(false);
360 BMessage
* msg
= new BMessage(FIELD_CHANGED
);
361 msg
->AddInt32("bitmask", FIELD_TO
);
362 fToControl
->SetModificationMessage(msg
);
365 fCcLabel
= new LabelView(B_TRANSLATE("Cc:"));
366 fCcControl
= new AddressTextControl("cc", new BMessage(CC_FIELD
));
368 fCcLabel
->SetEnabled(false);
369 fCcControl
->SetEditable(false);
370 fCcControl
->SetEnabled(false);
374 msg
= new BMessage(FIELD_CHANGED
);
375 msg
->AddInt32("bitmask", FIELD_CC
);
376 fCcControl
->SetModificationMessage(msg
);
380 fBccControl
= new AddressTextControl("bcc", new BMessage(BCC_FIELD
));
381 msg
= new BMessage(FIELD_CHANGED
);
382 msg
->AddInt32("bitmask", FIELD_BCC
);
383 fBccControl
->SetModificationMessage(msg
);
387 fSubjectControl
= new HeaderTextControl(B_TRANSLATE("Subject:"), NULL
,
388 new BMessage(SUBJECT_FIELD
));
389 msg
= new BMessage(FIELD_CHANGED
);
390 msg
->AddInt32("bitmask", FIELD_SUBJECT
);
391 fSubjectControl
->SetModificationMessage(msg
);
392 fSubjectControl
->SetAlignment(B_ALIGN_RIGHT
, B_ALIGN_LEFT
);
393 if (fIncoming
|| fResending
)
394 fSubjectControl
->SetEnabled(false);
398 fDateControl
= new HeaderTextControl(B_TRANSLATE("Date:"), NULL
, NULL
);
399 fDateControl
->SetAlignment(B_ALIGN_RIGHT
, B_ALIGN_LEFT
);
400 fDateControl
->SetEnabled(false);
403 BGridLayout
* layout
= GridLayout();
406 layout
->SetHorizontalSpacing(0);
407 layout
->SetVerticalSpacing(B_USE_HALF_ITEM_SPACING
);
410 if (fromField
!= NULL
) {
411 layout
->AddItem(fromField
->CreateLabelLayoutItem(), 0, row
);
412 layout
->AddItem(fromField
->CreateMenuBarLayoutItem(), 1, row
++, 3, 1);
413 } else if (fFromControl
!= NULL
) {
414 layout
->AddItem(fFromControl
->CreateLabelLayoutItem(), 0, row
);
415 layout
->AddItem(fFromControl
->CreateTextViewLayoutItem(), 1, row
++,
419 layout
->AddView(fToLabel
, 0, row
);
420 layout
->AddView(fToControl
, 1, row
++, 3, 1);
421 layout
->AddView(fCcLabel
, 0, row
);
422 layout
->AddView(fCcControl
, 1, row
, fIncoming
? 3 : 1, 1);
423 if (fBccControl
!= NULL
) {
424 layout
->AddView(new LabelView(B_TRANSLATE("Bcc:")), 2, row
);
425 layout
->AddView(fBccControl
, 3, row
++);
428 layout
->AddItem(fSubjectControl
->CreateLabelLayoutItem(), 0, row
);
429 layout
->AddItem(fSubjectControl
->CreateTextViewLayoutItem(), 1, row
++,
432 if (fDateControl
!= NULL
) {
433 layout
->AddItem(fDateControl
->CreateLabelLayoutItem(), 0, row
);
434 layout
->AddItem(fDateControl
->CreateTextViewLayoutItem(), 1, row
++,
441 THeaderView::From() const
443 return fFromControl
!= NULL
? fFromControl
->Text() : NULL
;
448 THeaderView::SetFrom(const char* from
)
450 if (fFromControl
!= NULL
)
451 fFromControl
->SetText(from
);
456 THeaderView::IsToEmpty() const
458 return To() == NULL
|| To()[0] == '\0';
463 THeaderView::To() const
465 return fToControl
->Text();
470 THeaderView::SetTo(const char* to
)
472 fToControl
->SetText(to
);
477 THeaderView::IsCcEmpty() const
479 return Cc() == NULL
|| Cc()[0] == '\0';
484 THeaderView::Cc() const
486 return fCcControl
!= NULL
? fCcControl
->Text() : NULL
;
491 THeaderView::SetCc(const char* cc
)
493 fCcControl
->SetText(cc
);
496 if (cc
!= NULL
&& cc
[0] != '\0') {
497 if (fCcControl
->IsHidden(this)) {
501 } else if (!fCcControl
->IsHidden(this)) {
510 THeaderView::IsBccEmpty() const
512 return Bcc() == NULL
|| Bcc()[0] == '\0';
517 THeaderView::Bcc() const
519 return fBccControl
!= NULL
? fBccControl
->Text() : NULL
;
524 THeaderView::SetBcc(const char* bcc
)
526 if (fBccControl
!= NULL
)
527 fBccControl
->SetText(bcc
);
532 THeaderView::IsSubjectEmpty() const
534 return Subject() == NULL
|| Subject()[0] == '\0';
539 THeaderView::Subject() const
541 return fSubjectControl
->Text();
546 THeaderView::SetSubject(const char* subject
)
548 fSubjectControl
->SetText(subject
);
553 THeaderView::IsDateEmpty() const
555 return Date() == NULL
|| Date()[0] == '\0';
560 THeaderView::Date() const
562 return fDateControl
!= NULL
? fDateControl
->Text() : NULL
;
567 THeaderView::SetDate(time_t date
)
571 if (fDateControl
!= NULL
) {
572 BDateTimeFormat formatter
;
575 formatter
.Format(string
, date
, B_FULL_DATE_FORMAT
,
576 B_MEDIUM_TIME_FORMAT
);
583 THeaderView::SetDate(const char* date
)
585 if (fDateControl
!= NULL
)
586 fDateControl
->SetText(date
);
591 THeaderView::AccountID() const
598 THeaderView::AccountName() const
600 BMenuItem
* menuItem
= fAccountMenu
->FindMarked();
601 if (menuItem
!= NULL
)
602 return menuItem
->Label();
609 THeaderView::SetAccount(int32 id
)
613 if (fAccountMenu
== NULL
)
616 for (int32 i
= fAccountMenu
->CountItems(); i
-- > 0;) {
617 BMenuItem
* item
= fAccountMenu
->ItemAt(i
);
621 BMessage
* message
= item
->Message();
622 if (message
->GetInt32("id", -1) == id
) {
623 item
->SetMarked(true);
631 THeaderView::SetAccount(const char* name
)
633 if (fAccountMenu
== NULL
)
636 BMenuItem
* item
= fAccountMenu
->FindItem(name
);
638 item
->SetMarked(true);
639 fAccountID
= item
->Message()->GetInt32("id", -1);
645 THeaderView::SetFromMessage(BEmailMessage
* mail
)
647 // Set Subject:, From:, To: & Cc: fields
648 SetSubject(mail
->Subject());
649 SetFrom(mail
->From());
654 if (mail
->GetAccountName(accountName
) == B_OK
)
655 SetAccount(accountName
);
657 // Set the date on this message
658 time_t date
= mail
->Date();
660 const char* dateField
= mail
->HeaderField("Date");
661 SetDate(dateField
!= NULL
? dateField
: B_TRANSLATE("Unknown"));
670 THeaderView::MessageReceived(BMessage
*msg
)
675 BTextView
* textView
= dynamic_cast<BTextView
*>(Window()->CurrentFocus());
676 if (dynamic_cast<AddressTextControl
*>(textView
->Parent()) != NULL
)
677 textView
->Parent()->MessageReceived(msg
);
679 BMessage
message(*msg
);
680 message
.what
= REFS_RECEIVED
;
681 Window()->PostMessage(&message
, Window());
689 if (msg
->FindPointer("source", (void **)&item
) >= B_OK
)
690 item
->SetMarked(true);
693 if (msg
->FindInt32("id",(int32
*)&account
) >= B_OK
)
694 fAccountID
= account
;
696 BMessage
message(FIELD_CHANGED
);
697 // field doesn't matter; no special processing for this field
698 // it's just to turn on the save button
699 message
.AddInt32("bitmask", 0);
700 Window()->PostMessage(&message
, Window());
708 THeaderView::AttachedToWindow()
710 fToControl
->SetTarget(Looper());
711 fSubjectControl
->SetTarget(Looper());
712 fCcControl
->SetTarget(Looper());
713 if (fBccControl
!= NULL
)
714 fBccControl
->SetTarget(Looper());
715 if (fAccountMenu
!= NULL
)
716 fAccountMenu
->SetTargetForItems(this);
718 BView::AttachedToWindow();