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.
35 //--------------------------------------------------------------------
38 // The enclosures list view (TListView), the list items (TListItem),
39 // and the view containing the list
40 // and handling the messages (TEnclosuresView).
41 //--------------------------------------------------------------------
43 #include "Enclosures.h"
51 #include <NodeMonitor.h>
52 #include <PopUpMenu.h>
54 #include <MailAttachment.h>
55 #include <MailMessage.h>
62 #include "MailSupport.h"
63 #include "MailWindow.h"
67 #define B_TRANSLATION_CONTEXT "Mail"
70 static const float kPlainFontSizeScale
= 0.9;
73 GetTrackerIcon(BMimeType
&type
, BBitmap
*icon
, icon_size iconSize
)
75 // set some icon size related variables
76 status_t error
= B_OK
;
80 bounds
.Set(0, 0, 15, 15);
83 bounds
.Set(0, 0, 31, 31);
89 // check parameters and initialization
91 && (!icon
|| icon
->InitCheck() != B_OK
|| icon
->Bounds() != bounds
))
96 // Ask the MIME database for the preferred application for the file type
97 // and whether this application has a special icon for the type.
98 char signature
[B_MIME_TYPE_LENGTH
];
99 if (type
.GetPreferredApp(signature
) == B_OK
) {
100 BMimeType
type(signature
);
101 success
= (type
.GetIconForType(type
.Type(), icon
, iconSize
) == B_OK
);
104 // Ask the MIME database whether there is an icon for the node's file type.
105 if (error
== B_OK
&& !success
)
106 success
= (type
.GetIcon(icon
, iconSize
) == B_OK
);
108 // Ask the MIME database for the super type and start all over
109 if (error
== B_OK
&& !success
) {
111 if (type
.GetSupertype(&super
) == B_OK
)
112 return GetTrackerIcon(super
, icon
, iconSize
);
115 // Return the icon for "application/octet-stream" from the MIME database.
116 if (error
== B_OK
&& !success
) {
117 // get the "application/octet-stream" icon
118 BMimeType
type("application/octet-stream");
119 error
= type
.GetIcon(icon
, iconSize
);
127 recursive_attachment_search(TEnclosuresView
* us
, BMailContainer
* mail
,
128 BMailComponent
*body
)
133 for (int32 i
= 0; i
< mail
->CountComponents(); i
++) {
134 BMailComponent
*component
= mail
->GetComponent(i
);
135 if (component
== body
)
138 if (component
->ComponentType() == B_MAIL_MULTIPART_CONTAINER
) {
139 recursive_attachment_search(us
,
140 dynamic_cast<BMIMEMultipartMailContainer
*>(component
), body
);
143 us
->fList
->AddItem(new TListItem(component
));
151 TEnclosuresView::TEnclosuresView(BRect rect
, BRect windowRect
)
153 BView(rect
, "m_enclosures", B_FOLLOW_TOP
| B_FOLLOW_LEFT_RIGHT
,
157 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
159 BFont
font(be_plain_font
);
160 font
.SetSize(font
.Size() * kPlainFontSizeScale
);
166 r
.left
= ENCLOSE_TEXT_H
+ font
.StringWidth(
167 B_TRANSLATE("Attachments: ")) + 5;
168 r
.top
= ENCLOSE_FIELD_V
;
169 r
.right
= windowRect
.right
- windowRect
.left
- B_V_SCROLL_BAR_WIDTH
- 9;
170 r
.bottom
= Frame().Height() - 8;
171 fList
= new TListView(r
, this);
172 fList
->SetInvocationMessage(new BMessage(LIST_INVOKED
));
174 BScrollView
*scroll
= new BScrollView("", fList
, B_FOLLOW_LEFT_RIGHT
|
175 B_FOLLOW_TOP
, 0, false, true);
177 scroll
->ScrollBar(B_VERTICAL
)->SetRange(0, 0);
181 TEnclosuresView::~TEnclosuresView()
183 for (int32 index
= fList
->CountItems();index
-- > 0;)
185 TListItem
*item
= static_cast<TListItem
*>(fList
->ItemAt(index
));
186 fList
->RemoveItem(index
);
188 if (item
->Component() == NULL
)
189 watch_node(item
->NodeRef(), B_STOP_WATCHING
, this);
196 TEnclosuresView::Draw(BRect where
)
200 SetHighColor(0, 0, 0);
201 SetLowColor(ViewColor());
206 MovePenTo(ENCLOSE_TEXT_H
, ENCLOSE_TEXT_V
+ fh
.ascent
);
207 DrawString(ENCLOSE_TEXT
);
212 TEnclosuresView::MessageReceived(BMessage
*msg
)
219 msg
->FindPointer("source", (void **)&list
);
222 TListItem
*item
= (TListItem
*) (list
->ItemAt(msg
->FindInt32("index")));
225 BMessenger
tracker("application/x-vnd.Be-TRAK");
226 if (tracker
.IsValid())
228 BMessage
message(B_REFS_RECEIVED
);
229 message
.AddRef("refs", item
->Ref());
231 tracker
.SendMessage(&message
);
241 while ((index
= fList
->CurrentSelection()) >= 0)
243 TListItem
*item
= (TListItem
*) fList
->ItemAt(index
);
244 fList
->RemoveItem(index
);
246 if (item
->Component())
248 TMailWindow
*window
= dynamic_cast<TMailWindow
*>(Window());
249 if (window
&& window
->Mail())
250 window
->Mail()->RemoveComponent(item
->Component());
252 BAlert
* alert
= new BAlert("", B_TRANSLATE(
253 "Removing attachments from a forwarded mail is not yet "
254 "implemented!\nIt will not yet work correctly."),
256 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
260 watch_node(item
->NodeRef(), B_STOP_WATCHING
, this);
267 fList
->Select(0, fList
->CountItems() - 1, true);
271 case B_REFS_RECEIVED
:
273 if (msg
->HasRef("refs"))
275 bool badType
= false;
279 while (msg
->FindRef("refs", index
++, &ref
) == B_NO_ERROR
)
281 BFile
file(&ref
, O_RDONLY
);
282 if (file
.InitCheck() == B_OK
&& file
.IsFile())
285 for (int16 loop
= 0; loop
< fList
->CountItems(); loop
++)
287 item
= (TListItem
*) fList
->ItemAt(loop
);
288 if (ref
== *(item
->Ref()))
291 fList
->ScrollToSelection();
295 fList
->AddItem(item
= new TListItem(&ref
));
296 fList
->Select(fList
->CountItems() - 1);
297 fList
->ScrollToSelection();
299 watch_node(item
->NodeRef(), B_WATCH_NAME
, this);
307 BAlert
* alert
= new BAlert("",
308 B_TRANSLATE("Only files can be added as attachments."),
310 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
319 if (msg
->FindInt32("opcode", &opcode
) == B_NO_ERROR
)
322 if (msg
->FindInt32("device", &device
) < B_OK
)
325 if (msg
->FindInt64("node", &inode
) < B_OK
)
328 for (int32 index
= fList
->CountItems();index
-- > 0;)
330 TListItem
*item
= static_cast<TListItem
*>(fList
->ItemAt(index
));
332 if (device
== item
->NodeRef()->device
333 && inode
== item
->NodeRef()->node
)
335 if (opcode
== B_ENTRY_REMOVED
)
337 // don't hide the <missing attachment> item
339 //fList->RemoveItem(index);
341 //watch_node(item->NodeRef(), B_STOP_WATCHING, this);
344 else if (opcode
== B_ENTRY_MOVED
)
346 item
->Ref()->device
= device
;
347 msg
->FindInt64("to directory", &item
->Ref()->directory
);
350 msg
->FindString("name", &name
);
351 item
->Ref()->set_name(name
);
354 fList
->InvalidateItem(index
);
363 BView::MessageReceived(msg
);
369 TEnclosuresView::Focus(bool focus
)
380 TEnclosuresView::AddEnclosuresFromMail(BEmailMessage
*mail
)
382 for (int32 i
= 0; i
< mail
->CountComponents(); i
++)
384 BMailComponent
*component
= mail
->GetComponent(i
);
385 if (component
== mail
->Body())
388 if (component
->ComponentType() == B_MAIL_MULTIPART_CONTAINER
)
389 recursive_attachment_search(this,dynamic_cast<BMIMEMultipartMailContainer
*>(component
),mail
->Body());
391 fList
->AddItem(new TListItem(component
));
399 TListView::TListView(BRect rect
, TEnclosuresView
*view
)
401 BListView(rect
, "", B_MULTIPLE_SELECTION_LIST
,
402 B_FOLLOW_TOP
| B_FOLLOW_LEFT_RIGHT
),
409 TListView::AttachedToWindow()
411 BListView::AttachedToWindow();
413 BFont
font(be_plain_font
);
414 font
.SetSize(font
.Size() * kPlainFontSizeScale
);
420 TListView::MakeFocus(bool focus
)
422 BListView::MakeFocus(focus
);
423 fParent
->Focus(focus
);
428 TListView::MouseDown(BPoint point
)
431 Looper()->CurrentMessage()->FindInt32("buttons", &buttons
);
433 BListView::MouseDown(point
);
435 if ((buttons
& B_SECONDARY_MOUSE_BUTTON
) != 0 && IndexOf(point
) >= 0) {
436 BPopUpMenu
menu("enclosure", false, false);
437 menu
.SetFont(be_plain_font
);
438 menu
.AddItem(new BMenuItem(B_TRANSLATE("Open attachment"),
439 new BMessage(LIST_INVOKED
)));
440 menu
.AddItem(new BMenuItem(B_TRANSLATE("Remove attachment"),
441 new BMessage(M_REMOVE
)));
443 BPoint menuStart
= ConvertToScreen(point
);
445 BMenuItem
* item
= menu
.Go(menuStart
);
447 if (item
->Command() == LIST_INVOKED
) {
448 BMessage
msg(LIST_INVOKED
);
449 msg
.AddPointer("source",this);
450 msg
.AddInt32("index",IndexOf(point
));
451 Window()->PostMessage(&msg
,fParent
);
453 Select(IndexOf(point
));
454 Window()->PostMessage(item
->Command(),fParent
);
462 TListView::KeyDown(const char *bytes
, int32 numBytes
)
464 BListView::KeyDown(bytes
,numBytes
);
466 if (numBytes
== 1 && *bytes
== B_DELETE
)
467 Window()->PostMessage(M_REMOVE
, fParent
);
474 TListItem::TListItem(entry_ref
*ref
)
480 entry
.GetNodeRef(&fNodeRef
);
484 TListItem::TListItem(BMailComponent
*component
)
486 fComponent(component
)
492 TListItem::Update(BView
*owner
, const BFont
*font
)
494 BListItem::Update(owner
, font
);
496 if (Height() < 17) // mini icon height + 1
502 TListItem::DrawItem(BView
*owner
, BRect r
, bool /* complete */)
505 owner
->SetHighColor(180, 180, 180);
506 owner
->SetLowColor(180, 180, 180);
508 owner
->SetHighColor(255, 255, 255);
509 owner
->SetLowColor(255, 255, 255);
512 owner
->SetHighColor(0, 0, 0);
514 BFont font
= *be_plain_font
;
515 font
.SetSize(font
.Size() * kPlainFontSizeScale
);
516 owner
->SetFont(&font
);
517 owner
->MovePenTo(r
.left
+ 24, r
.bottom
- 4);
520 // if it's already a mail component, we don't have an icon to
521 // draw, and the entry_ref is invalid
522 BMailAttachment
*attachment
= dynamic_cast<BMailAttachment
*>(fComponent
);
524 char name
[B_FILE_NAME_LENGTH
* 2];
525 if ((attachment
== NULL
) || (attachment
->FileName(name
) < B_OK
))
526 strcpy(name
, "unnamed");
529 if (fComponent
->MIMEType(&type
) == B_OK
)
530 sprintf(name
+ strlen(name
), ", Type: %s", type
.Type());
532 owner
->DrawString(name
);
534 BRect
iconRect(0, 0, B_MINI_ICON
- 1, B_MINI_ICON
- 1);
536 BBitmap
bitmap(iconRect
, B_RGBA32
);
537 if (GetTrackerIcon(type
, &bitmap
, B_MINI_ICON
) == B_NO_ERROR
) {
538 BRect
rect(r
.left
+ 4, r
.top
+ 1, r
.left
+ 4 + 15, r
.top
+ 1 + 15);
539 owner
->SetDrawingMode(B_OP_ALPHA
);
540 owner
->DrawBitmap(&bitmap
, iconRect
, rect
);
541 owner
->SetDrawingMode(B_OP_COPY
);
543 // ToDo: find some nicer image for this :-)
544 owner
->SetHighColor(150, 150, 150);
545 owner
->FillEllipse(BRect(r
.left
+ 8, r
.top
+ 4, r
.left
+ 16, r
.top
+ 13));
550 BFile
file(&fRef
, O_RDONLY
);
553 if (entry
.GetPath(&path
) == B_OK
&& file
.InitCheck() == B_OK
) {
554 owner
->DrawString(path
.Path());
556 BNodeInfo
info(&file
);
557 BRect
sr(0, 0, B_MINI_ICON
- 1, B_MINI_ICON
- 1);
559 BBitmap
bitmap(sr
, B_RGBA32
);
560 if (info
.GetTrackerIcon(&bitmap
, B_MINI_ICON
) == B_NO_ERROR
) {
561 BRect
dr(r
.left
+ 4, r
.top
+ 1, r
.left
+ 4 + 15, r
.top
+ 1 + 15);
562 owner
->SetDrawingMode(B_OP_ALPHA
);
563 owner
->DrawBitmap(&bitmap
, sr
, dr
);
564 owner
->SetDrawingMode(B_OP_COPY
);
567 owner
->DrawString("<missing attachment>");