/plugins/Navigator/tags/Navigator-2.0/src/ise/plugin/nav/NavHistoryPopup.java

# · Java · 415 lines · 284 code · 56 blank · 75 comment · 45 complexity · b0b8c8fde0bdce2a16b7cc5b26cb7307 MD5 · raw file

  1. /*
  2. * ChooseTagListPopup.java
  3. * Copyright (c) 2001, 2002 Kenrick Drew, Slava Pestov
  4. *
  5. * This file is part of TagsPlugin
  6. *
  7. * TagsPlugin is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or any later version.
  11. *
  12. * TagsPlugin is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20. *
  21. * $Id: ChooseTagListPopup.java,v 1.10 2004/11/07 15:52:34 orutherfurd Exp $
  22. */
  23. /* This is pretty much ripped from gui/CompleteWord.java */
  24. package ise.plugin.nav;
  25. import java.awt.BorderLayout;
  26. import java.awt.Component;
  27. import java.awt.Dimension;
  28. import java.awt.Point;
  29. import java.awt.Rectangle;
  30. import java.awt.event.*;
  31. import java.util.ArrayList;
  32. import java.util.Collection;
  33. import java.util.Collections;
  34. import java.util.HashSet;
  35. import java.util.List;
  36. import javax.swing.*;
  37. import javax.swing.border.Border;
  38. import javax.swing.border.LineBorder;
  39. import org.gjt.sp.jedit.*;
  40. import org.gjt.sp.jedit.textarea.JEditTextArea;
  41. import org.gjt.sp.jedit.textarea.Selection;
  42. import org.gjt.sp.jedit.gui.KeyEventWorkaround;
  43. // -- for Code2HTML 0.5
  44. //import code2html.Code2HTML;
  45. // -- for Code2HTML 0.6
  46. import code2html.generic.GenericExporter;
  47. import code2html.services.ExporterProvider;
  48. class NavHistoryPopup extends JPopupMenu {
  49. private JList list;
  50. private View view;
  51. private NavPosition initialPosition = null;
  52. private boolean numberKeyProcessed = false;
  53. private Navigator navigator = null;
  54. private boolean useCSS = false;
  55. private boolean showGutter = false;
  56. public NavHistoryPopup( View view, Navigator navigator, Collection<NavPosition> positions ) {
  57. this( view, navigator, positions, null );
  58. }
  59. public NavHistoryPopup( View view, Navigator navigator, Collection<NavPosition> positions, NavPosition currentPosition ) {
  60. if (positions == null || positions.size() == 0) {
  61. return;
  62. }
  63. this.navigator = navigator;
  64. this.view = view;
  65. initialPosition = currentPosition;
  66. // positions is a Stack, so need to reverse the order
  67. positions = new ArrayList<NavPosition>( positions );
  68. Collections.reverse( ( List ) positions );
  69. // create components
  70. JPanel contents = new JPanel( new BorderLayout() );
  71. if ( NavigatorPlugin.groupByFile() ) {
  72. positions = groupByFile( positions );
  73. }
  74. list = new JList( positions.toArray() );
  75. list.setCellRenderer( new CellRenderer() );
  76. list.setVisibleRowCount( jEdit.getIntegerProperty( "navigator.listSize", 10 ) );
  77. list.addMouseListener( new MouseHandler() );
  78. JScrollPane scroller = new JScrollPane( list );
  79. contents.add( scroller, BorderLayout.CENTER );
  80. // place components
  81. add( scroller );
  82. // add listeners
  83. KeyHandler keyHandler = new KeyHandler();
  84. addKeyListener( keyHandler );
  85. list.addKeyListener( keyHandler );
  86. this.view.setKeyEventInterceptor( keyHandler );
  87. // set Code2Html properties, don't want to use css, do want to show
  88. // the gutter since that gives us line numbers.
  89. useCSS = jEdit.getBooleanProperty( "code2html.use-css", false );
  90. showGutter = jEdit.getBooleanProperty( "code2html.show-gutter", true );
  91. jEdit.setBooleanProperty( "code2html.use-css", false );
  92. jEdit.setBooleanProperty( "code2html.show-gutter", true );
  93. // show components
  94. pack();
  95. setLocation();
  96. setVisible( true );
  97. list.requestFocus();
  98. if ( currentPosition != null ) {
  99. list.setSelectedValue( currentPosition, true );
  100. }
  101. }
  102. private Collection<NavPosition> groupByFile( Collection<NavPosition> positions ) {
  103. List<NavPosition> items = new ArrayList<NavPosition>( positions.size() );
  104. HashSet<String> paths = new HashSet<String>();
  105. for ( NavPosition pos: positions ) {
  106. if ( paths.add( pos.path ) ) {
  107. items.add( pos );
  108. }
  109. }
  110. return items;
  111. }
  112. /**
  113. * Set the location of the popup on the screen.
  114. */
  115. public void setLocation() {
  116. JEditTextArea textArea = view.getTextArea();
  117. int caretLine = textArea.getCaretLine();
  118. textArea.getLineStartOffset( caretLine );
  119. Rectangle rect = view.getGraphicsConfiguration().getBounds();
  120. Dimension d = getSize();
  121. Point location = new Point( rect.x + ( rect.width - d.width ) / 2,
  122. rect.y + ( rect.height - d.height ) / 2 );
  123. // make sure it fits on screen
  124. Dimension screenSize = rect.getSize();
  125. if ( location.x + d.width > screenSize.width ) {
  126. if ( d.width >= screenSize.width ) {
  127. /* In this instance we should actually resize the number of columns in
  128. * the tag index filename, but for now just position it so that you
  129. * can at least read the left side of the dialog
  130. */
  131. location.x = rect.x;
  132. }
  133. else {
  134. location.x = rect.x + rect.width - d.width - 200;
  135. }
  136. }
  137. if ( location.y + d.height > screenSize.height ) {
  138. location.y = screenSize.height - d.height;
  139. }
  140. setLocation( location );
  141. textArea = null;
  142. location = null;
  143. d = null;
  144. screenSize = null;
  145. }
  146. public void dispose() {
  147. // restore Code2Html properties to original values
  148. jEdit.setBooleanProperty( "code2html.use-css", useCSS );
  149. jEdit.setBooleanProperty( "code2html.show-gutter", showGutter );
  150. view.setKeyEventInterceptor( null );
  151. setVisible( false );
  152. view.getTextArea().requestFocus();
  153. }
  154. private void selected() {
  155. NavPosition item = ( ( NavPosition ) list.getSelectedValue() );
  156. navigator.jump( item );
  157. dispose();
  158. }
  159. class KeyHandler extends KeyAdapter {
  160. public void keyTyped( KeyEvent evt ) {
  161. evt = KeyEventWorkaround.processKeyEvent( evt );
  162. if ( evt == null )
  163. return ;
  164. switch ( evt.getKeyChar() ) {
  165. case '1':
  166. case '2':
  167. case '3':
  168. case '4':
  169. case '5':
  170. case '6':
  171. case '7':
  172. case '8':
  173. case '9':
  174. if ( numberKeyProcessed ) // Since many components have this handler
  175. return ;
  176. /* There may actually be more than 9 items in the list, but since
  177. * the user would have to scroll to see them either with the mouse
  178. * or with the arrow keys, then they can select the item they want
  179. * with those means.
  180. */
  181. int selected = Character.getNumericValue( evt.getKeyChar() ) - 1;
  182. if ( selected >= 0 &&
  183. selected < list.getModel().getSize() ) {
  184. list.setSelectedIndex( selected );
  185. selected();
  186. numberKeyProcessed = true;
  187. }
  188. evt.consume();
  189. }
  190. evt = null;
  191. }
  192. public void keyPressed( KeyEvent evt ) {
  193. evt = KeyEventWorkaround.processKeyEvent( evt );
  194. if ( evt == null )
  195. return ;
  196. switch ( evt.getKeyCode() ) {
  197. case KeyEvent.VK_TAB:
  198. case KeyEvent.VK_ENTER:
  199. selected();
  200. evt.consume();
  201. break;
  202. case KeyEvent.VK_ESCAPE:
  203. dispose();
  204. evt.consume();
  205. break;
  206. case KeyEvent.VK_UP:
  207. int selected = list.getSelectedIndex();
  208. if ( selected == 0 )
  209. selected = list.getModel().getSize() - 1;
  210. //else if ( getFocusOwner() == list )
  211. // return ; // Let JList handle the event
  212. else
  213. selected = selected - 1;
  214. list.setSelectedIndex( selected );
  215. list.ensureIndexIsVisible( selected );
  216. evt.consume();
  217. break;
  218. case KeyEvent.VK_DOWN:
  219. selected = list.getSelectedIndex();
  220. if ( selected == list.getModel().getSize() - 1 )
  221. selected = 0;
  222. //else if ( getFocusOwner() == list )
  223. // return ; // Let JList handle the event
  224. else
  225. selected = selected + 1;
  226. list.setSelectedIndex( selected );
  227. list.ensureIndexIsVisible( selected );
  228. evt.consume();
  229. break;
  230. case KeyEvent.VK_SPACE:
  231. case KeyEvent.VK_1:
  232. case KeyEvent.VK_2:
  233. case KeyEvent.VK_3:
  234. case KeyEvent.VK_4:
  235. case KeyEvent.VK_5:
  236. case KeyEvent.VK_6:
  237. case KeyEvent.VK_7:
  238. case KeyEvent.VK_8:
  239. case KeyEvent.VK_9:
  240. evt.consume(); /* so that we don't automatically dismiss */
  241. break;
  242. case KeyEvent.VK_PAGE_UP:
  243. case KeyEvent.VK_PAGE_DOWN:
  244. break;
  245. default:
  246. dispose();
  247. evt.consume();
  248. break;
  249. }
  250. evt = null;
  251. }
  252. }
  253. class MouseHandler extends MouseAdapter {
  254. public void mouseClicked( MouseEvent evt ) {
  255. selected();
  256. }
  257. }
  258. // A cell renderer that will show html. Delegates to the Code2HTML plugin
  259. // to show the line preview with proper syntax highlighting.
  260. class CellRenderer extends JLabel implements ListCellRenderer {
  261. private Border defaultBorder = BorderFactory.createEmptyBorder( 1, 1, 6, 1 );
  262. private Border initialPositionBorder = BorderFactory.createCompoundBorder( new LineBorder( getForeground() ) , defaultBorder );
  263. public CellRenderer() {
  264. setBorder( defaultBorder );
  265. }
  266. public Component getListCellRendererComponent(
  267. JList list,
  268. Object value, // value to display
  269. int index, // cell index
  270. boolean isSelected, // is the cell selected
  271. boolean cellHasFocus ) // the list and the cell have the focus
  272. {
  273. NavPosition pos = ( NavPosition ) value;
  274. if ( pos == null ) {
  275. return null;
  276. }
  277. String labelText = pos.toString();
  278. if ( jEdit.getBooleanProperty( "navigator.showLineText", true ) ) {
  279. EditPane editPane = null;
  280. for ( EditPane ep : view.getEditPanes() ) {
  281. if ( ep.hashCode() == pos.editPane ) {
  282. editPane = ep;
  283. break;
  284. }
  285. }
  286. if ( editPane == null || !jEdit.getBooleanProperty( "navigator.showLineTextSyntax", true ) ) {
  287. labelText = pos.toHtml(); // non-syntax highlighted html
  288. }
  289. else {
  290. // Have Code2HTML plugin create syntax highlighted html.
  291. // First, create a selection for the text of the line
  292. Buffer[] buffers = editPane.getBufferSet().getAllBuffers();
  293. Buffer buffer = null;
  294. for ( Buffer b : buffers ) {
  295. if ( b.getPath().equals( pos.path ) ) {
  296. buffer = b;
  297. break;
  298. }
  299. }
  300. if ( buffer == null ) {
  301. labelText = pos.toHtml();
  302. }
  303. else {
  304. int start = buffer.getLineStartOffset( pos.lineno );
  305. int end = buffer.getLineEndOffset( pos.lineno );
  306. Selection selection = new Selection.Rect( pos.lineno, start, pos.lineno, end );
  307. Selection[] selections = new Selection[ 1 ];
  308. selections[ 0 ] = selection;
  309. // Have code2html do the syntax highlighting
  310. // -- this is for Code2HTML 0.5:
  311. /*
  312. Code2HTML c2h = new Code2HTML(
  313. buffer,
  314. editPane.getTextArea().getPainter().getStyles(),
  315. selections
  316. );
  317. labelText = c2h.getHtmlString();
  318. */
  319. // -- this is for Code2HTML 0.6:
  320. GenericExporter exporter = ( GenericExporter ) ( ( ExporterProvider ) ServiceManager.getService( "code2html.services.ExporterProvider", "html" ) ).getExporter(
  321. buffer,
  322. editPane.getTextArea().getPainter().getStyles(),
  323. selections
  324. );
  325. labelText = exporter.getContentString();
  326. // clean up the output from code2html, it outputs html, head, and body tags,
  327. // I just want what is between the pre tags
  328. // -- next line can be removed with Code2HTML 0.6 since the getContentString method
  329. // will return only the <pre>...</pre> content.
  330. //labelText = labelText.substring( labelText.indexOf( "<pre>" ), labelText.lastIndexOf( "</pre>" ) + "</pre>".length() );
  331. // reduce multiple spaces to single space
  332. while ( labelText.indexOf( " " ) > -1 ) {
  333. labelText = labelText.replaceAll( " ", " " );
  334. }
  335. // remove line separators. Code2HTML only outputs \n, not \r.
  336. labelText = labelText.replaceAll( "\n", "" );
  337. // add on the path, followed by the syntax highlighted line. The line number
  338. // is provided by code2html, that's why the useGutter property is set to true.
  339. labelText = "<html><tt>" + pos.path + ":</tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + labelText.trim() ;
  340. }
  341. }
  342. }
  343. setText( labelText );
  344. setEnabled( list.isEnabled() );
  345. setFont( list.getFont() );
  346. setOpaque( true );
  347. setBackground( view.getBackground() );
  348. if ( jEdit.getBooleanProperty( "navigator.showStripes", true ) && index % 2 == 0 ) {
  349. setBackground( getBackground().darker() );
  350. }
  351. if ( isSelected ) {
  352. setBackground( list.getSelectionBackground() );
  353. setForeground( list.getSelectionForeground() );
  354. }
  355. setBorder( pos.equals( initialPosition ) ? initialPositionBorder : defaultBorder );
  356. return this;
  357. }
  358. }
  359. }