ClientAgentInputFilter.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  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. * Andrew Bazan
  23. * Jamie Wilkinson
  24. */
  25. #include <Alert.h>
  26. #include <Clipboard.h>
  27. #include <NodeInfo.h>
  28. #include <ScrollView.h>
  29. #include <String.h>
  30. #include <stdio.h>
  31. #include "ClientAgent.h"
  32. #include "ClientAgentInputFilter.h"
  33. #include "ClientWindow.h"
  34. #include "RunView.h"
  35. #include "Vision.h"
  36. #include "VisionBase.h"
  37. #include "VTextControl.h"
  38. #include "WindowList.h"
  39. ClientAgentInputFilter::ClientAgentInputFilter (ClientAgent *agent)
  40. : BMessageFilter (B_ANY_DELIVERY, B_ANY_SOURCE),
  41. fWindow (agent),
  42. fHandledDrop (false)
  43. {}
  44. filter_result
  45. ClientAgentInputFilter::Filter (BMessage *msg, BHandler **target)
  46. {
  47. filter_result result (B_DISPATCH_MESSAGE);
  48. switch (msg->what)
  49. {
  50. case B_MOUSE_MOVED:
  51. break;
  52. case B_COPY:
  53. {
  54. int32 start, finish;
  55. fWindow->fInput->TextView()->GetSelection (&start, &finish);
  56. if (start == finish)
  57. *target = fWindow->fText;
  58. }
  59. break;
  60. case B_SELECT_ALL:
  61. {
  62. if (fWindow->fInput->TextView()->TextLength() == 0)
  63. *target = fWindow->fText;
  64. }
  65. break;
  66. case B_KEY_DOWN:
  67. {
  68. result = HandleKeys (msg);
  69. }
  70. break;
  71. case B_MOUSE_UP:
  72. {
  73. if (fHandledDrop)
  74. {
  75. fHandledDrop = false;
  76. result = B_SKIP_MESSAGE;
  77. }
  78. }
  79. break;
  80. case B_MIME_TYPE:
  81. {
  82. if (msg->HasData ("text/plain", B_MIME_TYPE))
  83. {
  84. const char *buffer;
  85. ssize_t size;
  86. msg->FindData (
  87. "text/plain",
  88. B_MIME_TYPE,
  89. 0,
  90. reinterpret_cast<const void **>(&buffer),
  91. &size);
  92. // We copy it, because B_MIME_TYPE
  93. // might not be \0 terminated
  94. BString string;
  95. string.Append (buffer, size);
  96. HandleDrop (string.String());
  97. fHandledDrop = true;
  98. result = B_SKIP_MESSAGE;
  99. }
  100. }
  101. break;
  102. case B_SIMPLE_DATA:
  103. {
  104. if (msg->HasRef ("refs"))
  105. {
  106. for (int32 i = 0; msg->HasRef ("refs", i); ++i)
  107. {
  108. entry_ref ref;
  109. msg->FindRef ("refs", &ref);
  110. char mime[B_MIME_TYPE_LENGTH];
  111. BFile file (&ref, B_READ_ONLY);
  112. BNodeInfo info (&file);
  113. off_t size;
  114. if (file.InitCheck() == B_NO_ERROR
  115. && file.GetSize (&size) == B_NO_ERROR
  116. && info.InitCheck() == B_NO_ERROR
  117. && info.GetType (mime) == B_NO_ERROR
  118. && strncasecmp (mime, "text/", 5) == 0)
  119. {
  120. char *buffer (new char [size + 1]);
  121. if (buffer)
  122. {
  123. // Oh baby!
  124. file.Read (buffer, size);
  125. buffer[size] = 0;
  126. HandleDrop (buffer);
  127. delete [] buffer;
  128. break;
  129. }
  130. }
  131. }
  132. // Give the fWindow a chance to handle non
  133. // text files. If it's a message window, it'll
  134. // kick off a dcc send
  135. fWindow->DroppedFile (msg);
  136. }
  137. }
  138. break;
  139. case B_PASTE:
  140. {
  141. // we have our own pasting code so we can catch multiple lines
  142. BClipboard clipboard ("system");
  143. const char *fText;
  144. ssize_t textLen;
  145. BMessage *clip ((BMessage *)NULL);
  146. if (clipboard.Lock())
  147. {
  148. if ((clip = clipboard.Data()))
  149. if (clip->FindData ("text/plain", B_MIME_TYPE,
  150. (const void **)&fText, &textLen) != B_OK)
  151. {
  152. clipboard.Unlock();
  153. break;
  154. }
  155. }
  156. clipboard.Unlock();
  157. BString data (fText, textLen);
  158. HandleDrop (data.String());
  159. result = B_SKIP_MESSAGE;
  160. }
  161. break;
  162. case B_MOUSE_WHEEL_CHANGED:
  163. {
  164. // pass this msg to IRCView
  165. fWindow->fText->MessageReceived (msg);
  166. result = B_SKIP_MESSAGE;
  167. }
  168. break;
  169. default:
  170. {
  171. //printf ("FILTER UNHANDLED: ");
  172. //msg->PrintToStream();
  173. }
  174. break;
  175. }
  176. return result;
  177. }
  178. filter_result
  179. ClientAgentInputFilter::HandleKeys (BMessage *msg)
  180. {
  181. filter_result result (B_DISPATCH_MESSAGE);
  182. const char *keyStroke;
  183. int32 keymodifiers;
  184. BMessenger msgr (fWindow);
  185. WindowList *winList (vision_app->pClientWin()->pWindowList());
  186. msg->FindString ("bytes", &keyStroke);
  187. msg->FindInt32 ("modifiers", &keymodifiers);
  188. if (keyStroke == NULL)
  189. {
  190. return result;
  191. }
  192. switch (keyStroke[0])
  193. {
  194. /////////////////
  195. /// catch all ///
  196. /////////////////
  197. case B_RETURN:
  198. {
  199. // we dont want Shift+B_RETURN to select all the text
  200. // treat keypress like we would a normal B_RETURN
  201. if (fWindow->fInput->TextView()->TextLength())
  202. {
  203. BMessage msg (M_SUBMIT);
  204. msg.AddString ("input", fWindow->fInput->TextView()->Text());
  205. msgr.SendMessage (&msg);
  206. }
  207. result = B_SKIP_MESSAGE;
  208. }
  209. break;
  210. case B_TAB: // tab key
  211. {
  212. if ((keymodifiers & B_OPTION_KEY) == 0
  213. && (keymodifiers & B_COMMAND_KEY) == 0
  214. && (keymodifiers & B_CONTROL_KEY) == 0
  215. && (keymodifiers & B_SHIFT_KEY) == 0)
  216. {
  217. // used for tabcompletion for nickname/channelname/etc
  218. fWindow->TabExpansion();
  219. BMessage logMessage (M_CLIENT_LOG);
  220. logMessage.AddString ("name", fWindow->fId.String());
  221. logMessage.AddString ("data", "DEBUG: Tab completion used\n");
  222. fWindow->fSMsgr.SendMessage (&logMessage);
  223. }
  224. if ((keymodifiers & B_SHIFT_KEY) || !(keymodifiers & B_CONTROL_KEY))
  225. result = B_SKIP_MESSAGE;
  226. }
  227. break;
  228. }
  229. if ((keymodifiers & B_OPTION_KEY) == 0
  230. && (keymodifiers & B_COMMAND_KEY) != 0
  231. && (keymodifiers & B_CONTROL_KEY) == 0
  232. && (keymodifiers & B_SHIFT_KEY) != 0)
  233. {
  234. switch (keyStroke[0])
  235. {
  236. case '0':
  237. case B_INSERT:
  238. // switch to last active agent
  239. winList->SelectLast();
  240. result = B_SKIP_MESSAGE;
  241. break;
  242. case B_UP_ARROW:
  243. case B_LEFT_ARROW: // baxter muscle memory
  244. case ',': // bowser muscle memory
  245. winList->ContextSelectUp();
  246. result = B_SKIP_MESSAGE;
  247. break;
  248. case B_DOWN_ARROW: //
  249. case B_RIGHT_ARROW: // baxter muscle memory
  250. case '.': // bowser muscle memory
  251. winList->ContextSelectDown();
  252. result = B_SKIP_MESSAGE;
  253. break;
  254. case 'U':
  255. winList->MoveCurrentUp();
  256. result = B_SKIP_MESSAGE;
  257. break;
  258. case 'D':
  259. winList->MoveCurrentDown();
  260. result = B_SKIP_MESSAGE;
  261. break;
  262. }
  263. }
  264. else if ((keymodifiers & B_OPTION_KEY) == 0
  265. && (keymodifiers & B_COMMAND_KEY) != 0
  266. && (keymodifiers & B_CONTROL_KEY) == 0
  267. && (keymodifiers & B_SHIFT_KEY) == 0)
  268. {
  269. ///////////////
  270. /// Command ///
  271. ///////////////
  272. switch (keyStroke[0])
  273. {
  274. case B_UP_ARROW:
  275. case ',': // bowser muscle memory
  276. {
  277. // move up one agent
  278. winList->Select (winList->CurrentSelection() - 1);
  279. winList->ScrollToSelection();
  280. result = B_SKIP_MESSAGE;
  281. }
  282. break;
  283. case B_DOWN_ARROW:
  284. case '.': // bowser muscle memory
  285. {
  286. // move down one agent
  287. winList->Select (winList->CurrentSelection() + 1);
  288. winList->ScrollToSelection();
  289. result = B_SKIP_MESSAGE;
  290. }
  291. break;
  292. case B_LEFT_ARROW: // collapse current server (if expanded)
  293. {
  294. winList->CollapseCurrentServer();
  295. result = B_SKIP_MESSAGE;
  296. }
  297. break;
  298. case B_RIGHT_ARROW: // expand current server (if collapsed)
  299. {
  300. winList->ExpandCurrentServer();
  301. result = B_SKIP_MESSAGE;
  302. }
  303. break;
  304. case '/': // bowser muscle memory
  305. // move to the agents parent ServerAgent
  306. // XXX move to WindowList ?
  307. {
  308. winList->SelectServer();
  309. result = B_SKIP_MESSAGE;
  310. }
  311. break;
  312. }
  313. }
  314. if ((keymodifiers & B_OPTION_KEY) == 0
  315. && (keymodifiers & B_COMMAND_KEY) == 0
  316. && (keymodifiers & B_CONTROL_KEY) == 0
  317. && (keymodifiers & B_SHIFT_KEY) == 0)
  318. {
  319. ////////////////////
  320. /// no modifiers ///
  321. ////////////////////
  322. switch (keyStroke[0])
  323. {
  324. case B_UP_ARROW:
  325. {
  326. // used for input history
  327. msgr.SendMessage (M_PREVIOUS_INPUT);
  328. result = B_SKIP_MESSAGE;
  329. }
  330. break;
  331. case B_DOWN_ARROW:
  332. {
  333. // used for input history
  334. msgr.SendMessage (M_NEXT_INPUT);
  335. result = B_SKIP_MESSAGE;
  336. }
  337. break;
  338. case B_PAGE_UP:
  339. {
  340. // scroll the IRCView
  341. BRect myrect (fWindow->fText->Bounds());
  342. float height (myrect.bottom - myrect.top - 10.0);
  343. if (fWindow->fTextScroll->ScrollBar (B_VERTICAL)->Value() > height)
  344. fWindow->fText->ScrollBy (0.0, -1 * height);
  345. else
  346. fWindow->fText->ScrollTo (0.0, 0.0);
  347. result = B_SKIP_MESSAGE;
  348. }
  349. break;
  350. case B_PAGE_DOWN:
  351. {
  352. // scroll the IRCView
  353. BRect myrect (fWindow->fText->Bounds());
  354. float height (myrect.bottom - myrect.top - 10.0);
  355. float min, max;
  356. fWindow->fTextScroll->ScrollBar (B_VERTICAL)->GetRange (&min, &max);
  357. if (fWindow->fTextScroll->ScrollBar (B_VERTICAL)->Value() != max)
  358. fWindow->fText->ScrollBy (0.0, height);
  359. result = B_SKIP_MESSAGE;
  360. }
  361. break;
  362. case B_ESCAPE:
  363. {
  364. fWindow->fCancelMLPaste = true;
  365. result = B_SKIP_MESSAGE;
  366. }
  367. break;
  368. }
  369. }
  370. else if ((keymodifiers & B_OPTION_KEY) == 0
  371. && (keymodifiers & B_COMMAND_KEY) == 0
  372. && (keymodifiers & B_CONTROL_KEY) != 0
  373. && (keymodifiers & B_SHIFT_KEY) == 0)
  374. {
  375. ////////////
  376. /// Ctrl ///
  377. ////////////
  378. switch (keyStroke[0])
  379. {
  380. case B_UP_ARROW:
  381. {
  382. // scroll the IRCView up by 1 line
  383. if (fWindow->fTextScroll->ScrollBar (B_VERTICAL)->Value() != 0)
  384. {
  385. fWindow->fText->ScrollBy (0.0, vision_app->GetClientFont(F_TEXT)->Size() * -1);
  386. result = B_SKIP_MESSAGE;
  387. }
  388. }
  389. break;
  390. case B_DOWN_ARROW:
  391. {
  392. // scroll the IRCView down by 1 line
  393. float min, max;
  394. fWindow->fTextScroll->ScrollBar (B_VERTICAL)->GetRange (&min, &max);
  395. if (fWindow->fTextScroll->ScrollBar (B_VERTICAL)->Value() != max)
  396. {
  397. fWindow->fText->ScrollBy (0.0, vision_app->GetClientFont(F_TEXT)->Size());
  398. result = B_SKIP_MESSAGE;
  399. }
  400. }
  401. break;
  402. case B_HOME:
  403. {
  404. // scroll to the beginning of the IRCView
  405. fWindow->fText->ScrollTo (0.0, 0.0);
  406. result = B_SKIP_MESSAGE;
  407. }
  408. break;
  409. case B_END:
  410. {
  411. // scroll to the end of the IRCView
  412. float min, max;
  413. fWindow->fTextScroll->ScrollBar (B_VERTICAL)->GetRange (&min, &max);
  414. fWindow->fText->ScrollTo (0.0, max);
  415. result = B_SKIP_MESSAGE;
  416. }
  417. break;
  418. case B_PAGE_UP:
  419. case B_PAGE_DOWN:
  420. {
  421. // scroll the IRCView
  422. BRect myrect (fWindow->fText->Bounds());
  423. float height (myrect.bottom - myrect.top);
  424. if (keyStroke[0] == B_PAGE_UP)
  425. {
  426. if (fWindow->fTextScroll->ScrollBar (B_VERTICAL)->Value() > height)
  427. fWindow->fText->ScrollBy (0.0, -1 * height);
  428. else
  429. fWindow->fText->ScrollTo (0.0, 0.0);
  430. }
  431. else // B_PAGE_DOWN
  432. {
  433. float min, max;
  434. fWindow->fTextScroll->ScrollBar (B_VERTICAL)->GetRange (&min, &max);
  435. if (fWindow->fTextScroll->ScrollBar (B_VERTICAL)->Value() != max)
  436. fWindow->fText->ScrollBy (0.0, height);
  437. }
  438. result = B_SKIP_MESSAGE;
  439. }
  440. break;
  441. // ctrl+u = special control char - ascii 21
  442. case 21:
  443. {
  444. if (fWindow->fInput->TextView()->TextLength())
  445. {
  446. int32 selstart, selfinish;
  447. fWindow->fInput->TextView()->GetSelection (&selstart, &selfinish);
  448. fWindow->fInput->TextView()->Delete (0,
  449. selfinish);
  450. }
  451. result = B_SKIP_MESSAGE;
  452. }
  453. break;
  454. }
  455. }
  456. return result;
  457. }
  458. void
  459. ClientAgentInputFilter::HandleDrop (const char *buffer)
  460. {
  461. BMessage msg (M_SUBMIT_INPUT);
  462. const char *place;
  463. int32 lines (0);
  464. BMessenger msgr (fWindow);
  465. while ((place = strchr (buffer, '\n')))
  466. {
  467. BString str;
  468. str.Append (buffer, place - buffer);
  469. msg.AddString ("data", str.String());
  470. ++lines;
  471. buffer = place + 1;
  472. }
  473. if (*buffer)
  474. {
  475. msg.AddString ("data", buffer);
  476. ++lines;
  477. }
  478. int32 start, finish;
  479. fWindow->fInput->TextView()->GetSelection (&start, &finish);
  480. msg.AddInt32 ("selstart", start);
  481. msg.AddInt32 ("selend", finish);
  482. if (lines > 1)
  483. {
  484. if (true == vision_app->GetBool("Newbie Spam Mode"))
  485. {
  486. BString str;
  487. str += "As if there isn't enough, you ";
  488. str += "are about to add ";
  489. str << lines;
  490. str += " more lines of spam to ";
  491. str += "the internet. How ";
  492. str += "would you like to go about this?";
  493. BAlert *alert (new BAlert (
  494. "Spam",
  495. str.String(),
  496. "Cancel",
  497. "Spam!",
  498. "Single line",
  499. B_WIDTH_FROM_WIDEST,
  500. B_OFFSET_SPACING,
  501. B_WARNING_ALERT));
  502. BMessage *invokeMsg (new BMessage (msg));
  503. BInvoker *invoker (new BInvoker (invokeMsg, msgr));
  504. invokeMsg->AddPointer ("invoker", invoker);
  505. alert->Go (invoker);
  506. }
  507. else
  508. {
  509. msg.AddInt32 ("which", PASTE_MULTI);
  510. msgr.SendMessage (&msg);
  511. }
  512. }
  513. if (lines == 1)
  514. {
  515. msg.AddInt32 ("which", PASTE_SINGLE);
  516. msgr.SendMessage (&msg);
  517. fWindow->fInput->MakeFocus(false);
  518. fWindow->fInput->MakeFocus(true);
  519. }
  520. }