RosterListView.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright 2009, Pier Luigi Fiorini. All rights reserved.
  3. * Distributed under the terms of the MIT License.
  4. *
  5. * Authors:
  6. * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
  7. */
  8. #include "RosterListView.h"
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include <Catalog.h>
  12. #include <Looper.h>
  13. #include <MenuItem.h>
  14. #include <PopUpMenu.h>
  15. #include <SeparatorItem.h>
  16. #include "ChatProtocolMessages.h"
  17. #include "Contact.h"
  18. #include "ProtocolLooper.h"
  19. #include "RosterItem.h"
  20. #include "TheApp.h"
  21. #include "UserInfoWindow.h"
  22. #undef B_TRANSLATION_CONTEXT
  23. #define B_TRANSLATION_CONTEXT "RosterListView"
  24. const int32 kAddPeople = 'ADPL';
  25. const int32 kSendFile = 'SDFL';
  26. const int32 kShowLogs = 'SHLG';
  27. const int32 kStartConv = 'SRCV';
  28. const int32 kGetInfo = 'GINF';
  29. static int
  30. compare_by_name(const void* _item1, const void* _item2)
  31. {
  32. BListItem* item1 = *(BListItem**)_item1;
  33. BListItem* item2 = *(BListItem**)_item2;
  34. RosterItem* roster1 = dynamic_cast<RosterItem*>(item1);
  35. RosterItem* roster2 = dynamic_cast<RosterItem*>(item2);
  36. if (roster1 == NULL && roster2 == NULL)
  37. return 0;
  38. if (roster1 == NULL)
  39. return 1;
  40. if (roster2 == NULL)
  41. return -1;
  42. return strcasecmp(roster1->GetContact()->GetName().String(),
  43. roster2->GetContact()->GetName().String());
  44. }
  45. static int
  46. compare_by_status(const void* _item1, const void* _item2)
  47. {
  48. BListItem* item1 = *(RosterItem**)_item1;
  49. BListItem* item2 = *(RosterItem**)_item2;
  50. RosterItem* roster1 = dynamic_cast<RosterItem*>(item1);
  51. RosterItem* roster2 = dynamic_cast<RosterItem*>(item2);
  52. if (roster1 == NULL && roster2 == NULL)
  53. return 0;
  54. if (roster1 == NULL || roster1->Status() < roster2->Status())
  55. return 1;
  56. if (roster2 == NULL || roster1->Status() > roster2->Status())
  57. return -1;
  58. return 0;
  59. }
  60. RosterListView::RosterListView(const char* name)
  61. : BOutlineListView(name, B_SINGLE_SELECTION_LIST,
  62. B_WILL_DRAW | B_FRAME_EVENTS |
  63. B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE),
  64. fPrevItem(NULL)
  65. {
  66. // Context menu
  67. fPopUp = new BPopUpMenu("contextMenu", false, false);
  68. BMenuItem* item = NULL;
  69. fPopUp->AddItem(new BMenuItem(B_TRANSLATE("Start a chat"),
  70. new BMessage(kStartConv)));
  71. item = new BMenuItem(B_TRANSLATE("Send a file" B_UTF8_ELLIPSIS),
  72. new BMessage(kSendFile));
  73. item->SetEnabled(false);
  74. fPopUp->AddItem(item);
  75. fPopUp->AddItem(new BSeparatorItem());
  76. fPopUp->AddItem(new BMenuItem(B_TRANSLATE("User info" B_UTF8_ELLIPSIS),
  77. new BMessage(kGetInfo)));
  78. fPopUp->SetTargetForItems(this);
  79. }
  80. // #pragama mark -
  81. void
  82. RosterListView::AttachedToWindow()
  83. {
  84. fPopUp->SetTargetForItems(this);
  85. SetTarget(this);
  86. }
  87. void
  88. RosterListView::MessageReceived(BMessage* msg)
  89. {
  90. BListItem* item = ItemAt(CurrentSelection());
  91. RosterItem* ritem = reinterpret_cast<RosterItem*>(item);
  92. switch (msg->what) {
  93. case kGetInfo:
  94. {
  95. if (ritem == NULL)
  96. return;
  97. _InfoWindow(ritem->GetContact());
  98. break;
  99. }
  100. case kStartConv:
  101. {
  102. User* user;
  103. if (ritem == NULL || (user = ritem->GetContact()) == NULL)
  104. return;
  105. BMessage* start = new BMessage(IM_MESSAGE);
  106. start->AddInt32("im_what", IM_CREATE_CHAT);
  107. start->AddString("user_id", user->GetId());
  108. ProtocolLooper* looper = user->GetProtocolLooper();
  109. if (looper != NULL)
  110. looper->PostMessage(start);
  111. break;
  112. }
  113. default:
  114. BListView::MessageReceived(msg);
  115. }
  116. }
  117. void
  118. RosterListView::MouseMoved(BPoint where, uint32 code, const BMessage* msg)
  119. {
  120. BListView::MouseMoved(where, code, msg);
  121. return;
  122. switch (code) {
  123. case B_INSIDE_VIEW:
  124. {
  125. // Mouse cursor is inside this view, hide last item's popup
  126. // and show current item's popup
  127. BListItem* item = ItemAt(IndexOf(where));
  128. RosterItem* ritem = reinterpret_cast<RosterItem*>(item);
  129. if (ritem == NULL)
  130. return;
  131. // Hide previous item's popup
  132. if ((fPrevItem != NULL) && (fPrevItem != ritem))
  133. fPrevItem->GetContact()->HidePopUp();
  134. // Show current item's popup
  135. ritem->GetContact()->ShowPopUp(ConvertToScreen(where));
  136. // This will be the previous item
  137. fPrevItem = ritem;
  138. break;
  139. }
  140. case B_EXITED_VIEW:
  141. // Mouse cursor leaved this view, hide last item's popup
  142. if (fPrevItem != NULL)
  143. fPrevItem->GetContact()->HidePopUp();
  144. break;
  145. }
  146. }
  147. void
  148. RosterListView::MouseDown(BPoint where)
  149. {
  150. BMessage* message = Looper()->CurrentMessage();
  151. int32 buttons = 0;
  152. (void)message->FindInt32("buttons", &buttons);
  153. if (buttons == B_SECONDARY_MOUSE_BUTTON) {
  154. int32 index = IndexOf(where);
  155. if (index >= 0) {
  156. // Select list item
  157. Select(index);
  158. // Show context menu if right button is clicked
  159. (void)fPopUp->Go(ConvertToScreen(where), true, true, false);
  160. }
  161. } else {
  162. // Call original MouseDown()
  163. BListView::MouseDown(where);
  164. }
  165. }
  166. void
  167. RosterListView::Draw(BRect updateRect)
  168. {
  169. int32 count = CountItems();
  170. if (count == 0)
  171. return;
  172. BRect itemFrame(0, 0, Bounds().right, -1);
  173. for (int32 i = 0; i < count; i++) {
  174. BListItem* item = ItemAt(i);
  175. RosterItem* rosterItem = reinterpret_cast<RosterItem*>(item);
  176. if (!rosterItem->IsVisible())
  177. continue;
  178. itemFrame.bottom = itemFrame.top + ceilf(item->Height()) - 1;
  179. if (itemFrame.Intersects(updateRect))
  180. rosterItem->DrawItem(this, itemFrame);
  181. itemFrame.top = itemFrame.bottom + 1;
  182. }
  183. }
  184. bool
  185. RosterListView::AddItem(BListItem* item)
  186. {
  187. item->Deselect();
  188. bool ret = false;
  189. if (HasItem(item) == false)
  190. ret = BListView::AddItem(item);
  191. Sort();
  192. return ret;
  193. }
  194. bool
  195. RosterListView::RemoveItem(BListItem* item)
  196. {
  197. item->Deselect();
  198. return BListView::RemoveItem(item);
  199. }
  200. RosterItem*
  201. RosterListView::RosterItemAt(int32 index)
  202. {
  203. return dynamic_cast<RosterItem*>(ItemAt(index));
  204. }
  205. void
  206. RosterListView::Sort()
  207. {
  208. SortItems(compare_by_name);
  209. }
  210. void
  211. RosterListView::_InfoWindow(Contact* linker)
  212. {
  213. UserInfoWindow* win = new UserInfoWindow(linker);
  214. win->Show();
  215. }