You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FrameContainer.java 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. /*
  2. * Copyright (c) 2006-2014 DMDirc Developers
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc;
  23. import com.dmdirc.actions.ActionManager;
  24. import com.dmdirc.actions.CoreActionType;
  25. import com.dmdirc.commandparser.parsers.CommandParser;
  26. import com.dmdirc.interfaces.Connection;
  27. import com.dmdirc.interfaces.FrameCloseListener;
  28. import com.dmdirc.interfaces.FrameComponentChangeListener;
  29. import com.dmdirc.interfaces.FrameInfoListener;
  30. import com.dmdirc.interfaces.NotificationListener;
  31. import com.dmdirc.interfaces.config.AggregateConfigProvider;
  32. import com.dmdirc.interfaces.config.ConfigChangeListener;
  33. import com.dmdirc.messages.MessageSinkManager;
  34. import com.dmdirc.parser.common.CompositionState;
  35. import com.dmdirc.ui.Colour;
  36. import com.dmdirc.ui.IconManager;
  37. import com.dmdirc.ui.input.TabCompleter;
  38. import com.dmdirc.ui.messages.Formatter;
  39. import com.dmdirc.ui.messages.IRCDocument;
  40. import com.dmdirc.ui.messages.Styliser;
  41. import com.dmdirc.util.URLBuilder;
  42. import com.dmdirc.util.collections.ListenerList;
  43. import com.google.common.base.Optional;
  44. import java.util.ArrayList;
  45. import java.util.Collection;
  46. import java.util.Collections;
  47. import java.util.Date;
  48. import java.util.HashSet;
  49. import java.util.LinkedList;
  50. import java.util.List;
  51. import java.util.Set;
  52. import java.util.concurrent.CopyOnWriteArrayList;
  53. import static com.google.common.base.Preconditions.checkState;
  54. /**
  55. * The frame container implements basic methods that should be present in all objects that handle a
  56. * frame.
  57. */
  58. public abstract class FrameContainer {
  59. /** Listeners not yet using ListenerSupport. */
  60. protected final ListenerList listeners = new ListenerList();
  61. /** The colour of our frame's notifications. */
  62. private Colour notification = Colour.BLACK;
  63. /** The document used to store this container's content. */
  64. private IRCDocument document;
  65. /** The children of this frame. */
  66. private final Collection<FrameContainer> children = new CopyOnWriteArrayList<>();
  67. /** The parent of this frame. */
  68. private FrameContainer parent;
  69. /** The name of the icon being used for this container's frame. */
  70. private String icon;
  71. /** The name of this container. */
  72. private String name;
  73. /** The title of this container. */
  74. private String title;
  75. /** The config manager for this container. */
  76. private final AggregateConfigProvider configManager;
  77. /** The IconChanger for this container. */
  78. private final IconChanger changer = new IconChanger();
  79. /** The UI components that this frame requires. */
  80. private final Set<String> components;
  81. /** The styliser used by this container. */
  82. private Styliser styliser;
  83. /** Object used to synchronise styliser access. */
  84. private final Object styliserSync = new Object();
  85. /** Object used to synchronise styliser access. */
  86. private final Object documentSync = new Object();
  87. /** The icon manager to use for this container. */
  88. private final IconManager iconManager;
  89. /** Whether or not this container is writable. */
  90. private final boolean writable;
  91. /**
  92. * The command parser used for commands in this container.
  93. * <p>
  94. * Only defined if this container is {@link #writable}.
  95. */
  96. private final Optional<CommandParser> commandParser;
  97. /**
  98. * The manager to use to despatch messages to sinks.
  99. * <p>
  100. * Only defined if this container is {@link #writable}.
  101. */
  102. private final Optional<MessageSinkManager> messageSinkManager;
  103. /**
  104. * The tab completer to use.
  105. * <p>
  106. * Only defined if this container is {@link #writable}.
  107. */
  108. private final Optional<TabCompleter> tabCompleter;
  109. /**
  110. * Instantiate new frame container.
  111. *
  112. * @param icon The icon to use for this container
  113. * @param name The name of this container
  114. * @param title The title of this container
  115. * @param config The config manager for this container
  116. * @param urlBuilder The URL builder to use when finding icons.
  117. * @param components The UI components that this frame requires
  118. *
  119. * @since 0.6.4
  120. */
  121. protected FrameContainer(
  122. final String icon,
  123. final String name,
  124. final String title,
  125. final AggregateConfigProvider config,
  126. final URLBuilder urlBuilder,
  127. final Collection<String> components) {
  128. this.configManager = config;
  129. this.name = name;
  130. this.title = title;
  131. this.components = new HashSet<>(components);
  132. this.iconManager = new IconManager(configManager, urlBuilder);
  133. this.writable = false;
  134. this.commandParser = Optional.absent();
  135. this.tabCompleter = Optional.absent();
  136. this.messageSinkManager = Optional.absent();
  137. setIcon(icon);
  138. }
  139. /**
  140. * Instantiate new frame container that accepts user input.
  141. *
  142. * @param icon The icon to use for this container
  143. * @param name The name of this container
  144. * @param title The title of this container
  145. * @param config The config manager for this container
  146. * @param urlBuilder The URL builder to use when finding icons.
  147. * @param commandParser The command parser to use for input.
  148. * @param tabCompleter The tab completer to use.
  149. * @param messageSinkManager The manager to use to despatch notifications.
  150. * @param components The UI components that this frame requires
  151. *
  152. * @since 0.6.4
  153. */
  154. protected FrameContainer(
  155. final String icon,
  156. final String name,
  157. final String title,
  158. final AggregateConfigProvider config,
  159. final URLBuilder urlBuilder,
  160. final CommandParser commandParser,
  161. final TabCompleter tabCompleter,
  162. final MessageSinkManager messageSinkManager,
  163. final Collection<String> components) {
  164. this.configManager = config;
  165. this.name = name;
  166. this.title = title;
  167. this.components = new HashSet<>(components);
  168. this.iconManager = new IconManager(configManager, urlBuilder);
  169. this.writable = true;
  170. this.commandParser = Optional.of(commandParser);
  171. this.tabCompleter = Optional.of(tabCompleter);
  172. this.messageSinkManager = Optional.of(messageSinkManager);
  173. commandParser.setOwner(this);
  174. setIcon(icon);
  175. }
  176. public Colour getNotification() {
  177. return notification;
  178. }
  179. public FrameContainer getParent() {
  180. return parent;
  181. }
  182. public String getIcon() {
  183. return icon;
  184. }
  185. public String getName() {
  186. return name;
  187. }
  188. public String getTitle() {
  189. return title;
  190. }
  191. public AggregateConfigProvider getConfigManager() {
  192. return configManager;
  193. }
  194. public boolean isWritable() {
  195. return writable;
  196. }
  197. /**
  198. * Returns a collection of direct children of this frame.
  199. *
  200. * @return This frame's children
  201. *
  202. * @since 0.6.4
  203. */
  204. public Collection<FrameContainer> getChildren() {
  205. return Collections.unmodifiableCollection(children);
  206. }
  207. /**
  208. * Adds a new child window to this frame.
  209. *
  210. * @param child The window to be added
  211. *
  212. * @since 0.6.4
  213. */
  214. public void addChild(final FrameContainer child) {
  215. children.add(child);
  216. child.setParent(this);
  217. }
  218. /**
  219. * Removes a child window from this frame.
  220. *
  221. * @param child The window to be removed
  222. *
  223. * @since 0.6.4
  224. */
  225. public void removeChild(final FrameContainer child) {
  226. children.remove(child);
  227. }
  228. /**
  229. * Sets the parent of this container to the one specified. If this container already had a
  230. * parent, it will deregister itself with the old parent.
  231. *
  232. * @param parent The new parent for this container
  233. *
  234. * @since 0.6.4
  235. */
  236. public synchronized void setParent(final FrameContainer parent) {
  237. if (this.parent != null && (parent == null || !parent.equals(this.parent))) {
  238. this.parent.removeChild(this);
  239. }
  240. this.parent = parent;
  241. }
  242. /**
  243. * Gets an icon manager for this container.
  244. *
  245. * @return An icon manager for this container.
  246. */
  247. public IconManager getIconManager() {
  248. return iconManager;
  249. }
  250. /**
  251. * Retrieves the {@link IRCDocument} used to store this frame's content.
  252. *
  253. * @return This frame's document
  254. *
  255. * @since 0.6.4
  256. */
  257. public IRCDocument getDocument() {
  258. synchronized (documentSync) {
  259. if (document == null) {
  260. document = new IRCDocument(getConfigManager(), getStyliser());
  261. }
  262. return document;
  263. }
  264. }
  265. /**
  266. * Changes the name of this container, and notifies any {@link FrameInfoListener}s of the
  267. * change.
  268. *
  269. * @param name The new name for this frame.
  270. */
  271. protected void setName(final String name) {
  272. this.name = name;
  273. listeners.getCallable(FrameInfoListener.class).nameChanged(this, name);
  274. }
  275. /**
  276. * Changes the title of this container, and notifies any {@link FrameInfoListener}s of the
  277. * change.
  278. *
  279. * @param title The new title for this frame.
  280. */
  281. public void setTitle(final String title) {
  282. this.title = title;
  283. listeners.getCallable(FrameInfoListener.class).titleChanged(this, title);
  284. }
  285. /**
  286. * Returns the collection of UI component identifiers that this frame container requires for its
  287. * display.
  288. *
  289. * @since 0.6.6
  290. * @return Collection of UI component identifiers
  291. */
  292. public Set<String> getComponents() {
  293. return Collections.unmodifiableSet(components);
  294. }
  295. /**
  296. * Adds a new component to this container.
  297. *
  298. * @since 0.6.6
  299. * @param component The component to be added
  300. */
  301. public void addComponent(final String component) {
  302. components.add(component);
  303. for (FrameComponentChangeListener listener
  304. : listeners.get(FrameComponentChangeListener.class)) {
  305. listener.componentAdded(this, component);
  306. }
  307. }
  308. /**
  309. * Removes a component from this container.
  310. *
  311. * @since 0.6.6
  312. * @param component The component to be removed
  313. */
  314. public void removeComponent(final String component) {
  315. components.remove(component);
  316. for (FrameComponentChangeListener listener
  317. : listeners.get(FrameComponentChangeListener.class)) {
  318. listener.componentRemoved(this, component);
  319. }
  320. }
  321. /**
  322. * Closes this container (and it's associated frame).
  323. */
  324. public void close() {
  325. for (FrameCloseListener listener : listeners.get(FrameCloseListener.class)) {
  326. listener.windowClosing(this);
  327. }
  328. }
  329. /**
  330. * Returns the connection that this container is associated with.
  331. *
  332. * @return the associated connection, or {@code null}.
  333. */
  334. public abstract Connection getConnection();
  335. /**
  336. * Sets the icon to be used by this frame container.
  337. *
  338. * @param icon The new icon to be used
  339. */
  340. public final void setIcon(final String icon) {
  341. this.icon = icon;
  342. iconUpdated();
  343. configManager.removeListener(changer);
  344. configManager.addChangeListener("icon", icon, changer);
  345. }
  346. /**
  347. * Called when this container's icon is updated.
  348. */
  349. private void iconUpdated() {
  350. listeners.getCallable(FrameInfoListener.class).iconChanged(this, icon);
  351. }
  352. /**
  353. * Retrieves the styliser which should be used by this container.
  354. *
  355. * @return this container's styliser
  356. */
  357. public Styliser getStyliser() {
  358. synchronized (styliserSync) {
  359. if (styliser == null) {
  360. styliser = new Styliser(getConnection(), getConfigManager());
  361. }
  362. return styliser;
  363. }
  364. }
  365. /**
  366. * Clears any outstanding notifications this frame has set.
  367. */
  368. public void clearNotification() {
  369. // TODO: This should default ot something colour independent
  370. notification = Colour.BLACK;
  371. listeners.getCallable(NotificationListener.class).notificationCleared(this);
  372. }
  373. /**
  374. * Sends a notification to the frame manager if this fame isn't active.
  375. *
  376. * @param colour The colour to use for the notification
  377. */
  378. public void sendNotification(final Colour colour) {
  379. if (!colour.equals(notification)) {
  380. notification = colour;
  381. listeners.getCallable(NotificationListener.class).notificationSet(this, colour);
  382. }
  383. }
  384. /**
  385. * Adds a line to this container's window. If the window is null for some reason, the line is
  386. * silently discarded.
  387. *
  388. * @param type The message type to use
  389. * @param timestamp The timestamp to use for this line
  390. * @param args The message's arguments
  391. *
  392. * @since 0.6.4
  393. */
  394. public void addLine(final String type, final Date timestamp,
  395. final Object... args) {
  396. if (type != null && !type.isEmpty()) {
  397. addLine(Formatter.formatMessage(getConfigManager(), type, args),
  398. timestamp);
  399. }
  400. }
  401. /**
  402. * Adds a line to this container's window. If the window is null for some reason, the line is
  403. * silently discarded.
  404. *
  405. * @param type The message type to use
  406. * @param args The message's arguments
  407. */
  408. public void addLine(final String type, final Object... args) {
  409. addLine(type, new Date(), args);
  410. }
  411. /**
  412. * Adds a line to this container's window. If the window is null for some reason, the line is
  413. * silently discarded.
  414. *
  415. * @param type The message type to use
  416. * @param timestamp The timestamp to use for this line
  417. * @param args The message's arguments
  418. *
  419. * @since 0.6.4
  420. */
  421. public void addLine(final StringBuffer type, final Date timestamp,
  422. final Object... args) {
  423. if (type != null) {
  424. addLine(type.toString(), timestamp, args);
  425. }
  426. }
  427. /**
  428. * Adds a line to this container's window. If the window is null for some reason, the line is
  429. * silently discarded.
  430. *
  431. * @param type The message type to use
  432. * @param args The message's arguments
  433. */
  434. public void addLine(final StringBuffer type, final Object... args) {
  435. addLine(type, new Date(), args);
  436. }
  437. /**
  438. * Adds the specified raw line to the window, without using a formatter.
  439. *
  440. * @param line The line to be added
  441. * @param timestamp Whether or not to display the timestamp for this line
  442. */
  443. public void addLine(final String line, final boolean timestamp) {
  444. addLine(line, timestamp ? new Date() : null);
  445. }
  446. /**
  447. * Adds the specified raw line to the window, without using a formatter, and using the specified
  448. * timestamp. If the timestamp is <code>null</code>, no timestamp is added.
  449. *
  450. * @param line The line to be added
  451. * @param timestamp The timestamp to use for the line
  452. *
  453. * @since 0.6.4
  454. */
  455. public void addLine(final String line, final Date timestamp) {
  456. final List<String[]> lines = new LinkedList<>();
  457. for (final String myLine : line.split("\n")) {
  458. if (timestamp != null) {
  459. lines.add(new String[]{
  460. Formatter.formatMessage(getConfigManager(), "timestamp",
  461. timestamp),
  462. myLine,});
  463. } else {
  464. lines.add(new String[]{myLine});
  465. }
  466. ActionManager.getActionManager().triggerEvent(
  467. CoreActionType.CLIENT_LINE_ADDED, null, this, myLine);
  468. }
  469. getDocument().addText(lines);
  470. }
  471. /**
  472. * Adds a close listener for this frame container.
  473. *
  474. * @since 0.6.5
  475. * @param listener The listener to be added
  476. */
  477. public void addCloseListener(final FrameCloseListener listener) {
  478. listeners.add(FrameCloseListener.class, listener);
  479. }
  480. /**
  481. * Removes a close listener from this frame container.
  482. *
  483. * @since 0.6.5
  484. * @param listener The listener to be removed
  485. */
  486. public void removeCloseListener(final FrameCloseListener listener) {
  487. listeners.remove(FrameCloseListener.class, listener);
  488. }
  489. /**
  490. * Adds a component listener to this container.
  491. *
  492. * @since 0.6.6
  493. * @param listener The listener to be added
  494. */
  495. public void addComponentListener(final FrameComponentChangeListener listener) {
  496. listeners.add(FrameComponentChangeListener.class, listener);
  497. }
  498. /**
  499. * Removes a component listener from this container.
  500. *
  501. * @since 0.6.6
  502. * @param listener The listener to be removed
  503. */
  504. public void removeComponentListener(final FrameComponentChangeListener listener) {
  505. listeners.remove(FrameComponentChangeListener.class, listener);
  506. }
  507. /**
  508. * Adds a notification listener to this container.
  509. *
  510. * @param listener The listener to inform of notification events.
  511. */
  512. public void addNotificationListener(final NotificationListener listener) {
  513. listeners.add(NotificationListener.class, listener);
  514. }
  515. /**
  516. * Removes a notification listener from this container.
  517. *
  518. * @param listener The listener to be removed.
  519. */
  520. public void removeNotificationListener(final NotificationListener listener) {
  521. listeners.remove(NotificationListener.class, listener);
  522. }
  523. /**
  524. * Adds a frame info listener to this container.
  525. *
  526. * @param listener The listener to be informed of frame information changes.
  527. */
  528. public void addFrameInfoListener(final FrameInfoListener listener) {
  529. listeners.add(FrameInfoListener.class, listener);
  530. }
  531. /**
  532. * Removes a frame info listener from this container.
  533. *
  534. * @param listener The listener to be removed.
  535. */
  536. public void removeFrameInfoListener(final FrameInfoListener listener) {
  537. listeners.remove(FrameInfoListener.class, listener);
  538. }
  539. /**
  540. * Sends a line of text to this container's source.
  541. *
  542. * @param line The line to be sent
  543. */
  544. public void sendLine(final String line) {
  545. throw new UnsupportedOperationException("Container doesn't override sendLine");
  546. }
  547. /**
  548. * Retrieves the command parser to be used for this container.
  549. *
  550. * @return This container's command parser
  551. */
  552. public CommandParser getCommandParser() {
  553. checkState(writable);
  554. return commandParser.get();
  555. }
  556. /**
  557. * Retrieves the tab completer which should be used for this cotnainer.
  558. *
  559. * @return This container's tab completer
  560. */
  561. public TabCompleter getTabCompleter() {
  562. checkState(writable);
  563. return tabCompleter.get();
  564. }
  565. /**
  566. * Returns the maximum length that a line passed to sendLine() should be, in order to prevent it
  567. * being truncated or causing protocol violations.
  568. *
  569. * @return The maximum line length for this container
  570. */
  571. public int getMaxLineLength() {
  572. throw new UnsupportedOperationException("Container doesn't override getMaxLineLength");
  573. }
  574. /**
  575. * Splits the specified line into chunks that contain a number of bytes less than or equal to
  576. * the value returned by {@link #getMaxLineLength()}.
  577. *
  578. * @param line The line to be split
  579. *
  580. * @return An ordered list of chunks of the desired length
  581. */
  582. protected List<String> splitLine(final String line) {
  583. final List<String> result = new ArrayList<>();
  584. if (line.indexOf('\n') > -1) {
  585. for (String part : line.split("\n")) {
  586. result.addAll(splitLine(part));
  587. }
  588. } else {
  589. final StringBuilder remaining = new StringBuilder(line);
  590. while (getMaxLineLength() > -1 && remaining.toString().getBytes().length
  591. > getMaxLineLength()) {
  592. int number = Math.min(remaining.length(), getMaxLineLength());
  593. while (remaining.substring(0, number).getBytes().length > getMaxLineLength()) {
  594. number--;
  595. }
  596. result.add(remaining.substring(0, number));
  597. remaining.delete(0, number);
  598. }
  599. result.add(remaining.toString());
  600. }
  601. return result;
  602. }
  603. /**
  604. * Returns the number of lines that the specified string would be sent as.
  605. *
  606. * @param line The string to be split and sent
  607. *
  608. * @return The number of lines required to send the specified string
  609. */
  610. public final int getNumLines(final String line) {
  611. final String[] splitLines = line.split("(\n|\r\n|\r)", Integer.MAX_VALUE);
  612. int lines = 0;
  613. for (String splitLine : splitLines) {
  614. if (getMaxLineLength() <= 0) {
  615. lines++;
  616. } else {
  617. lines += (int) Math.ceil(splitLine.getBytes().length
  618. / (double) getMaxLineLength());
  619. }
  620. }
  621. return lines;
  622. }
  623. /**
  624. * Processes and displays a notification.
  625. *
  626. * @param messageType The name of the formatter to be used for the message
  627. * @param args The arguments for the message
  628. *
  629. * @return True if any further behaviour should be executed, false otherwise
  630. */
  631. public boolean doNotification(final String messageType, final Object... args) {
  632. return doNotification(new Date(), messageType, args);
  633. }
  634. /**
  635. * Processes and displays a notification.
  636. *
  637. * @param date The date/time at which the event occured
  638. * @param messageType The name of the formatter to be used for the message
  639. * @param args The arguments for the message
  640. *
  641. * @return True if any further behaviour should be executed, false otherwise
  642. */
  643. public boolean doNotification(final Date date, final String messageType, final Object... args) {
  644. final List<Object> messageArgs = new ArrayList<>();
  645. final List<Object> actionArgs = new ArrayList<>();
  646. final StringBuffer buffer = new StringBuffer(messageType);
  647. actionArgs.add(this);
  648. for (Object arg : args) {
  649. actionArgs.add(arg);
  650. if (!processNotificationArg(arg, messageArgs)) {
  651. messageArgs.add(arg);
  652. }
  653. }
  654. modifyNotificationArgs(actionArgs, messageArgs);
  655. handleNotification(date, buffer.toString(), messageArgs.toArray());
  656. return true;
  657. }
  658. /**
  659. * Allows subclasses to modify the lists of arguments for notifications.
  660. *
  661. * @param actionArgs The list of arguments to be passed to the actions system
  662. * @param messageArgs The list of arguments to be passed to the formatter
  663. */
  664. protected void modifyNotificationArgs(final List<Object> actionArgs,
  665. final List<Object> messageArgs) {
  666. // Do nothing
  667. }
  668. /**
  669. * Allows subclasses to process specific types of notification arguments.
  670. *
  671. * @param arg The argument to be processed
  672. * @param args The list of arguments that any data should be appended to
  673. *
  674. * @return True if the arg has been processed, false otherwise
  675. */
  676. protected boolean processNotificationArg(final Object arg, final List<Object> args) {
  677. return false;
  678. }
  679. /**
  680. * Handles general server notifications (i.e., ones not tied to a specific window). The user can
  681. * select where the notifications should go in their config.
  682. *
  683. * @param messageType The type of message that is being sent
  684. * @param args The arguments for the message
  685. */
  686. public void handleNotification(final String messageType, final Object... args) {
  687. handleNotification(new Date(), messageType, args);
  688. }
  689. /**
  690. * Handles general server notifications (i.e., ones not tied to a specific window). The user can
  691. * select where the notifications should go in their config.
  692. *
  693. * @param date The date/time at which the event occured
  694. * @param messageType The type of message that is being sent
  695. * @param args The arguments for the message
  696. */
  697. public void handleNotification(final Date date, final String messageType, final Object... args) {
  698. checkState(writable);
  699. messageSinkManager.get().despatchMessage(this, date, messageType, args);
  700. }
  701. /**
  702. * Sets the composition state for the local user for this chat.
  703. *
  704. * @param state The new composition state
  705. */
  706. public void setCompositionState(final CompositionState state) {
  707. // Default implementation does nothing. Subclasses that support
  708. // composition should override this.
  709. }
  710. /**
  711. * Updates the icon of this frame if its config setting is changed.
  712. */
  713. private class IconChanger implements ConfigChangeListener {
  714. @Override
  715. public void configChanged(final String domain, final String key) {
  716. iconUpdated();
  717. }
  718. }
  719. }