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.

TextFrame.java 37KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  1. /*
  2. * Copyright (c) 2006-2010 Chris Smith, Shane Mc Cormack, Gregory Holmes
  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.addons.ui_swing.components.frames;
  23. import com.dmdirc.FrameContainer;
  24. import com.dmdirc.actions.ActionManager;
  25. import com.dmdirc.actions.CoreActionType;
  26. import com.dmdirc.addons.ui_swing.SwingController;
  27. import com.dmdirc.addons.ui_swing.UIUtilities;
  28. import com.dmdirc.addons.ui_swing.actions.ChannelCopyAction;
  29. import com.dmdirc.addons.ui_swing.actions.CommandAction;
  30. import com.dmdirc.addons.ui_swing.actions.HyperlinkCopyAction;
  31. import com.dmdirc.addons.ui_swing.actions.NicknameCopyAction;
  32. import com.dmdirc.addons.ui_swing.actions.SearchAction;
  33. import com.dmdirc.addons.ui_swing.actions.TextPaneCopyAction;
  34. import com.dmdirc.addons.ui_swing.components.LoggingSwingWorker;
  35. import com.dmdirc.addons.ui_swing.components.SwingSearchBar;
  36. import com.dmdirc.addons.ui_swing.textpane.ClickType;
  37. import com.dmdirc.addons.ui_swing.textpane.LineInfo;
  38. import com.dmdirc.addons.ui_swing.textpane.TextPane;
  39. import com.dmdirc.addons.ui_swing.textpane.TextPanePageDownAction;
  40. import com.dmdirc.addons.ui_swing.textpane.TextPanePageUpAction;
  41. import com.dmdirc.commandparser.PopupManager;
  42. import com.dmdirc.commandparser.PopupMenu;
  43. import com.dmdirc.commandparser.PopupMenuItem;
  44. import com.dmdirc.commandparser.PopupType;
  45. import com.dmdirc.commandparser.parsers.GlobalCommandParser;
  46. import com.dmdirc.util.StringTranscoder;
  47. import com.dmdirc.config.ConfigManager;
  48. import com.dmdirc.interfaces.ConfigChangeListener;
  49. import com.dmdirc.interfaces.FrameInfoAdapter;
  50. import com.dmdirc.logger.ErrorLevel;
  51. import com.dmdirc.logger.Logger;
  52. import com.dmdirc.ui.IconManager;
  53. import com.dmdirc.ui.WindowManager;
  54. import com.dmdirc.ui.interfaces.InputWindow;
  55. import com.dmdirc.ui.interfaces.Window;
  56. import com.dmdirc.ui.messages.Formatter;
  57. import com.dmdirc.util.URLHandler;
  58. import java.awt.Dimension;
  59. import java.awt.Point;
  60. import java.awt.event.KeyEvent;
  61. import java.awt.event.KeyListener;
  62. import java.awt.event.MouseEvent;
  63. import java.awt.event.MouseListener;
  64. import java.beans.PropertyChangeEvent;
  65. import java.beans.PropertyChangeListener;
  66. import java.beans.PropertyVetoException;
  67. import java.lang.reflect.Constructor;
  68. import java.lang.reflect.InvocationTargetException;
  69. import java.nio.charset.Charset;
  70. import java.nio.charset.IllegalCharsetNameException;
  71. import java.nio.charset.UnsupportedCharsetException;
  72. import java.util.Date;
  73. import java.util.LinkedList;
  74. import java.util.List;
  75. import java.util.concurrent.atomic.AtomicBoolean;
  76. import javax.swing.BorderFactory;
  77. import javax.swing.JComponent;
  78. import javax.swing.JInternalFrame;
  79. import javax.swing.JMenu;
  80. import javax.swing.JMenuItem;
  81. import javax.swing.JPopupMenu;
  82. import javax.swing.JSeparator;
  83. import javax.swing.KeyStroke;
  84. import javax.swing.SwingUtilities;
  85. import javax.swing.UIManager;
  86. import javax.swing.WindowConstants;
  87. import javax.swing.event.InternalFrameEvent;
  88. import javax.swing.event.InternalFrameListener;
  89. import javax.swing.plaf.basic.BasicInternalFrameUI;
  90. import javax.swing.plaf.synth.SynthLookAndFeel;
  91. /**
  92. * Implements a generic (internal) frame.
  93. */
  94. public abstract class TextFrame extends JInternalFrame implements Window,
  95. PropertyChangeListener, InternalFrameListener,
  96. MouseListener, KeyListener, ConfigChangeListener {
  97. /** Logger to use. */
  98. private static final java.util.logging.Logger LOGGER =
  99. java.util.logging.Logger.getLogger(TextFrame.class.getName());
  100. /**
  101. * A version number for this class. It should be changed whenever the class
  102. * structure is changed (or anything else that would prevent serialized
  103. * objects being unserialized with the new class).
  104. */
  105. private static final long serialVersionUID = 5;
  106. /** The channel object that owns this frame. */
  107. protected final FrameContainer frameParent;
  108. /** Frame output pane. */
  109. private TextPane textPane;
  110. /** search bar. */
  111. private SwingSearchBar searchBar;
  112. /** String transcoder. */
  113. private StringTranscoder transcoder;
  114. /** Frame buffer size. */
  115. private int frameBufferSize;
  116. /** Quick copy? */
  117. private boolean quickCopy;
  118. /** Are we closing? */
  119. private boolean closing = false;
  120. /** Input window for popup commands. */
  121. private Window inputWindow;
  122. /** Swing controller. */
  123. private SwingController controller;
  124. /** Are we maximising/restoring? */
  125. private AtomicBoolean maximiseRestoreInProgress = new AtomicBoolean(false);
  126. /** Click types. */
  127. public enum MouseClickType {
  128. /** Clicked. */
  129. CLICKED,
  130. /** Released. */
  131. RELEASED,
  132. /** Pressed. */
  133. PRESSED,
  134. }
  135. /**
  136. * Creates a new instance of Frame.
  137. *
  138. * @param owner FrameContainer owning this frame.
  139. * @param controller Swing controller
  140. */
  141. public TextFrame(final FrameContainer owner,
  142. final SwingController controller) {
  143. super();
  144. this.controller = controller;
  145. frameParent = owner;
  146. final ConfigManager config = owner.getConfigManager();
  147. frameBufferSize = config.getOptionInt("ui", "frameBufferSize");
  148. quickCopy = config.getOptionBool("ui", "quickCopy");
  149. setFrameIcon(IconManager.getIconManager().getIcon(owner.getIcon()));
  150. owner.addFrameInfoListener(new FrameInfoAdapter() {
  151. /** {@inheritDoc} */
  152. @Override
  153. public void iconChanged(final Window window, final String icon) {
  154. setFrameIcon(IconManager.getIconManager().getIcon(icon));
  155. }
  156. });
  157. try {
  158. transcoder = new StringTranscoder(Charset.forName(
  159. config.getOption("channel", "encoding")));
  160. } catch (UnsupportedCharsetException ex) {
  161. transcoder = new StringTranscoder(Charset.forName("UTF-8"));
  162. } catch (IllegalCharsetNameException ex) {
  163. transcoder = new StringTranscoder(Charset.forName("UTF-8"));
  164. } catch (IllegalArgumentException ex) {
  165. transcoder = new StringTranscoder(Charset.forName("UTF-8"));
  166. }
  167. inputWindow = this;
  168. while (!(inputWindow instanceof InputWindow) && inputWindow != null) {
  169. inputWindow = WindowManager.getParent(inputWindow);
  170. }
  171. initComponents();
  172. setMaximizable(true);
  173. setClosable(true);
  174. setResizable(true);
  175. setIconifiable(true);
  176. setFocusable(true);
  177. setPreferredSize(new Dimension(controller.getMainFrame().getWidth() /
  178. 2, controller.getMainFrame().getHeight() / 3));
  179. setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
  180. addPropertyChangeListener("UI", this);
  181. addInternalFrameListener(this);
  182. getTextPane().setBackground(config.getOptionColour("ui",
  183. "backgroundcolour"));
  184. getTextPane().setForeground(config.getOptionColour("ui",
  185. "foregroundcolour"));
  186. config.addChangeListener("ui", "foregroundcolour", this);
  187. config.addChangeListener("ui", "backgroundcolour", this);
  188. config.addChangeListener("ui", "quickCopy", this);
  189. config.addChangeListener("ui", "frameBufferSize", this);
  190. addPropertyChangeListener("maximum", this);
  191. }
  192. /**
  193. * Returns this text frames swing controller.
  194. *
  195. * @return Swing controller
  196. */
  197. public SwingController getController() {
  198. return controller;
  199. }
  200. /** {@inheritDoc} */
  201. @Override
  202. public void setTitle(final String title) {
  203. UIUtilities.invokeLater(new Runnable() {
  204. /** {@inheritDoc} */
  205. @Override
  206. public void run() {
  207. TextFrame.super.setTitle(title);
  208. }
  209. });
  210. }
  211. /** {@inheritDoc} */
  212. @Override
  213. public void setVisible(final boolean isVisible) {
  214. UIUtilities.invokeLater(new Runnable() {
  215. @Override
  216. public void run() {
  217. if (isVisible() && isVisible) {
  218. open();
  219. } else {
  220. TextFrame.super.setVisible(isVisible);
  221. }
  222. }
  223. });
  224. }
  225. /** {@inheritDoc} */
  226. @Override
  227. public void open() {
  228. final boolean pref = frameParent.getConfigManager().getOptionBool("ui",
  229. "maximisewindows");
  230. UIUtilities.invokeLater(new Runnable() {
  231. @Override
  232. public void run() {
  233. if (!isVisible()) {
  234. TextFrame.super.setVisible(true);
  235. }
  236. try {
  237. if (pref || controller.getMainFrame().getMaximised()) {
  238. if (!isMaximum()) {
  239. setMaximum(true);
  240. }
  241. }
  242. } catch (PropertyVetoException ex) {
  243. //Ignore
  244. }
  245. try {
  246. if (!isSelected()) {
  247. setSelected(true);
  248. }
  249. } catch (PropertyVetoException ex) {
  250. //Ignore
  251. }
  252. }
  253. });
  254. }
  255. /** {@inheritDoc} */
  256. @Override
  257. public void activateFrame() {
  258. UIUtilities.invokeLater(new Runnable() {
  259. @Override
  260. public void run() {
  261. try {
  262. if (isIcon()) {
  263. setIcon(false);
  264. }
  265. if (!isVisible()) {
  266. TextFrame.super.setVisible(true);
  267. }
  268. if (!isSelected()) {
  269. setSelected(true);
  270. }
  271. } catch (PropertyVetoException ex) {
  272. //Ignore
  273. }
  274. }
  275. });
  276. }
  277. /** Closes this frame. */
  278. @Override
  279. public void close() {
  280. UIUtilities.invokeLater(new Runnable() {
  281. @Override
  282. public void run() {
  283. if (closing) {
  284. return;
  285. }
  286. closing = true;
  287. try {
  288. if (!isClosed()) {
  289. setClosed(true);
  290. }
  291. } catch (PropertyVetoException ex) {
  292. Logger.userError(ErrorLevel.LOW, "Unable to close frame");
  293. }
  294. }
  295. });
  296. }
  297. /** {@inheritDoc} */
  298. @Override
  299. public void minimise() {
  300. UIUtilities.invokeLater(new Runnable() {
  301. @Override
  302. public void run() {
  303. try {
  304. if (!isIcon()) {
  305. setIcon(true);
  306. }
  307. } catch (PropertyVetoException ex) {
  308. Logger.userError(ErrorLevel.LOW, "Unable to minimise frame");
  309. }
  310. }
  311. });
  312. }
  313. /** {@inheritDoc} */
  314. @Override
  315. public void maximise() {
  316. LOGGER.finest("maximise(): About to invokeAndWait");
  317. UIUtilities.invokeLater(new Runnable() {
  318. /** {@inheritDoc} */
  319. @Override
  320. public void run() {
  321. LOGGER.finest("maximise(): Running");
  322. try {
  323. if (isMaximum()) {
  324. return;
  325. }
  326. maximiseRestoreInProgress.set(true);
  327. LOGGER.finest("maximise(): About to set icon");
  328. if (isIcon()) {
  329. setIcon(false);
  330. }
  331. LOGGER.finest("maximise(): About to set maximum");
  332. setMaximum(true);
  333. LOGGER.finest("maximise(): Done?");
  334. } catch (PropertyVetoException ex) {
  335. Logger.userError(ErrorLevel.LOW, "Unable to minimise frame");
  336. }
  337. maximiseRestoreInProgress.set(false);
  338. LOGGER.finest("maximise(): Done running");
  339. }
  340. });
  341. LOGGER.finest("maximise(): Done");
  342. }
  343. /** {@inheritDoc} */
  344. @Override
  345. public void restore() {
  346. UIUtilities.invokeLater(new Runnable() {
  347. /** {@inheritDoc} */
  348. @Override
  349. public void run() {
  350. try {
  351. if (!isMaximum()) {
  352. return;
  353. }
  354. maximiseRestoreInProgress.set(true);
  355. if (isIcon()) {
  356. setIcon(false);
  357. }
  358. setMaximum(false);
  359. } catch (PropertyVetoException ex) {
  360. Logger.userError(ErrorLevel.LOW, "Unable to minimise frame");
  361. }
  362. maximiseRestoreInProgress.set(false);
  363. }
  364. });
  365. }
  366. /** {@inheritDoc} */
  367. @Override
  368. public void toggleMaximise() {
  369. UIUtilities.invokeLater(new Runnable() {
  370. /** {@inheritDoc} */
  371. @Override
  372. public void run() {
  373. if (isMaximum()) {
  374. restore();
  375. } else {
  376. maximise();
  377. }
  378. }
  379. });
  380. }
  381. /** {@inheritDoc} */
  382. @Override
  383. public final void addLine(final String line, final boolean timestamp) {
  384. final String encodedLine = transcoder.decode(line);
  385. UIUtilities.invokeLater(new Runnable() {
  386. /** {@inheritDoc} */
  387. @Override
  388. public void run() {
  389. final List<String[]> lines = new LinkedList<String[]>();
  390. for (final String myLine : encodedLine.split("\n")) {
  391. if (timestamp) {
  392. lines.add(new String[]{
  393. Formatter.formatMessage(getConfigManager(),
  394. "timestamp", new Date()), myLine,});
  395. } else {
  396. lines.add(new String[]{myLine,});
  397. }
  398. new LoggingSwingWorker() {
  399. /** {@inheritDoc} */
  400. @Override
  401. protected Object doInBackground() throws Exception {
  402. ActionManager.processEvent(
  403. CoreActionType.CLIENT_LINE_ADDED,
  404. null, getContainer(), myLine);
  405. return null;
  406. }
  407. }.execute();
  408. }
  409. textPane.getDocument().addText(lines);
  410. if (frameBufferSize > 0) {
  411. textPane.trim(frameBufferSize);
  412. }
  413. }
  414. });
  415. }
  416. /** {@inheritDoc} */
  417. @Override
  418. public final void addLine(final String messageType,
  419. final Object... args) {
  420. if (!messageType.isEmpty()) {
  421. addLine(Formatter.formatMessage(getConfigManager(), messageType,
  422. args), true);
  423. }
  424. }
  425. /** {@inheritDoc} */
  426. @Override
  427. public final void addLine(final StringBuffer messageType,
  428. final Object... args) {
  429. if (messageType != null) {
  430. addLine(messageType.toString(), args);
  431. }
  432. }
  433. /** {@inheritDoc} */
  434. @Override
  435. public final void clear() {
  436. UIUtilities.invokeLater(new Runnable() {
  437. /** {@inheritDoc} */
  438. @Override
  439. public void run() {
  440. getTextPane().clear();
  441. }
  442. });
  443. }
  444. /**
  445. * Initialises the components for this frame.
  446. */
  447. private void initComponents() {
  448. setTextPane(new TextPane(getContainer()));
  449. getTextPane().addMouseListener(this);
  450. getTextPane().addKeyListener(this);
  451. searchBar = new SwingSearchBar(this, controller.getMainFrame());
  452. searchBar.setVisible(false);
  453. searchBar.addKeyListener(this);
  454. getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).
  455. put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0),
  456. "pageUpAction");
  457. getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).
  458. put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
  459. "pageDownAction");
  460. getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).
  461. put(KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0), "searchAction");
  462. getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).
  463. put(KeyStroke.getKeyStroke(KeyEvent.VK_F,
  464. UIUtilities.getCtrlDownMask()), "searchAction");
  465. getActionMap().put("pageUpAction",
  466. new TextPanePageUpAction(getTextPane()));
  467. getActionMap().put("pageDownAction",
  468. new TextPanePageDownAction(getTextPane()));
  469. getActionMap().put("searchAction", new SearchAction(searchBar));
  470. }
  471. /**
  472. * Removes and reinserts the border of an internal frame on maximising.
  473. * {@inheritDoc}
  474. *
  475. * @param event Property change event
  476. */
  477. @Override
  478. public final void propertyChange(final PropertyChangeEvent event) {
  479. LOGGER.finer("Property change: name: " + event.getPropertyName() +
  480. " value: " + event.getOldValue() + "->" + event.getNewValue());
  481. if ("UI".equals(event.getPropertyName())) {
  482. if (isMaximum()) {
  483. hideTitlebar();
  484. }
  485. } else {
  486. if ((Boolean) event.getNewValue()) {
  487. hideTitlebar();
  488. } else {
  489. showTitlebar();
  490. }
  491. }
  492. LOGGER.finest("Done property change");
  493. }
  494. /** Hides the titlebar for this frame. */
  495. private void hideTitlebar() {
  496. UIUtilities.invokeLater(new Runnable() {
  497. /** {@inheritDoc} */
  498. @Override
  499. public void run() {
  500. setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
  501. ((BasicInternalFrameUI) getUI()).setNorthPane(null);
  502. }
  503. });
  504. }
  505. /** Shows the titlebar for this frame. */
  506. private void showTitlebar() {
  507. UIUtilities.invokeLater(new Runnable() {
  508. /** {@inheritDoc} */
  509. @Override
  510. public void run() {
  511. final Class<?> c;
  512. Object temp = null;
  513. Constructor<?> constructor;
  514. final String componentUI = (String) UIManager.get(
  515. "InternalFrameUI");
  516. if ("javax.swing.plaf.synth.SynthLookAndFeel".equals(componentUI)) {
  517. temp = SynthLookAndFeel.createUI(TextFrame.this);
  518. } else {
  519. try {
  520. c = getClass().getClassLoader().loadClass(componentUI);
  521. constructor =
  522. c.getConstructor(new Class[]{
  523. javax.swing.JInternalFrame.class});
  524. temp =
  525. constructor.newInstance(new Object[]{
  526. TextFrame.this});
  527. } catch (ClassNotFoundException ex) {
  528. Logger.appError(ErrorLevel.MEDIUM,
  529. "Unable to readd titlebar",
  530. ex);
  531. } catch (NoSuchMethodException ex) {
  532. Logger.appError(ErrorLevel.MEDIUM,
  533. "Unable to readd titlebar",
  534. ex);
  535. } catch (InstantiationException ex) {
  536. Logger.appError(ErrorLevel.MEDIUM,
  537. "Unable to readd titlebar",
  538. ex);
  539. } catch (IllegalAccessException ex) {
  540. Logger.appError(ErrorLevel.MEDIUM,
  541. "Unable to readd titlebar",
  542. ex);
  543. } catch (InvocationTargetException ex) {
  544. Logger.appError(ErrorLevel.MEDIUM,
  545. "Unable to readd titlebar",
  546. ex);
  547. }
  548. }
  549. setBorder(UIManager.getBorder("InternalFrame.border"));
  550. if (temp == null) {
  551. temp = new BasicInternalFrameUI(TextFrame.this);
  552. }
  553. setUI((BasicInternalFrameUI) temp);
  554. }
  555. });
  556. }
  557. /**
  558. * Not needed for this class. {@inheritDoc}
  559. *
  560. * @param event Internal frame event
  561. */
  562. @Override
  563. public void internalFrameOpened(final InternalFrameEvent event) {
  564. new LoggingSwingWorker() {
  565. /** {@inheritDoc} */
  566. @Override
  567. protected Object doInBackground() throws Exception {
  568. frameParent.windowOpened();
  569. return null;
  570. }
  571. }.execute();
  572. }
  573. /**
  574. * Not needed for this class. {@inheritDoc}
  575. *
  576. * @param event Internal frame event
  577. */
  578. @Override
  579. public void internalFrameClosing(final InternalFrameEvent event) {
  580. new LoggingSwingWorker() {
  581. /** {@inheritDoc} */
  582. @Override
  583. protected Object doInBackground() throws Exception {
  584. frameParent.windowClosing();
  585. return null;
  586. }
  587. }.execute();
  588. }
  589. /**
  590. * Not needed for this class. {@inheritDoc}
  591. *
  592. * @param event Internal frame event
  593. */
  594. @Override
  595. public void internalFrameClosed(final InternalFrameEvent event) {
  596. new LoggingSwingWorker() {
  597. /** {@inheritDoc} */
  598. @Override
  599. protected Object doInBackground() throws Exception {
  600. frameParent.windowClosed();
  601. return null;
  602. }
  603. }.execute();
  604. }
  605. /**
  606. * Makes the internal frame invisible. {@inheritDoc}
  607. *
  608. * @param event Internal frame event
  609. */
  610. @Override
  611. public void internalFrameIconified(final InternalFrameEvent event) {
  612. UIUtilities.invokeLater(new Runnable() {
  613. @Override
  614. public void run() {
  615. event.getInternalFrame().setVisible(false);
  616. }
  617. });
  618. }
  619. /**
  620. * Not needed for this class. {@inheritDoc}
  621. *
  622. * @param event Internal frame event
  623. */
  624. @Override
  625. public void internalFrameDeiconified(final InternalFrameEvent event) {
  626. //Ignore.
  627. }
  628. /**
  629. * Activates the input field on frame focus. {@inheritDoc}
  630. *
  631. * @param event Internal frame event
  632. */
  633. @Override
  634. public void internalFrameActivated(final InternalFrameEvent event) {
  635. LOGGER.finer(getName() + ": internalFrameActivated()");
  636. if (maximiseRestoreInProgress.get()) {
  637. return;
  638. }
  639. new LoggingSwingWorker() {
  640. /** {@inheritDoc} */
  641. @Override
  642. protected Object doInBackground() throws Exception {
  643. LOGGER.finer(getName() +
  644. ": internalFrameActivated(): doInBackground");
  645. frameParent.windowActivated();
  646. return null;
  647. }
  648. }.execute();
  649. }
  650. /**
  651. * Not needed for this class. {@inheritDoc}
  652. *
  653. * @param event Internal frame event
  654. */
  655. @Override
  656. public void internalFrameDeactivated(final InternalFrameEvent event) {
  657. if (maximiseRestoreInProgress.get()) {
  658. return;
  659. }
  660. new LoggingSwingWorker() {
  661. /** {@inheritDoc} */
  662. @Override
  663. protected Object doInBackground() throws Exception {
  664. frameParent.windowDeactivated();
  665. return null;
  666. }
  667. }.execute();
  668. }
  669. /** {@inheritDoc} */
  670. @Override
  671. public FrameContainer getContainer() {
  672. return frameParent;
  673. }
  674. /** {@inheritDoc} */
  675. @Override
  676. public ConfigManager getConfigManager() {
  677. return getContainer().getConfigManager();
  678. }
  679. /**
  680. * Returns the text pane for this frame.
  681. *
  682. * @return Text pane for this frame
  683. */
  684. public final TextPane getTextPane() {
  685. return textPane;
  686. }
  687. /**
  688. * Returns the transcoder for this frame.
  689. *
  690. * @return String transcoder for this frame
  691. */
  692. @Override
  693. public StringTranscoder getTranscoder() {
  694. return transcoder;
  695. }
  696. /** {@inheritDoc} */
  697. @Override
  698. public final String getName() {
  699. if (frameParent == null) {
  700. return "";
  701. }
  702. return frameParent.toString();
  703. }
  704. /**
  705. * Sets the frames text pane.
  706. *
  707. * @param newTextPane new text pane to use
  708. */
  709. protected final void setTextPane(final TextPane newTextPane) {
  710. this.textPane = newTextPane;
  711. }
  712. /**
  713. * {@inheritDoc}
  714. *
  715. * @param mouseEvent Mouse event
  716. */
  717. @Override
  718. public void mouseClicked(final MouseEvent mouseEvent) {
  719. if (mouseEvent.getSource() == getTextPane()) {
  720. processMouseClickEvent(mouseEvent, MouseClickType.CLICKED);
  721. }
  722. }
  723. /**
  724. * {@inheritDoc}
  725. *
  726. * @param mouseEvent Mouse event
  727. */
  728. @Override
  729. public void mousePressed(final MouseEvent mouseEvent) {
  730. processMouseClickEvent(mouseEvent, MouseClickType.PRESSED);
  731. }
  732. /**
  733. * {@inheritDoc}
  734. *
  735. * @param mouseEvent Mouse event
  736. */
  737. @Override
  738. public void mouseReleased(final MouseEvent mouseEvent) {
  739. if (quickCopy && mouseEvent.getSource() == getTextPane()) {
  740. getTextPane().copy();
  741. getTextPane().clearSelection();
  742. }
  743. processMouseClickEvent(mouseEvent, MouseClickType.RELEASED);
  744. }
  745. /**
  746. * {@inheritDoc}
  747. *
  748. * @param mouseEvent Mouse event
  749. */
  750. @Override
  751. public void mouseEntered(final MouseEvent mouseEvent) {
  752. //Ignore.
  753. }
  754. /**
  755. * {@inheritDoc}
  756. *
  757. * @param mouseEvent Mouse event
  758. */
  759. @Override
  760. public void mouseExited(final MouseEvent mouseEvent) {
  761. //Ignore.
  762. }
  763. /**
  764. * Processes every mouse button event to check for a popup trigger.
  765. *
  766. * @param e mouse event
  767. * @param type
  768. */
  769. public void processMouseClickEvent(final MouseEvent e,
  770. final MouseClickType type) {
  771. final Point point = e.getLocationOnScreen();
  772. SwingUtilities.convertPointFromScreen(point, this);
  773. if (e.getSource() == getTextPane() && point != null) {
  774. final LineInfo lineInfo = getTextPane().getClickPosition(textPane.
  775. getMousePosition());
  776. final ClickType clickType = getTextPane().getClickType(lineInfo);
  777. final String attribute = (String) getTextPane().
  778. getAttributeValueAtPoint(lineInfo);
  779. if (e.isPopupTrigger()) {
  780. showPopupMenuInternal(clickType, point, attribute);
  781. } else {
  782. if (type == MouseClickType.CLICKED) {
  783. switch (clickType) {
  784. case CHANNEL:
  785. ActionManager.processEvent(CoreActionType.LINK_CHANNEL_CLICKED, null, attribute);
  786. frameParent.getServer().join(attribute);
  787. break;
  788. case HYPERLINK:
  789. ActionManager.processEvent(CoreActionType.LINK_URL_CLICKED, null, attribute);
  790. URLHandler.getURLHander().launchApp(attribute);
  791. break;
  792. case NICKNAME:
  793. ActionManager.processEvent(CoreActionType.LINK_NICKNAME_CLICKED, null, attribute);
  794. if (getContainer().getServer().hasQuery(attribute)) {
  795. getContainer().getServer().getQuery(attribute).
  796. activateFrame();
  797. } else {
  798. getContainer().getServer().addQuery(attribute);
  799. getContainer().getServer().getQuery(attribute).
  800. show();
  801. }
  802. break;
  803. default:
  804. break;
  805. }
  806. }
  807. }
  808. }
  809. super.processMouseEvent(e);
  810. }
  811. /**
  812. * What popup type should be used for popup menus for nicknames
  813. *
  814. * @return Appropriate popuptype for this frame
  815. */
  816. public abstract PopupType getNicknamePopupType();
  817. /**
  818. * What popup type should be used for popup menus for channels
  819. *
  820. * @return Appropriate popuptype for this frame
  821. */
  822. public abstract PopupType getChannelPopupType();
  823. /**
  824. * What popup type should be used for popup menus for hyperlinks
  825. *
  826. * @return Appropriate popuptype for this frame
  827. */
  828. public abstract PopupType getHyperlinkPopupType();
  829. /**
  830. * What popup type should be used for popup menus for normal clicks
  831. *
  832. * @return Appropriate popuptype for this frame
  833. */
  834. public abstract PopupType getNormalPopupType();
  835. /**
  836. * A method called to add custom popup items.
  837. *
  838. * @param popupMenu Popup menu to add popup items to
  839. */
  840. public abstract void addCustomPopupItems(final JPopupMenu popupMenu);
  841. /**
  842. * Shows a popup menu at the specified point for the specified click type
  843. *
  844. * @param type ClickType Click type
  845. * @param point Point Point of the click
  846. * @param argument Word under the click
  847. */
  848. private void showPopupMenuInternal(final ClickType type,
  849. final Point point,
  850. final String argument) {
  851. final JPopupMenu popupMenu;
  852. switch (type) {
  853. case CHANNEL:
  854. popupMenu = getPopupMenu(getChannelPopupType(), argument);
  855. popupMenu.add(new ChannelCopyAction(argument));
  856. if (popupMenu.getComponentCount() > 1) {
  857. popupMenu.addSeparator();
  858. }
  859. break;
  860. case HYPERLINK:
  861. popupMenu = getPopupMenu(getHyperlinkPopupType(), argument);
  862. popupMenu.add(new HyperlinkCopyAction(argument));
  863. if (popupMenu.getComponentCount() > 1) {
  864. popupMenu.addSeparator();
  865. }
  866. break;
  867. case NICKNAME:
  868. popupMenu = getPopupMenu(getNicknamePopupType(), argument);
  869. if (popupMenu.getComponentCount() > 0) {
  870. popupMenu.addSeparator();
  871. }
  872. popupMenu.add(new NicknameCopyAction(argument));
  873. break;
  874. default:
  875. popupMenu = getPopupMenu(null, argument);
  876. break;
  877. }
  878. popupMenu.add(new TextPaneCopyAction(getTextPane()));
  879. addCustomPopupItems(popupMenu);
  880. popupMenu.show(this, (int) point.getX(), (int) point.getY());
  881. }
  882. /**
  883. * Shows a popup menu at the specified point for the specified click type
  884. *
  885. * @param type ClickType Click type
  886. * @param point Point Point of the click (Must be screen coords)
  887. * @param argument Word under the click
  888. */
  889. public void showPopupMenu(final ClickType type,
  890. final Point point,
  891. final String argument) {
  892. SwingUtilities.convertPointFromScreen(point, this);
  893. final JPopupMenu popupMenu;
  894. switch (type) {
  895. case CHANNEL:
  896. popupMenu = getPopupMenu(getChannelPopupType(), argument);
  897. popupMenu.add(new ChannelCopyAction(argument));
  898. if (popupMenu.getComponentCount() > 1) {
  899. popupMenu.addSeparator();
  900. }
  901. break;
  902. case HYPERLINK:
  903. popupMenu = getPopupMenu(getHyperlinkPopupType(), argument);
  904. popupMenu.add(new HyperlinkCopyAction(argument));
  905. if (popupMenu.getComponentCount() > 1) {
  906. popupMenu.addSeparator();
  907. }
  908. break;
  909. case NICKNAME:
  910. popupMenu = getPopupMenu(getNicknamePopupType(), argument);
  911. if (popupMenu.getComponentCount() > 0) {
  912. popupMenu.addSeparator();
  913. }
  914. popupMenu.add(new NicknameCopyAction(argument));
  915. break;
  916. default:
  917. popupMenu = getPopupMenu(null, argument);
  918. break;
  919. }
  920. popupMenu.show(this, (int) point.getX(), (int) point.getY());
  921. }
  922. /**
  923. * Builds a popup menu of a specified type
  924. *
  925. * @param type type of menu to build
  926. * @param arguments Arguments for the command
  927. *
  928. * @return PopupMenu
  929. */
  930. public JPopupMenu getPopupMenu(
  931. final PopupType type,
  932. final Object... arguments) {
  933. JPopupMenu popupMenu = new JPopupMenu();
  934. if (type != null) {
  935. popupMenu = (JPopupMenu) populatePopupMenu(popupMenu,
  936. PopupManager.getMenu(type, getConfigManager()),
  937. arguments);
  938. }
  939. return popupMenu;
  940. }
  941. /**
  942. * Populates the specified popupmenu
  943. *
  944. * @param menu Menu component
  945. * @param popup Popup to get info from
  946. * @param arguments Arguments for the command
  947. *
  948. * @return Populated popup
  949. */
  950. private JComponent populatePopupMenu(final JComponent menu,
  951. final PopupMenu popup,
  952. final Object... arguments) {
  953. for (PopupMenuItem menuItem : popup.getItems()) {
  954. if (menuItem.isDivider()) {
  955. menu.add(new JSeparator());
  956. } else if (menuItem.isSubMenu()) {
  957. menu.add(populatePopupMenu(new JMenu(menuItem.getName()),
  958. menuItem.getSubMenu(), arguments));
  959. } else {
  960. menu.add(new JMenuItem(new CommandAction(inputWindow == null ? GlobalCommandParser.
  961. getGlobalCommandParser()
  962. : ((InputWindow) inputWindow).getCommandParser(),
  963. (InputWindow) inputWindow, menuItem.getName(),
  964. menuItem.getCommand(arguments))));
  965. }
  966. }
  967. return menu;
  968. }
  969. /**
  970. * {@inheritDoc}
  971. *
  972. * @param event Key event
  973. */
  974. @Override
  975. public void keyTyped(final KeyEvent event) {
  976. //Ignore.
  977. }
  978. /**
  979. * {@inheritDoc}
  980. *
  981. * @param event Key event
  982. */
  983. @Override
  984. public void keyPressed(final KeyEvent event) {
  985. if (!quickCopy && (event.getModifiers() & UIUtilities.getCtrlMask()) !=
  986. 0 &&
  987. event.getKeyCode() == KeyEvent.VK_C) {
  988. getTextPane().copy();
  989. }
  990. }
  991. /**
  992. * {@inheritDoc}
  993. *
  994. * @param event Key event
  995. */
  996. @Override
  997. public void keyReleased(final KeyEvent event) {
  998. //Ignore.
  999. }
  1000. /**
  1001. * Gets the search bar.
  1002. *
  1003. * @return the frames search bar
  1004. */
  1005. public final SwingSearchBar getSearchBar() {
  1006. return searchBar;
  1007. }
  1008. /** {@inheritDoc} */
  1009. @Override
  1010. public void configChanged(final String domain,
  1011. final String key) {
  1012. if (getConfigManager() == null) {
  1013. return;
  1014. }
  1015. if ("ui".equals(domain)) {
  1016. if ("foregroundcolour".equals(key) && getTextPane() != null) {
  1017. getTextPane().setForeground(getConfigManager().
  1018. getOptionColour("ui", "foregroundcolour"));
  1019. } else if ("backgroundcolour".equals(key) && getTextPane() != null) {
  1020. getTextPane().setBackground(getConfigManager().
  1021. getOptionColour("ui", "backgroundcolour"));
  1022. } else if ("frameBufferSize".equals(key)) {
  1023. frameBufferSize = getContainer().getConfigManager().
  1024. getOptionInt("ui", "frameBufferSize");
  1025. } else if ("quickCopy".equals(key)) {
  1026. quickCopy = getContainer().getConfigManager().
  1027. getOptionBool("ui", "quickCopy");
  1028. }
  1029. }
  1030. }
  1031. }