Right click drags of people files into BeMail lets you choose which of multiple e-mail addess attributes you want to use, and the people query for the "To:" menu now looks on non-boot volumes as well. Patch c/o slaad.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13803 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+141
-59
@@ -49,6 +49,7 @@ All rights reserved.
|
|||||||
#include <StringView.h>
|
#include <StringView.h>
|
||||||
#include <E-mail.h>
|
#include <E-mail.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
#include <PopUpMenu.h>
|
||||||
#include <fs_index.h>
|
#include <fs_index.h>
|
||||||
#include <fs_info.h>
|
#include <fs_info.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -76,6 +77,7 @@ extern uint32 gDefaultChain;
|
|||||||
const char *kDateLabel = "Date:";
|
const char *kDateLabel = "Date:";
|
||||||
const uint32 kMsgFrom = 'hFrm';
|
const uint32 kMsgFrom = 'hFrm';
|
||||||
const uint32 kMsgEncoding = 'encd';
|
const uint32 kMsgEncoding = 'encd';
|
||||||
|
const uint32 kMsgAddressChosen = 'acsn';
|
||||||
|
|
||||||
|
|
||||||
class QPopupMenu : public QueryMenu {
|
class QPopupMenu : public QueryMenu {
|
||||||
@@ -718,7 +720,8 @@ THeaderView::LoadMessage(BEmailMessage *mail)
|
|||||||
|
|
||||||
TTextControl::TTextControl(BRect rect, char *label, BMessage *msg,
|
TTextControl::TTextControl(BRect rect, char *label, BMessage *msg,
|
||||||
bool incoming, bool resending, int32 resizingMode)
|
bool incoming, bool resending, int32 resizingMode)
|
||||||
: BComboBox(rect, "happy", label, msg, resizingMode)
|
: BComboBox(rect, "happy", label, msg, resizingMode),
|
||||||
|
fRefDropMenu(NULL)
|
||||||
//:BTextControl(rect, "happy", label, "", msg, resizingMode)
|
//:BTextControl(rect, "happy", label, "", msg, resizingMode)
|
||||||
{
|
{
|
||||||
strcpy(fLabel, label);
|
strcpy(fLabel, label);
|
||||||
@@ -750,75 +753,123 @@ void
|
|||||||
TTextControl::MessageReceived(BMessage *msg)
|
TTextControl::MessageReceived(BMessage *msg)
|
||||||
{
|
{
|
||||||
switch (msg->what) {
|
switch (msg->what) {
|
||||||
case B_SIMPLE_DATA:
|
case B_SIMPLE_DATA: {
|
||||||
if (!fIncoming || fResending) {
|
if ((fIncoming == true) && (fResending == false)) return;
|
||||||
BMessage message(REFS_RECEIVED);
|
|
||||||
bool enclosure = false;
|
int32 buttons = -1;
|
||||||
BString addressList;
|
BPoint point;
|
||||||
// Batch up the addresses to be added, since we can only
|
|
||||||
// insert a few times before deadlocking since inserting
|
|
||||||
// sends a notification message to the window BLooper,
|
|
||||||
// which is busy doing this insert. BeOS message queues
|
|
||||||
// are annoyingly limited in their design.
|
|
||||||
|
|
||||||
entry_ref ref;
|
if (msg->FindInt32("buttons", &buttons) != B_OK) {
|
||||||
for (int32 index = 0;msg->FindRef("refs", index, &ref) == B_OK; index++) {
|
buttons = B_PRIMARY_MOUSE_BUTTON;
|
||||||
BFile file(&ref, B_READ_ONLY);
|
};
|
||||||
if (file.InitCheck() == B_NO_ERROR) {
|
if (buttons != B_PRIMARY_MOUSE_BUTTON) {
|
||||||
BNodeInfo node(&file);
|
if (msg->FindPoint("_drop_point_", &point) != B_OK) return;
|
||||||
char type[B_FILE_NAME_LENGTH];
|
};
|
||||||
node.GetType(type);
|
|
||||||
|
BMessage message(REFS_RECEIVED);
|
||||||
|
bool enclosure = false;
|
||||||
|
BString addressList;
|
||||||
|
// Batch up the addresses to be added, since we can only
|
||||||
|
// insert a few times before deadlocking since inserting
|
||||||
|
// sends a notification message to the window BLooper,
|
||||||
|
// which is busy doing this insert. BeOS message queues
|
||||||
|
// are annoyingly limited in their design.
|
||||||
|
|
||||||
if (fCommand != SUBJECT_FIELD &&
|
entry_ref ref;
|
||||||
!strcmp(type,"application/x-person")) {
|
for (int32 index = 0;msg->FindRef("refs", index, &ref) == B_OK; index++) {
|
||||||
// add person's E-mail address to the To: field
|
BFile file(&ref, B_READ_ONLY);
|
||||||
|
if (file.InitCheck() == B_NO_ERROR) {
|
||||||
|
BNodeInfo info(&file);
|
||||||
|
char type[B_FILE_NAME_LENGTH];
|
||||||
|
info.GetType(type);
|
||||||
|
|
||||||
const char *attr;
|
if (fCommand != SUBJECT_FIELD &&
|
||||||
|
!strcmp(type,"application/x-person")) {
|
||||||
|
// add person's E-mail address to the To: field
|
||||||
|
|
||||||
|
BString attr = "";
|
||||||
|
if (buttons == B_PRIMARY_MOUSE_BUTTON) {
|
||||||
|
|
||||||
if (msg->FindString("attr", &attr) < B_OK)
|
if (msg->FindString("attr", &attr) < B_OK)
|
||||||
attr = "META:email"; // If not META:email3 etc.
|
attr = "META:email"; // If not META:email3 etc.
|
||||||
|
|
||||||
BString email;
|
|
||||||
ReadAttrString(&file,attr,&email);
|
|
||||||
|
|
||||||
/* we got something... */
|
|
||||||
if (email.Length() > 0) {
|
|
||||||
/* see if we can get a username as well */
|
|
||||||
BString name;
|
|
||||||
ReadAttrString(&file,"META:name",&name);
|
|
||||||
|
|
||||||
BString address;
|
|
||||||
/* if we have no Name, just use the email address */
|
|
||||||
if (name.Length() == 0)
|
|
||||||
address = email;
|
|
||||||
else {
|
|
||||||
/* otherwise, pretty-format it */
|
|
||||||
address << "\"" << name << "\" <" << email << ">";
|
|
||||||
}
|
|
||||||
if (addressList.Length() > 0)
|
|
||||||
addressList << ", ";
|
|
||||||
addressList << address;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
enclosure = true;
|
BNode node(&ref);
|
||||||
message.AddRef("refs", &ref);
|
node.RewindAttrs();
|
||||||
|
|
||||||
|
char buffer[B_ATTR_NAME_LENGTH];
|
||||||
|
|
||||||
|
if (fRefDropMenu) delete fRefDropMenu;
|
||||||
|
fRefDropMenu = new BPopUpMenu("RecipientMenu");
|
||||||
|
|
||||||
|
while (node.GetNextAttrName(buffer) == B_OK) {
|
||||||
|
if (strstr(buffer, "email") <= 0) continue;
|
||||||
|
attr = buffer;
|
||||||
|
|
||||||
|
BString address;
|
||||||
|
ReadAttrString(&node, buffer, &address);
|
||||||
|
if (address.Length() <= 0) continue;
|
||||||
|
|
||||||
|
BMessage *itemMsg = new BMessage(kMsgAddressChosen);
|
||||||
|
itemMsg->AddString("address", address.String());
|
||||||
|
itemMsg->AddRef("ref", &ref);
|
||||||
|
|
||||||
|
BMenuItem *item = new BMenuItem(address.String(),
|
||||||
|
itemMsg);
|
||||||
|
fRefDropMenu->AddItem(item);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (fRefDropMenu->CountItems() > 1) {
|
||||||
|
fRefDropMenu->SetTargetForItems(this);
|
||||||
|
fRefDropMenu->Go(point, true, true, true);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
delete fRefDropMenu;
|
||||||
|
fRefDropMenu = NULL;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
BString email;
|
||||||
|
ReadAttrString(&file,attr.String(),&email);
|
||||||
|
|
||||||
|
/* we got something... */
|
||||||
|
if (email.Length() > 0) {
|
||||||
|
/* see if we can get a username as well */
|
||||||
|
BString name;
|
||||||
|
ReadAttrString(&file,"META:name",&name);
|
||||||
|
|
||||||
|
BString address;
|
||||||
|
/* if we have no Name, just use the email address */
|
||||||
|
if (name.Length() == 0)
|
||||||
|
address = email;
|
||||||
|
else {
|
||||||
|
/* otherwise, pretty-format it */
|
||||||
|
address << "\"" << name << "\" <" << email << ">";
|
||||||
|
}
|
||||||
|
if (addressList.Length() > 0)
|
||||||
|
addressList << ", ";
|
||||||
|
addressList << address;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
enclosure = true;
|
||||||
|
message.AddRef("refs", &ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addressList.Length() > 0) {
|
|
||||||
BTextView *textView = TextView();
|
|
||||||
int end = textView->TextLength();
|
|
||||||
if (end != 0) {
|
|
||||||
textView->Select(end, end);
|
|
||||||
textView->Insert(", ");
|
|
||||||
}
|
|
||||||
textView->Insert(addressList.String());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enclosure)
|
|
||||||
Window()->PostMessage(&message, Window());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addressList.Length() > 0) {
|
||||||
|
BTextView *textView = TextView();
|
||||||
|
int end = textView->TextLength();
|
||||||
|
if (end != 0) {
|
||||||
|
textView->Select(end, end);
|
||||||
|
textView->Insert(", ");
|
||||||
|
}
|
||||||
|
textView->Insert(addressList.String());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enclosure) Window()->PostMessage(&message, Window());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
case M_SELECT:
|
case M_SELECT:
|
||||||
{
|
{
|
||||||
@@ -828,6 +879,37 @@ TTextControl::MessageReceived(BMessage *msg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case kMsgAddressChosen: {
|
||||||
|
BString display;
|
||||||
|
BString address;
|
||||||
|
entry_ref ref;
|
||||||
|
|
||||||
|
if (msg->FindString("address", &address) != B_OK) return;
|
||||||
|
if (msg->FindRef("ref", &ref) != B_OK) return;
|
||||||
|
|
||||||
|
if (address.Length() > 0) {
|
||||||
|
BString name;
|
||||||
|
BNode node(&ref);
|
||||||
|
|
||||||
|
display = address;
|
||||||
|
|
||||||
|
ReadAttrString(&node, "META:name", &name);
|
||||||
|
if (name.Length() > 0) {
|
||||||
|
display = "";
|
||||||
|
display << "\"" << name << "\" <" << address << ">";
|
||||||
|
};
|
||||||
|
|
||||||
|
BTextView *textView = TextView();
|
||||||
|
int end = textView->TextLength();
|
||||||
|
if (end != 0) {
|
||||||
|
textView->Select(end, end);
|
||||||
|
textView->Insert(", ");
|
||||||
|
};
|
||||||
|
textView->Insert(display.String());
|
||||||
|
|
||||||
|
};
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// BTextControl::MessageReceived(msg);
|
// BTextControl::MessageReceived(msg);
|
||||||
BComboBox::MessageReceived(msg);
|
BComboBox::MessageReceived(msg);
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ class TTextControl : public BComboBox
|
|||||||
bool fIncoming;
|
bool fIncoming;
|
||||||
bool fResending;
|
bool fResending;
|
||||||
char fLabel[100];
|
char fLabel[100];
|
||||||
|
BPopUpMenu *fRefDropMenu;
|
||||||
int32 fCommand;
|
int32 fCommand;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -106,9 +106,9 @@ QueryMenu::QueryMenu(const char *title, bool popUp, bool radioMode, bool autoRen
|
|||||||
fQueryLooper->AddHandler(fQueryHandler);
|
fQueryLooper->AddHandler(fQueryHandler);
|
||||||
fQueryLooper->Unlock();
|
fQueryLooper->Unlock();
|
||||||
|
|
||||||
BMessenger mercury(fQueryHandler, fQueryLooper);
|
// BMessenger mercury(fQueryHandler, fQueryLooper);
|
||||||
fQuery = new BQuery();
|
// fQuery = new BQuery();
|
||||||
fQuery->SetTarget(mercury);
|
// fQuery->SetTarget(mercury);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -116,7 +116,12 @@ QueryMenu::~QueryMenu(void)
|
|||||||
{
|
{
|
||||||
fCancelQuery = true;
|
fCancelQuery = true;
|
||||||
fQueryLock.Lock();
|
fQueryLock.Lock();
|
||||||
delete fQuery;
|
|
||||||
|
int32 queries = fQueries.size();
|
||||||
|
for (int i = 0; i < queries; i++) {
|
||||||
|
fQueries[i]->Clear();
|
||||||
|
delete fQueries[i];
|
||||||
|
};
|
||||||
fQueryLock.Unlock();
|
fQueryLock.Unlock();
|
||||||
|
|
||||||
fQueryLooper->Lock();
|
fQueryLooper->Lock();
|
||||||
@@ -160,22 +165,52 @@ void QueryMenu::DoQueryMessage(BMessage *msg)
|
|||||||
|
|
||||||
status_t QueryMenu::SetPredicate(const char *expr, BVolume *volume)
|
status_t QueryMenu::SetPredicate(const char *expr, BVolume *volume)
|
||||||
{
|
{
|
||||||
status_t status;
|
// status_t status;
|
||||||
|
|
||||||
|
if (volume == NULL) {
|
||||||
|
BVolumeRoster roster;
|
||||||
|
BVolume volume;
|
||||||
|
BMessenger mercury(fQueryHandler, fQueryLooper);
|
||||||
|
|
||||||
|
roster.Rewind();
|
||||||
|
while (roster.GetNextVolume(&volume) == B_NO_ERROR) {
|
||||||
|
if ((volume.KnowsQuery() == true) && (volume.KnowsAttr() == true) &&
|
||||||
|
(volume.KnowsMime() == true)) {
|
||||||
|
|
||||||
|
BQuery *query = new BQuery();
|
||||||
|
if (query->SetVolume(&volume) != B_OK) {
|
||||||
|
delete query;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if (query->SetPredicate(expr) != B_OK) {
|
||||||
|
delete query;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if (query->SetTarget(mercury) != B_OK) {
|
||||||
|
delete query;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
fQueries.push_back(query);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
};
|
||||||
|
|
||||||
// Set the volume
|
// Set the volume
|
||||||
if (volume == NULL)
|
// if (volume == NULL)
|
||||||
{
|
// {
|
||||||
BVolume bootVolume;
|
// BVolume bootVolume;
|
||||||
BVolumeRoster().GetBootVolume(&bootVolume);
|
// BVolumeRoster().GetBootVolume(&bootVolume);
|
||||||
|
//
|
||||||
if ( (status = fQuery->SetVolume(&bootVolume)) != B_OK)
|
// if ( (status = fQuery->SetVolume(&bootVolume)) != B_OK)
|
||||||
return status;
|
// return status;
|
||||||
}
|
// }
|
||||||
else if ((status = fQuery->SetVolume(volume)) != B_OK)
|
// else if ((status = fQuery->SetVolume(volume)) != B_OK)
|
||||||
return status;
|
// return status;
|
||||||
|
//
|
||||||
if ((status = fQuery->SetPredicate(expr)) < B_OK)
|
// if ((status = fQuery->SetPredicate(expr)) < B_OK)
|
||||||
return status;
|
// return status;
|
||||||
|
|
||||||
// Force query thread to exit if still running
|
// Force query thread to exit if still running
|
||||||
fCancelQuery = true;
|
fCancelQuery = true;
|
||||||
@@ -219,17 +254,22 @@ int32 QueryMenu::QueryThread()
|
|||||||
|
|
||||||
// Begin resolving query
|
// Begin resolving query
|
||||||
fCancelQuery = false;
|
fCancelQuery = false;
|
||||||
fQuery->Fetch();
|
int32 queries = fQueries.size();
|
||||||
|
for (int i = 0; i < queries; i++) {
|
||||||
// Build Menu
|
BQuery *query = fQueries[i];
|
||||||
entry_ref ref;
|
|
||||||
node_ref node;
|
query->Fetch();
|
||||||
while (fQuery->GetNextRef(&ref) == B_OK && !fCancelQuery)
|
|
||||||
{
|
// Build Menu
|
||||||
BEntry entry(&ref);
|
entry_ref ref;
|
||||||
entry.GetNodeRef(&node);
|
node_ref node;
|
||||||
EntryCreated(ref, node.node);
|
while (query->GetNextRef(&ref) == B_OK && !fCancelQuery)
|
||||||
}
|
{
|
||||||
|
BEntry entry(&ref);
|
||||||
|
entry.GetNodeRef(&node);
|
||||||
|
EntryCreated(ref, node.node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Remove the group separator if there are no groups or no items without groups
|
// Remove the group separator if there are no groups or no items without groups
|
||||||
BMenuItem *item;
|
BMenuItem *item;
|
||||||
@@ -272,8 +312,9 @@ void QueryMenu::EntryCreated(const entry_ref &ref, ino_t node)
|
|||||||
msg->AddRef("refs", &ref);
|
msg->AddRef("refs", &ref);
|
||||||
msg->AddInt64("node", node);
|
msg->AddInt64("node", node);
|
||||||
item = new BMenuItem(ref.name, msg);
|
item = new BMenuItem(ref.name, msg);
|
||||||
if (fTargetHandler)
|
if (fTargetHandler) {
|
||||||
item->SetTarget(fTargetHandler);
|
item->SetTarget(fTargetHandler);
|
||||||
|
};
|
||||||
AddItem(item);
|
AddItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,11 +38,15 @@ All rights reserved.
|
|||||||
#include <Locker.h>
|
#include <Locker.h>
|
||||||
#include <PopUpMenu.h>
|
#include <PopUpMenu.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class BLooper;
|
class BLooper;
|
||||||
class BQuery;
|
class BQuery;
|
||||||
class BVolume;
|
class BVolume;
|
||||||
class QHandler;
|
class QHandler;
|
||||||
|
|
||||||
|
typedef vector<BQuery *> query_t;
|
||||||
|
|
||||||
class QueryMenu : public BPopUpMenu {
|
class QueryMenu : public BPopUpMenu {
|
||||||
friend QHandler;
|
friend QHandler;
|
||||||
|
|
||||||
@@ -70,7 +74,8 @@ class QueryMenu : public BPopUpMenu {
|
|||||||
int32 QueryThread(void);
|
int32 QueryThread(void);
|
||||||
|
|
||||||
BLocker fQueryLock;
|
BLocker fQueryLock;
|
||||||
BQuery *fQuery;
|
// BQuery *fQuery;
|
||||||
|
query_t fQueries;
|
||||||
QHandler *fQueryHandler;
|
QHandler *fQueryHandler;
|
||||||
bool fCancelQuery;
|
bool fCancelQuery;
|
||||||
bool fPopUp;
|
bool fPopUp;
|
||||||
|
|||||||
Reference in New Issue
Block a user