ListAgent.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /*
  2. * The contents of this file are subject to the Mozilla Public
  3. * License Version 1.1 (the "License"); you may not use this file
  4. * except in compliance with the License. You may obtain a copy of
  5. * the License at http://www.mozilla.org/MPL/
  6. *
  7. * Software distributed under the License is distributed on an "AS
  8. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9. * implied. See the License for the specific language governing
  10. * rights and limitations under the License.
  11. *
  12. * The Original Code is Vision.
  13. *
  14. * The Initial Developer of the Original Code is The Vision Team.
  15. * Portions created by The Vision Team are
  16. * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights
  17. * Reserved.
  18. *
  19. * Contributor(s): Wade Majors <wade@ezri.org>
  20. * Rene Gollent
  21. * Todd Lair
  22. */
  23. #include <MenuBar.h>
  24. #include <MenuItem.h>
  25. #include <ScrollView.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include "ColumnTypes.h"
  29. #include "ColumnListView.h"
  30. #include "Prompt.h"
  31. #include "StatusView.h"
  32. #include "Vision.h"
  33. #include "Utilities.h"
  34. #include "ListAgent.h"
  35. #include "WindowList.h"
  36. #include "ClientWindow.h"
  37. #include "Theme.h"
  38. /*
  39. -- #beos was here --
  40. <kurros> regurg, fondle my buttocks
  41. <regurg> Your?
  42. <kurros> regurg, yes. mine
  43. <regurg> I understand.
  44. <kurros> regurg, no. i don't think you do
  45. <regurg> Does this make you feel unhappy?
  46. <Brazilian> hmm, eliza is just broke
  47. <kurros> regurg, i just want my buttocks fondled
  48. <regurg> Why do you say your?
  49. <Brazilian> the whole string ("fondle by buttocks") is getting passed
  50. <kurros> regurg, repair thyself
  51. <regurg> Earlier you said your .
  52. <kurros> regurg, get off it. don't worry about it anymore
  53. <regurg> But your .
  54. */
  55. const int32 LIST_BATCH_SIZE = 75;
  56. ListAgent::ListAgent (
  57. BRect frame,
  58. const char *title,
  59. BMessenger *sMsgr_)
  60. : BView (
  61. frame,
  62. title,
  63. B_FOLLOW_ALL_SIDES,
  64. B_WILL_DRAW | B_FRAME_EVENTS),
  65. activeTheme (vision_app->ActiveTheme()),
  66. fSMsgr (sMsgr_),
  67. listUpdateTrigger (NULL),
  68. filter (""),
  69. find (""),
  70. processing (false)
  71. {
  72. frame = Bounds();
  73. listMenu = new BMenu (S_LIST_MENU);
  74. listMenu->AddItem (mFind = new BMenuItem (
  75. S_LIST_MENU_FIND B_UTF8_ELLIPSIS,
  76. new BMessage (M_LIST_FIND)));
  77. listMenu->AddItem (mFindAgain = new BMenuItem (
  78. S_LIST_MENU_FINDNEXT,
  79. new BMessage (M_LIST_FAGAIN)));
  80. listMenu->AddItem (mFilter = new BMenuItem (
  81. S_LIST_MENU_FILTER B_UTF8_ELLIPSIS,
  82. new BMessage (M_LIST_FILTER)));
  83. mFind->SetEnabled (false);
  84. mFindAgain->SetEnabled (false);
  85. mFilter->SetEnabled (false);
  86. BView *bgView (new BView (
  87. frame,
  88. "background",
  89. B_FOLLOW_ALL_SIDES,
  90. B_WILL_DRAW));
  91. bgView->SetViewColor (activeTheme->ForegroundAt (C_BACKGROUND));
  92. AddChild (bgView);
  93. frame = bgView->Bounds().InsetByCopy (1, 1);
  94. listView = new BColumnListView (
  95. frame,
  96. "list",
  97. B_FOLLOW_ALL_SIDES,
  98. B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE);
  99. listView->SetInvocationMessage (new BMessage (M_LIST_INVOKE));
  100. bgView->AddChild (listView);
  101. listView->MakeFocus (true);
  102. listView->SetTarget(this);
  103. channelColumn = new BStringColumn (S_LIST_COLUMN_CHAN, be_plain_font->StringWidth (S_LIST_COLUMN_CHAN) * 2,
  104. 0, frame.Width(), 0);
  105. listView->AddColumn (channelColumn, 0);
  106. usersColumn = new BIntegerColumn (S_LIST_COLUMN_USER, be_plain_font->StringWidth (S_LIST_COLUMN_USER) * 2, 0, frame.Width(), B_ALIGN_CENTER);
  107. listView->AddColumn (usersColumn, 1);
  108. topicColumn = new BStringColumn (S_LIST_COLUMN_TOPIC, frame.Width() / 2,
  109. 0, frame.Width(), 0);
  110. listView->AddColumn (topicColumn, 2);
  111. listView->SetSelectionMode (B_SINGLE_SELECTION_LIST);
  112. activeTheme->ReadLock();
  113. listView->SetColor (B_COLOR_BACKGROUND, activeTheme->ForegroundAt (C_BACKGROUND));
  114. listView->SetColor (B_COLOR_TEXT, activeTheme->ForegroundAt (C_TEXT));
  115. listView->SetColor (B_COLOR_SELECTION, activeTheme->ForegroundAt (C_SELECTION));
  116. listView->SetFont (B_FONT_ROW, &activeTheme->FontAt (F_LISTAGENT));
  117. activeTheme->ReadUnlock();
  118. #ifdef __INTEL__
  119. memset (&re, 0, sizeof (re));
  120. memset (&fre, 0, sizeof (fre));
  121. #endif
  122. }
  123. ListAgent::~ListAgent (void)
  124. {
  125. BRow *row (NULL);
  126. if (listUpdateTrigger)
  127. delete listUpdateTrigger;
  128. while (listView->CountRows() > 0)
  129. {
  130. row = listView->RowAt (0);
  131. listView->RemoveRow (row);
  132. delete row;
  133. }
  134. while (hiddenItems.CountItems() > 0)
  135. delete hiddenItems.RemoveItemAt (0L);
  136. delete fSMsgr;
  137. delete fAgentWinItem;
  138. #ifdef __INTEL__
  139. regfree (&re);
  140. regfree (&fre);
  141. #endif
  142. }
  143. void
  144. ListAgent::AttachedToWindow (void)
  145. {
  146. fMsgr = BMessenger (this);
  147. listView->SetTarget(this);
  148. }
  149. void
  150. ListAgent::Show (void)
  151. {
  152. Window()->PostMessage (M_STATUS_CLEAR);
  153. this->fMsgr.SendMessage (M_STATUS_ADDITEMS);
  154. #ifdef __INTEL__
  155. vision_app->pClientWin()->AddMenu (listMenu);
  156. listMenu->SetTargetForItems (this);
  157. #endif
  158. const BRect *agentRect (dynamic_cast<ClientWindow *>(Window())->AgentRect());
  159. if (*agentRect != Frame())
  160. {
  161. ResizeTo (agentRect->Width(), agentRect->Height());
  162. MoveTo (agentRect->left, agentRect->top);
  163. }
  164. BView::Show();
  165. }
  166. void
  167. ListAgent::Hide (void)
  168. {
  169. vision_app->pClientWin()->RemoveMenu (listMenu);
  170. BView::Hide();
  171. }
  172. void
  173. ListAgent::AddBatch (void)
  174. {
  175. // make sure you call this from a locked looper
  176. BRow *row (NULL);
  177. Window()->DisableUpdates();
  178. while ((row = fBuildList.RemoveItemAt (0L)) != NULL)
  179. listView->AddRow (row);
  180. Window()->EnableUpdates();
  181. BString cString;
  182. cString << listView->CountRows();
  183. if (!IsHidden())
  184. vision_app->pClientWin()->pStatusView()->SetItemValue (0, cString.String(), true);
  185. }
  186. void
  187. ListAgent::MessageReceived (BMessage *msg)
  188. {
  189. switch (msg->what)
  190. {
  191. case M_THEME_FONT_CHANGE:
  192. {
  193. int32 which (msg->FindInt16 ("which"));
  194. if (which == F_LISTAGENT)
  195. {
  196. activeTheme->ReadLock();
  197. listView->SetFont (B_FONT_ROW, &activeTheme->FontAt (F_LISTAGENT));
  198. activeTheme->ReadUnlock();
  199. listView->Invalidate();
  200. }
  201. }
  202. break;
  203. case M_THEME_FOREGROUND_CHANGE:
  204. {
  205. int32 which (msg->FindInt16 ("which"));
  206. bool refresh (false);
  207. switch (which)
  208. {
  209. case C_BACKGROUND:
  210. activeTheme->ReadLock();
  211. listView->SetColor (B_COLOR_BACKGROUND, activeTheme->ForegroundAt (C_BACKGROUND));
  212. activeTheme->ReadUnlock();
  213. refresh = true;
  214. break;
  215. case C_TEXT:
  216. activeTheme->ReadLock();
  217. listView->SetColor (B_COLOR_TEXT, activeTheme->ForegroundAt (C_TEXT));
  218. activeTheme->ReadUnlock();
  219. refresh = true;
  220. break;
  221. case C_SELECTION:
  222. activeTheme->ReadLock();
  223. listView->SetColor (B_COLOR_SELECTION, activeTheme->ForegroundAt (C_SELECTION));
  224. activeTheme->ReadUnlock();
  225. refresh = true;
  226. break;
  227. default:
  228. break;
  229. }
  230. if (refresh)
  231. Invalidate();
  232. }
  233. break;
  234. case M_STATUS_ADDITEMS:
  235. {
  236. vision_app->pClientWin()->pStatusView()->AddItem (new StatusItem (S_STATUS_LISTCOUNT, ""), true);
  237. vision_app->pClientWin()->pStatusView()->AddItem (new StatusItem (S_STATUS_LISTSTAT, ""), true);
  238. vision_app->pClientWin()->pStatusView()->AddItem (new StatusItem (S_STATUS_LISTFILTER, "", STATUS_ALIGN_LEFT), true);
  239. BString cString;
  240. cString << listView->CountRows();
  241. vision_app->pClientWin()->pStatusView()->SetItemValue (0, cString.String(), false);
  242. vision_app->pClientWin()->pStatusView()->SetItemValue (1, statusStr.String(), false);
  243. vision_app->pClientWin()->pStatusView()->SetItemValue (2, filter.String(), true);
  244. }
  245. break;
  246. case M_LIST_COMMAND:
  247. {
  248. if (!processing)
  249. {
  250. BMessage sMsg (M_SERVER_SEND);
  251. BString command ("LIST");
  252. BString params (msg->FindString ("cmd"));
  253. if (params != "-9z99")
  254. {
  255. command.Append (" ");
  256. command.Append (params);
  257. }
  258. sMsg.AddString ("data", command.String());
  259. fSMsgr->SendMessage (&sMsg);
  260. processing = true;
  261. if (!IsHidden())
  262. vision_app->pClientWin()->pStatusView()->SetItemValue (0, "0", true);
  263. }
  264. }
  265. break;
  266. case M_LIST_BEGIN:
  267. {
  268. BMessage msg (M_LIST_UPDATE);
  269. listUpdateTrigger = new BMessageRunner (BMessenger(this), &msg, 3000000);
  270. statusStr = S_LIST_STATUS_LOADING;
  271. if (!IsHidden())
  272. vision_app->pClientWin()->pStatusView()->SetItemValue (1, statusStr.String(), true);
  273. }
  274. break;
  275. case M_LIST_DONE:
  276. {
  277. if (listUpdateTrigger)
  278. {
  279. delete listUpdateTrigger;
  280. listUpdateTrigger = 0;
  281. }
  282. statusStr = S_LIST_STATUS_DONE;
  283. listView->SetSortingEnabled (true);
  284. listView->SetSortColumn (channelColumn, true, true);
  285. if (!IsHidden())
  286. vision_app->pClientWin()->pStatusView()->SetItemValue (1, statusStr.String(), true);
  287. mFind->SetEnabled (true);
  288. mFindAgain->SetEnabled (true);
  289. mFilter->SetEnabled (true);
  290. processing = false;
  291. // empty out any remaining channels that fell below the batch cut off
  292. AddBatch();
  293. BString cString;
  294. cString << listView->CountRows();
  295. if (!IsHidden())
  296. vision_app->pClientWin()->pStatusView()->SetItemValue (0, cString.String(), true);
  297. }
  298. break;
  299. case M_LIST_EVENT:
  300. {
  301. const char *channel, *users, *topic;
  302. msg->FindString ("channel", &channel);
  303. msg->FindString ("users", &users);
  304. msg->FindString ("topic", &topic);
  305. BRow *row (new BRow ());
  306. BStringField *channelField (new BStringField (channel));
  307. BIntegerField *userField (new BIntegerField (atoi(users)));
  308. BStringField *topicField (new BStringField (topic));
  309. row->SetField (channelField, channelColumn->LogicalFieldNum());
  310. row->SetField (userField, usersColumn->LogicalFieldNum());
  311. row->SetField (topicField, topicColumn->LogicalFieldNum());
  312. fBuildList.AddItem (row);
  313. if (fBuildList.CountItems() == LIST_BATCH_SIZE)
  314. AddBatch();
  315. }
  316. break;
  317. #ifdef __INTEL__
  318. case M_LIST_FILTER:
  319. if (msg->HasString ("text"))
  320. {
  321. const char *buffer;
  322. msg->FindString ("text", &buffer);
  323. if (filter != buffer)
  324. {
  325. filter = buffer;
  326. if (!IsHidden())
  327. vision_app->pClientWin()->pStatusView()->SetItemValue (2, filter.String(), true);
  328. regfree (&re);
  329. memset (&re, 0, sizeof (re));
  330. regcomp (
  331. &re,
  332. filter.String(),
  333. REG_EXTENDED | REG_ICASE | REG_NOSUB);
  334. BRow *currentRow;
  335. BStringField *channel,
  336. *topic;
  337. while (hiddenItems.CountItems() != 0)
  338. {
  339. currentRow = hiddenItems.RemoveItemAt (0L);
  340. listView->AddRow (currentRow);
  341. }
  342. if (filter != NULL)
  343. {
  344. int32 k (0);
  345. while (k < listView->CountRows())
  346. {
  347. currentRow = listView->RowAt (k);
  348. channel = (BStringField *)currentRow->GetField (0);
  349. topic = (BStringField *)currentRow->GetField (2);
  350. if ((regexec (&re, channel->String(), 0, 0, 0) != REG_NOMATCH)
  351. || (regexec (&re, topic->String(), 0, 0, 0) != REG_NOMATCH))
  352. {
  353. k++;
  354. continue;
  355. }
  356. else
  357. {
  358. listView->RemoveRow (currentRow);
  359. hiddenItems.AddItem (currentRow);
  360. }
  361. }
  362. }
  363. fMsgr.SendMessage (M_LIST_DONE);
  364. processing = true;
  365. }
  366. }
  367. else
  368. {
  369. PromptWindow *prompt (new PromptWindow (
  370. BPoint ((Window()->Frame().right/2) - 100, (Window()->Frame().bottom/2) - 50),
  371. " Filter:",
  372. "List Filter",
  373. filter.String(),
  374. this,
  375. new BMessage (M_LIST_FILTER),
  376. new RegExValidate ("Filter"),
  377. true));
  378. prompt->Show();
  379. }
  380. break;
  381. case M_LIST_FIND:
  382. if (msg->HasString ("text"))
  383. {
  384. int32 selection (listView->IndexOf(listView->CurrentSelection()));
  385. const char *buffer;
  386. msg->FindString ("text", &buffer);
  387. if (strlen (buffer) == 0)
  388. {
  389. find = buffer;
  390. break;
  391. }
  392. if (selection < 0)
  393. {
  394. selection = 0;
  395. }
  396. else
  397. {
  398. ++selection;
  399. }
  400. if (find != buffer)
  401. {
  402. regfree (&fre);
  403. memset (&fre, 0, sizeof (fre));
  404. regcomp (
  405. &fre,
  406. buffer,
  407. REG_EXTENDED | REG_ICASE | REG_NOSUB);
  408. find = buffer;
  409. }
  410. BStringField *field;
  411. int32 i;
  412. for (i = selection; i < listView->CountRows(); ++i)
  413. {
  414. field = (BStringField *)listView->RowAt (i)->GetField (0);
  415. if (regexec (&fre, field->String(), 0, 0, 0) != REG_NOMATCH)
  416. break;
  417. }
  418. if (i < listView->CountRows())
  419. {
  420. BRow* row = listView->RowAt (i);
  421. listView->DeselectAll();
  422. listView->AddToSelection (row);
  423. listView->ScrollTo(row);
  424. listView->Refresh();
  425. }
  426. else
  427. {
  428. listView->DeselectAll();
  429. }
  430. }
  431. else
  432. {
  433. PromptWindow *prompt (new PromptWindow (
  434. BPoint ((Window()->Frame().right / 2) - 100, (Window()->Frame().bottom/2) - 50),
  435. S_LIST_PROMPT_LABEL,
  436. S_LIST_PROMPT_TITLE,
  437. find.String(),
  438. this,
  439. new BMessage (M_LIST_FIND),
  440. new RegExValidate ("Find:"),
  441. true));
  442. prompt->Show();
  443. }
  444. break;
  445. case M_LIST_FAGAIN:
  446. if (find.Length())
  447. {
  448. msg->AddString ("text", find.String());
  449. msg->what = M_LIST_FIND;
  450. fMsgr.SendMessage (msg);
  451. }
  452. break;
  453. #endif
  454. case M_LIST_INVOKE:
  455. {
  456. BMessage msg (M_SUBMIT);
  457. BString buffer;
  458. BRow *row (listView->CurrentSelection());
  459. if (row)
  460. {
  461. buffer = "/JOIN ";
  462. buffer += ((BStringField *)row->GetField(0))->String();
  463. msg.AddBool ("history", false);
  464. msg.AddBool ("clear", false);
  465. msg.AddString ("input", buffer.String());
  466. fSMsgr->SendMessage (&msg);
  467. }
  468. }
  469. break;
  470. case M_CLIENT_QUIT:
  471. {
  472. fSMsgr->SendMessage(M_LIST_SHUTDOWN);
  473. BMessage deathchant (M_OBITUARY);
  474. deathchant.AddPointer ("agent", this);
  475. deathchant.AddPointer ("item", fAgentWinItem);
  476. vision_app->pClientWin()->PostMessage (&deathchant);
  477. }
  478. break;
  479. default:
  480. BView::MessageReceived (msg);
  481. }
  482. }