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:
Nathan Whitehorn
2005-07-22 13:25:37 +00:00
parent 1270e8a017
commit 9d41fc2bec
4 changed files with 219 additions and 90 deletions
+141 -59
View File
@@ -49,6 +49,7 @@ All rights reserved.
#include <StringView.h>
#include <E-mail.h>
#include <String.h>
#include <PopUpMenu.h>
#include <fs_index.h>
#include <fs_info.h>
#include <map>
@@ -76,6 +77,7 @@ extern uint32 gDefaultChain;
const char *kDateLabel = "Date:";
const uint32 kMsgFrom = 'hFrm';
const uint32 kMsgEncoding = 'encd';
const uint32 kMsgAddressChosen = 'acsn';
class QPopupMenu : public QueryMenu {
@@ -718,7 +720,8 @@ THeaderView::LoadMessage(BEmailMessage *mail)
TTextControl::TTextControl(BRect rect, char *label, BMessage *msg,
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)
{
strcpy(fLabel, label);
@@ -750,75 +753,123 @@ void
TTextControl::MessageReceived(BMessage *msg)
{
switch (msg->what) {
case B_SIMPLE_DATA:
if (!fIncoming || fResending) {
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.
case B_SIMPLE_DATA: {
if ((fIncoming == true) && (fResending == false)) return;
int32 buttons = -1;
BPoint point;
entry_ref ref;
for (int32 index = 0;msg->FindRef("refs", index, &ref) == B_OK; index++) {
BFile file(&ref, B_READ_ONLY);
if (file.InitCheck() == B_NO_ERROR) {
BNodeInfo node(&file);
char type[B_FILE_NAME_LENGTH];
node.GetType(type);
if (msg->FindInt32("buttons", &buttons) != B_OK) {
buttons = B_PRIMARY_MOUSE_BUTTON;
};
if (buttons != B_PRIMARY_MOUSE_BUTTON) {
if (msg->FindPoint("_drop_point_", &point) != B_OK) return;
};
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 &&
!strcmp(type,"application/x-person")) {
// add person's E-mail address to the To: field
entry_ref ref;
for (int32 index = 0;msg->FindRef("refs", index, &ref) == B_OK; index++) {
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)
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 {
enclosure = true;
message.AddRef("refs", &ref);
BNode node(&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;
};
case M_SELECT:
{
@@ -828,6 +879,37 @@ TTextControl::MessageReceived(BMessage *msg)
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:
// BTextControl::MessageReceived(msg);
BComboBox::MessageReceived(msg);
+1
View File
@@ -143,6 +143,7 @@ class TTextControl : public BComboBox
bool fIncoming;
bool fResending;
char fLabel[100];
BPopUpMenu *fRefDropMenu;
int32 fCommand;
};
+71 -30
View File
@@ -106,9 +106,9 @@ QueryMenu::QueryMenu(const char *title, bool popUp, bool radioMode, bool autoRen
fQueryLooper->AddHandler(fQueryHandler);
fQueryLooper->Unlock();
BMessenger mercury(fQueryHandler, fQueryLooper);
fQuery = new BQuery();
fQuery->SetTarget(mercury);
// BMessenger mercury(fQueryHandler, fQueryLooper);
// fQuery = new BQuery();
// fQuery->SetTarget(mercury);
}
@@ -116,7 +116,12 @@ QueryMenu::~QueryMenu(void)
{
fCancelQuery = true;
fQueryLock.Lock();
delete fQuery;
int32 queries = fQueries.size();
for (int i = 0; i < queries; i++) {
fQueries[i]->Clear();
delete fQueries[i];
};
fQueryLock.Unlock();
fQueryLooper->Lock();
@@ -160,22 +165,52 @@ void QueryMenu::DoQueryMessage(BMessage *msg)
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
if (volume == NULL)
{
BVolume bootVolume;
BVolumeRoster().GetBootVolume(&bootVolume);
if ( (status = fQuery->SetVolume(&bootVolume)) != B_OK)
return status;
}
else if ((status = fQuery->SetVolume(volume)) != B_OK)
return status;
if ((status = fQuery->SetPredicate(expr)) < B_OK)
return status;
// if (volume == NULL)
// {
// BVolume bootVolume;
// BVolumeRoster().GetBootVolume(&bootVolume);
//
// if ( (status = fQuery->SetVolume(&bootVolume)) != B_OK)
// return status;
// }
// else if ((status = fQuery->SetVolume(volume)) != B_OK)
// return status;
//
// if ((status = fQuery->SetPredicate(expr)) < B_OK)
// return status;
// Force query thread to exit if still running
fCancelQuery = true;
@@ -219,17 +254,22 @@ int32 QueryMenu::QueryThread()
// Begin resolving query
fCancelQuery = false;
fQuery->Fetch();
// Build Menu
entry_ref ref;
node_ref node;
while (fQuery->GetNextRef(&ref) == B_OK && !fCancelQuery)
{
BEntry entry(&ref);
entry.GetNodeRef(&node);
EntryCreated(ref, node.node);
}
int32 queries = fQueries.size();
for (int i = 0; i < queries; i++) {
BQuery *query = fQueries[i];
query->Fetch();
// Build Menu
entry_ref ref;
node_ref 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
BMenuItem *item;
@@ -272,8 +312,9 @@ void QueryMenu::EntryCreated(const entry_ref &ref, ino_t node)
msg->AddRef("refs", &ref);
msg->AddInt64("node", node);
item = new BMenuItem(ref.name, msg);
if (fTargetHandler)
if (fTargetHandler) {
item->SetTarget(fTargetHandler);
};
AddItem(item);
}
+6 -1
View File
@@ -38,11 +38,15 @@ All rights reserved.
#include <Locker.h>
#include <PopUpMenu.h>
#include <vector>
class BLooper;
class BQuery;
class BVolume;
class QHandler;
typedef vector<BQuery *> query_t;
class QueryMenu : public BPopUpMenu {
friend QHandler;
@@ -70,7 +74,8 @@ class QueryMenu : public BPopUpMenu {
int32 QueryThread(void);
BLocker fQueryLock;
BQuery *fQuery;
// BQuery *fQuery;
query_t fQueries;
QHandler *fQueryHandler;
bool fCancelQuery;
bool fPopUp;