From fa0e6b21929d1b1e2e983a088094aae9d0c934aa Mon Sep 17 00:00:00 2001 From: Humdinger Date: Tue, 17 Mar 2026 14:17:08 +0100 Subject: [PATCH] Added "Label as" Tracker add-on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to the "Mark as" Tracker add-on, but for custom labels stored as files in ~/config/settings/Mail/labels. * Sets the MAIL:label file attribute. * The pop-up menu with all available labels also has an item to remove a currently set label from an email, and to open the labels folder to "Manage labels…" (add, remove, rename etc.). * Added File_Mail_label icon to distinguish from the "Mark as" add-on icon. It's supposed to be a narrow post-it as label… "Mark as" Tracker add-on: * Remove custom statuses from the "Mark as" Tracker add-on. That's what the new labels were introduced for. Change-Id: I912a747156da3538457f622c1e2b163700c0c7eb Reviewed-on: https://review.haiku-os.org/c/haiku/+/10539 Reviewed-by: nephele nephele --- data/artwork/icons/File_Mail_label | Bin 0 -> 10463 bytes src/add-ons/tracker/Jamfile | 1 + src/add-ons/tracker/label_as/Jamfile | 16 +++ src/add-ons/tracker/label_as/LabelAs.cpp | 132 ++++++++++++++++++++++ src/add-ons/tracker/label_as/LabelAs.rdef | 34 ++++++ src/add-ons/tracker/mark_as/MarkAs.cpp | 29 +---- 6 files changed, 186 insertions(+), 26 deletions(-) create mode 100644 data/artwork/icons/File_Mail_label create mode 100644 src/add-ons/tracker/label_as/Jamfile create mode 100644 src/add-ons/tracker/label_as/LabelAs.cpp create mode 100644 src/add-ons/tracker/label_as/LabelAs.rdef diff --git a/data/artwork/icons/File_Mail_label b/data/artwork/icons/File_Mail_label new file mode 100644 index 0000000000000000000000000000000000000000..360458e51133fa3d86a444ad156ac3e304284517 GIT binary patch literal 10463 zcmeHNd2AF_9Ddt{QWUiw1k|X55~UFhh#FL6mnsxuv1&1z2%2R(r6b$jb!UK9P18g% z9#Im5NAwTRcxyf4nJ9RRXrdU2i81l`NB@$97~_$w-#2gG^v(9QzE!a%_9c(m`QH8g z&NpSn%FedsE0@g|C@IwHD5YbL5NWheuIYoing}Sm7K%dkEon0C8osq^r=FW z(AI!99e@2WA#OQT_Alpx9$&cVWwWcP=*Jb+uGFgP5Gk~9S5we1N!t}y5q%hGv&h33 z+^8+W$+-|0mPeT^E?U)j4&V1@0}821W7MkiFKC^F-wtXsD#xb9)C7Jya2_Bn_DkSb z0OMHV?HwKAJbb?iRn9Xl#JMi(T@hZ)^}1kP2)`%SRoW!VC9fFZb#|)|0qQ)|KGZ?f zIjCh+r#0;5cty*Or44^RWxiA_y7|EE5-AjN?&J$4pYI#6VH@rrz;+;d=1D#ye>yF`djP)Rg};Gj|vB1-{i#M^X~#E;!` z4B|Ig68{jkXG?r!SVrOx!aOG8PXlfu{&L_Z;%|)SNfLi&gong)!+wzK9j1N}Xr75m zJ)eu3MO}!x3U#(ly-i0+{n$OnpnioV^&4;sTj~!)Ulv{G8}LqF1CN@ZUg0gkb?Oxk zN)pr)XQeHe{7p}UhtyLCa$Q{&*Y}F*QhflPx-(x&sma8!}Ic z$$SuG9u6Y+;5k>R^dz0rklCK2Y~AymN@Gxs3tT2Ai`r0Tga_-3o((j*Y8nj;`if8Z+j!2 zr{a0{k{`c3v31sRMk|4Lp%X0!Hg<{DcRzY!#6UU0V>JVZUBvfGy8C9fzI5C@hLMc1 z!%OOdN~J_H5AlQkg6oTek(t`0BQGMyNZ}mhm4$riMP{MrAXz4Ddgnp z`f?v8nGwws?o{P-a+}rPpQ^5_YqQ@W%*O*O#Zmhn-fv?lQl5isvq%OH z5=+}#&t*RvyMxL;>Ky#d^YN}AbATygRY&_Wh4%uN#*T}SrW)4*r;?_{feCywFuCpw z5Q|mMpeihnGPV;);CZ|a+V{)4JMR=V~(^>s!Y2f46 zGBfs09|-PzYuntTpXpDxy`TBvr0i)(Ri?euc-~8;t$Z1aA`c-w^&T93@ zq2H8J&C0Z7cFfE!-m-h(uQ*S9J}M(Odi5|nX{|v&2sRGM_!+W7W>{2iL~nBm`mzuY zml4lf>cle`#Tghtxf*An+*nL9BhJ43h^7ZXMlA+OevH#`27c_c@G!{v8V0j2sJF4?6`-1o*CRE_ zp1stl6}r@D;gp(`eo|`u`a~(D;0ILNcN;{sIKtD&o%OWq3$#%y(jqCf890|on)4#u zAWh67Vrfz<;t-6>O~EU=Vx&0TintkF$@Kb4;BypLHI*CCrrQT~oP{h<|8#~_s!sc< zwF8x^*V@fd=*xA}_|&c2&56LJ#2RDfxQ{dA{?iip@)$oPf%9XNWV$JVZ;blKy5AX8 zO6y%g#+-bvjAkKUuEgi=(6l{#eXcm+D;eA5b>XAGEX~_b$@bHW=IY4h|S-s`0 zpXThz_&udc;1;8v<6vk*k@&fTvBdu*+I8_uQOSK%{AnnHE;hDE1F<)>TKCBHXlQb+ zq@nTeN)k^R6xBkiOVXhFVlZZ)Vi-4O%c1_$rDYC5*ZV(wAPAoFYFU}d|eQErJ)@vEiF2t_) zML;7n3|ve@s1&-pCO#L{6wsJ%P-wLQZCQlZ2DGoCoTh+w49+EmpA_c82sa3mmKF<> z`zOFX#(_=UEk}xVBCv@%0~>h7*A8=F%Pv^3H=~CycE*?4?0-10mo$0L-J=-X^id4%) z(qEh0^NvX0NFPa?;(tV<&tyFT)s%Gb4;3aK_#p +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "Label-as add-on" + + +BCollator collator; + + +static int +compare_menu_items(const BMenuItem* a, const BMenuItem* b) +{ + return collator.Compare(a->Label(), b->Label()); +} + + +static BPoint +mouse_position() +{ + BPoint position; + get_mouse(&position, NULL); + return position; +} + + +void +open_labels_folder() +{ + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY, &path); + path.Append("Mail/labels"); + + BEntry entry(path.Path()); + if (!entry.Exists()) + create_directory(path.Path(), 0777); + + BEntry folderEntry; + if (folderEntry.SetTo(path.Path()) == B_OK + && folderEntry.Exists()) { + BMessage openFolderCommand(B_REFS_RECEIVED); + BMessenger tracker("application/x-vnd.Be-TRAK"); + + entry_ref ref; + folderEntry.GetRef(&ref); + openFolderCommand.AddRef("refs", &ref); + tracker.SendMessage(&openFolderCommand); + } +} + + +static void +retrieve_label_items(BMenu* menu) +{ + menu->AddItem(new BMenuItem(B_TRANSLATE("Remove label"), NULL)); + menu->AddSeparatorItem(); + + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) + return; + + path.Append("Mail/labels"); + BDirectory directory(path.Path()); + BObjectList items; + entry_ref ref; + + while (directory.GetNextRef(&ref) == B_OK) + items.AddItem(new BMenuItem(ref.name, NULL)); + + if (!items.IsEmpty()) { + if (BLocale::Default()->GetCollator(&collator) == B_OK) { + collator.SetNumericSorting(true); + items.SortItems(compare_menu_items); + } + for (int32 i = 0; i < items.CountItems(); i++) + menu->AddItem(items.ItemAt(i)); + menu->AddSeparatorItem(); + } + menu->AddItem(new BMenuItem(B_TRANSLATE("Manage labels" B_UTF8_ELLIPSIS), NULL)); +} + + +// #pragma mark - + + +extern "C" void +process_refs(entry_ref dir, BMessage* message, void* /*reserved*/) +{ + BPopUpMenu* menu = new BPopUpMenu("labels"); + retrieve_label_items(menu); + + BMenuItem* item = menu->Go(mouse_position() - BPoint(5, 5), false, true); + if (item == NULL) + return; + + BString label = item->Label(); + entry_ref ref; + for (int i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) { + BNode node(&ref); + BString type; + BString previousLabel; + if (node.InitCheck() == B_OK && node.ReadAttrString("BEOS:TYPE", &type) == B_OK + && (type == B_MAIL_TYPE || type == B_PARTIAL_MAIL_TYPE)) { + if (label == B_TRANSLATE("Remove label")) + node.RemoveAttr(B_MAIL_ATTR_LABEL); + else if (label == B_TRANSLATE("Manage labels" B_UTF8_ELLIPSIS)) + open_labels_folder(); + else if (node.ReadAttrString(B_MAIL_ATTR_LABEL, &previousLabel) != B_OK + || previousLabel != label) + node.WriteAttrString(B_MAIL_ATTR_LABEL, &label); + } + } +} diff --git a/src/add-ons/tracker/label_as/LabelAs.rdef b/src/add-ons/tracker/label_as/LabelAs.rdef new file mode 100644 index 0000000000..0c6fa7d683 --- /dev/null +++ b/src/add-ons/tracker/label_as/LabelAs.rdef @@ -0,0 +1,34 @@ +resource app_signature "application/x-vnd.Haiku-LabelAs"; + +resource file_types message { + "types" = "text/x-email", + "types" = "text/x-partial-email" +}; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + /* 0 = development 1 = alpha 2 = beta + 3 = gamma 4 = golden master 5 = final */ + variety = 0, + + internal = 1, + + short_info = "LabelAs, Copyright 2026 Haiku, Inc.", + long_info = "A Tracker Add-on that marks emails with the chosen label." +}; + +resource vector_icon { + $"6E636966060500040167020006023A94CE3C078BBE370C3CD1394B9EF94A1372" + $"00FAF9D2FFDDDB8F03FF0000020006023AC26B3A272ABB621E3C2B0B4A03F64A" + $"005700010101FF807E5D020006033959AFBA52CE3AE8E03A190A49C920491610" + $"2F67CBFFA80594DDFD1BAFFB070A04495D4C5E604A5C480A04363A5C49485D22" + $"4A0A044F464A4B504E55490802384244480802BB11C23D3E4B0802B946C3AF3E" + $"510606AE0B383D4434BFC9BB81C22FBAAD46314D33C41EBBC74D354936404008" + $"0A010100000A0001011001178402040A020101000A030102000A040303040510" + $"01178100040A00010630242201178300040A0501062024220A00001001178200" + $"04" +}; + diff --git a/src/add-ons/tracker/mark_as/MarkAs.cpp b/src/add-ons/tracker/mark_as/MarkAs.cpp index b7ea6304da..1c035fce85 100644 --- a/src/add-ons/tracker/mark_as/MarkAs.cpp +++ b/src/add-ons/tracker/mark_as/MarkAs.cpp @@ -48,31 +48,6 @@ add_status_item(BMenu* menu, const char* name) } -static void -retrieve_status_items(BMenu* menu) -{ - BPath path; - if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) - return; - - path.Append("Mail/status"); - - BDirectory directory(path.Path()); - - entry_ref ref; - while (directory.GetNextRef(&ref) == B_OK) { - if (!strcmp(ref.name, ".") || !strcmp(ref.name, "..")) - continue; - - add_status_item(menu, ref.name); - } - - add_status_item(menu, "New"); - add_status_item(menu, "Read"); - add_status_item(menu, "Replied"); -} - - // #pragma mark - @@ -80,7 +55,9 @@ extern "C" void process_refs(entry_ref dir, BMessage* message, void* /*reserved*/) { BPopUpMenu* menu = new BPopUpMenu("status"); - retrieve_status_items(menu); + add_status_item(menu, "New"); + add_status_item(menu, "Read"); + add_status_item(menu, "Replied"); BMenuItem* item = menu->Go(mouse_position() - BPoint(5, 5), false, true); if (item == NULL)