/jEdit/tags/jedit-4-3-1/org/gjt/sp/jedit/browser/BrowserView.java

# · Java · 742 lines · 552 code · 78 blank · 112 comment · 106 complexity · 9a99f00f49b4330edd2646454e142e6f MD5 · raw file

  1. /*
  2. * BrowserView.java
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2003 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit.browser;
  23. //{{{ Imports
  24. import javax.swing.border.EmptyBorder;
  25. import javax.swing.event.*;
  26. import javax.swing.*;
  27. import java.awt.event.*;
  28. import java.awt.*;
  29. import java.io.File;
  30. import java.io.IOException;
  31. import java.util.*;
  32. import org.gjt.sp.jedit.gui.DockableWindowManager;
  33. import org.gjt.sp.jedit.io.*;
  34. import org.gjt.sp.jedit.*;
  35. import org.gjt.sp.util.Log;
  36. //}}}
  37. /**
  38. * VFS browser tree view.
  39. * @author Slava Pestov
  40. * @version $Id: BrowserView.java 16560 2009-11-29 19:06:17Z kerik-sf $
  41. */
  42. class BrowserView extends JPanel
  43. {
  44. //{{{ BrowserView constructor
  45. BrowserView(final VFSBrowser browser)
  46. {
  47. this.browser = browser;
  48. tmpExpanded = new HashSet<String>();
  49. DockableWindowManager dwm = jEdit.getActiveView().getDockableWindowManager();
  50. KeyListener keyListener = dwm.closeListener(VFSBrowser.NAME);
  51. parentDirectories = new ParentDirectoryList();
  52. parentDirectories.addKeyListener(keyListener);
  53. parentDirectories.setName("parent");
  54. parentDirectories.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  55. parentDirectories.setCellRenderer(new ParentDirectoryRenderer());
  56. parentDirectories.setVisibleRowCount(5);
  57. parentDirectories.addMouseListener(new ParentMouseHandler());
  58. final JScrollPane parentScroller = new JScrollPane(parentDirectories);
  59. parentScroller.setMinimumSize(new Dimension(0,0));
  60. table = new VFSDirectoryEntryTable(this);
  61. table.addMouseListener(new TableMouseHandler());
  62. table.setName("file");
  63. JScrollPane tableScroller = new JScrollPane(table);
  64. tableScroller.setMinimumSize(new Dimension(0,0));
  65. tableScroller.getViewport().setBackground(table.getBackground());
  66. tableScroller.getViewport().addMouseListener(new TableMouseHandler());
  67. splitPane = new JSplitPane(
  68. browser.isHorizontalLayout()
  69. ? JSplitPane.HORIZONTAL_SPLIT : JSplitPane.VERTICAL_SPLIT,
  70. jEdit.getBooleanProperty("appearance.continuousLayout"),
  71. parentScroller, tableScroller);
  72. splitPane.setOneTouchExpandable(true);
  73. SwingUtilities.invokeLater(new Runnable()
  74. {
  75. public void run()
  76. {
  77. String prop = browser.isHorizontalLayout() ? "vfs.browser.horizontalSplitter" : "vfs.browser.splitter";
  78. int loc = jEdit.getIntegerProperty(prop,-1);
  79. if(loc == -1)
  80. loc = parentScroller.getPreferredSize().height;
  81. splitPane.setDividerLocation(loc);
  82. parentDirectories.ensureIndexIsVisible(
  83. parentDirectories.getModel()
  84. .getSize());
  85. }
  86. });
  87. if(browser.isMultipleSelectionEnabled())
  88. table.getSelectionModel().setSelectionMode(
  89. ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  90. else
  91. table.getSelectionModel().setSelectionMode(
  92. ListSelectionModel.SINGLE_SELECTION);
  93. setLayout(new BorderLayout());
  94. add(BorderLayout.CENTER,splitPane);
  95. propertiesChanged();
  96. } //}}}
  97. //{{{ focusOnFileView() method
  98. public void focusOnFileView()
  99. {
  100. table.requestFocus();
  101. } //}}}
  102. //{{{ removeNotify() method
  103. @Override
  104. public void removeNotify()
  105. {
  106. String prop = browser.isHorizontalLayout() ? "vfs.browser.horizontalSplitter" : "vfs.browser.splitter";
  107. jEdit.setIntegerProperty(prop,splitPane.getDividerLocation());
  108. super.removeNotify();
  109. } //}}}
  110. //{{{ getSelectedFiles() method
  111. public VFSFile[] getSelectedFiles()
  112. {
  113. return table.getSelectedFiles();
  114. } //}}}
  115. //{{{ selectNone() method
  116. public void selectNone()
  117. {
  118. table.clearSelection();
  119. } //}}}
  120. //{{{ saveExpansionState() method
  121. public void saveExpansionState()
  122. {
  123. tmpExpanded.clear();
  124. table.getExpandedDirectories(tmpExpanded);
  125. } //}}}
  126. //{{{ clearExpansionState() method
  127. public void clearExpansionState()
  128. {
  129. tmpExpanded.clear();
  130. } //}}}
  131. //{{{ loadDirectory() method
  132. public void loadDirectory(Object node, String path,
  133. boolean addToHistory)
  134. {
  135. path = MiscUtilities.constructPath(browser.getDirectory(),path);
  136. VFS vfs = VFSManager.getVFSForPath(path);
  137. Object session = vfs.createVFSSession(path,this);
  138. if(session == null)
  139. return;
  140. if(node == null)
  141. {
  142. parentDirectories.setListData(new Object[] {
  143. new LoadingPlaceholder() });
  144. }
  145. Object[] loadInfo = new Object[2];
  146. VFSManager.runInWorkThread(new BrowserIORequest(
  147. BrowserIORequest.LIST_DIRECTORY,browser,
  148. session,vfs,path,null,loadInfo));
  149. browser.directoryLoaded(node,loadInfo,addToHistory);
  150. } //}}}
  151. //{{{ directoryLoaded() method
  152. /**
  153. * Rebuild the parent view after a directory has been loaded.
  154. *
  155. * @param node
  156. * @param path
  157. * @param directory
  158. */
  159. public void directoryLoaded(Object node, String path, java.util.List<VFSFile> directory)
  160. {
  161. //{{{ If reloading root, update parent directory list
  162. if(node == null)
  163. {
  164. DefaultListModel parentList = new DefaultListModel();
  165. String parent = path;
  166. for(;;)
  167. {
  168. VFS _vfs = VFSManager.getVFSForPath(parent);
  169. VFSFile file = null;
  170. if (_vfs instanceof FileVFS)
  171. {
  172. Object session = _vfs.createVFSSession(path, browser);
  173. try
  174. {
  175. file = _vfs._getFile(session, parent, browser);
  176. if (file != null)
  177. {
  178. file.setName(_vfs.getFileName(parent));
  179. }
  180. }
  181. catch (IOException e)
  182. {
  183. Log.log(Log.ERROR, this, e, e);
  184. }
  185. }
  186. if (file == null)
  187. {
  188. // create a DirectoryEntry manually
  189. // instead of using _vfs._getFile()
  190. // since so many VFS's have broken
  191. // implementations of this method
  192. file = new VFSFile(
  193. _vfs.getFileName(parent),
  194. parent,parent,
  195. VFSFile.DIRECTORY,
  196. 0L,false);
  197. }
  198. /*parentList.insertElementAt(new VFSFile(
  199. _vfs.getFileName(parent),
  200. parent,parent,
  201. VFSFile.DIRECTORY,
  202. 0L,false),0);*/
  203. parentList.insertElementAt(file,0);
  204. String newParent = _vfs.getParentOfPath(parent);
  205. if(newParent == null ||
  206. MiscUtilities.pathsEqual(parent,newParent))
  207. break;
  208. else
  209. parent = newParent;
  210. }
  211. parentDirectories.setModel(parentList);
  212. int index = parentList.getSize() - 1;
  213. parentDirectories.setSelectedIndex(index);
  214. parentDirectories.ensureIndexIsVisible(index);
  215. } //}}}
  216. table.setDirectory(VFSManager.getVFSForPath(path),
  217. node,directory,tmpExpanded);
  218. } //}}}
  219. //{{{ updateFileView() method
  220. public void updateFileView()
  221. {
  222. table.repaint();
  223. } //}}}
  224. //{{{ maybeReloadDirectory() method
  225. public void maybeReloadDirectory(String path)
  226. {
  227. String browserDir = browser.getDirectory();
  228. String symlinkBrowserDir;
  229. if(MiscUtilities.isURL(browserDir))
  230. {
  231. symlinkBrowserDir = browserDir;
  232. }
  233. else
  234. {
  235. symlinkBrowserDir = MiscUtilities.resolveSymlinks(
  236. browserDir);
  237. }
  238. if(MiscUtilities.pathsEqual(path,symlinkBrowserDir))
  239. {
  240. saveExpansionState();
  241. loadDirectory(null,browserDir,false);
  242. }
  243. // because this method is called for *every* VFS update,
  244. // we don't want to scan the tree all the time. So we
  245. // use the following algorithm to determine if the path
  246. // might be part of the tree:
  247. // - if the path starts with the browser's current directory,
  248. // we do the tree scan
  249. // - if the browser's directory is 'favorites:' -- we have to
  250. // do the tree scan, as every path can appear under the
  251. // favorites list
  252. // - if the browser's directory is 'roots:' and path is on
  253. // the local filesystem, do a tree scan
  254. if(!browserDir.startsWith(FavoritesVFS.PROTOCOL)
  255. && !browserDir.startsWith(FileRootsVFS.PROTOCOL)
  256. && !path.startsWith(symlinkBrowserDir))
  257. return;
  258. if(browserDir.startsWith(FileRootsVFS.PROTOCOL)
  259. && MiscUtilities.isURL(path)
  260. && !MiscUtilities.getProtocolOfURL(path)
  261. .equals("file"))
  262. return;
  263. table.maybeReloadDirectory(path);
  264. } //}}}
  265. //{{{ propertiesChanged() method
  266. public void propertiesChanged()
  267. {
  268. showIcons = jEdit.getBooleanProperty("vfs.browser.showIcons");
  269. table.propertiesChanged();
  270. GUIUtilities.initContinuousLayout(splitPane);
  271. splitPane.setBorder(null);
  272. } //}}}
  273. //{{{ getBrowser() method
  274. /**
  275. * Returns the associated <code>VFSBrowser</code> instance.
  276. * @since jEdit 4.2pre1
  277. */
  278. public VFSBrowser getBrowser()
  279. {
  280. return browser;
  281. } //}}}
  282. //{{{ getTable() method
  283. public VFSDirectoryEntryTable getTable()
  284. {
  285. return table;
  286. } //}}}
  287. //{{{ getParentDirectoryList() method
  288. public JList getParentDirectoryList()
  289. {
  290. return parentDirectories;
  291. } //}}}
  292. //{{{ Private members
  293. //{{{ Instance variables
  294. private final VFSBrowser browser;
  295. private final JSplitPane splitPane;
  296. private final JList parentDirectories;
  297. private final VFSDirectoryEntryTable table;
  298. private final Set<String> tmpExpanded;
  299. private BrowserCommandsMenu popup;
  300. private boolean showIcons;
  301. //}}}
  302. //{{{ showFilePopup() method
  303. private void showFilePopup(VFSFile[] files, Component comp,
  304. Point point)
  305. {
  306. popup = new BrowserCommandsMenu(browser,files);
  307. // for the parent directory right-click; on the click we select
  308. // the clicked item, but when the popup goes away we select the
  309. // currently showing directory.
  310. popup.addPopupMenuListener(new PopupMenuListener()
  311. {
  312. public void popupMenuCanceled(PopupMenuEvent e) {}
  313. public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
  314. public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
  315. {
  316. // we use SwingUtilities.invokeLater()
  317. // so that the action is executed before
  318. // the popup is hidden.
  319. SwingUtilities.invokeLater(new Runnable()
  320. {
  321. public void run()
  322. {
  323. int index = parentDirectories
  324. .getModel()
  325. .getSize() - 1;
  326. parentDirectories.setSelectedIndex(index);
  327. }
  328. });
  329. }
  330. });
  331. GUIUtilities.showPopupMenu(popup,comp,point.x,point.y);
  332. } //}}}
  333. //}}}
  334. //{{{ Inner classes
  335. //{{{ ParentDirectoryRenderer class
  336. class ParentDirectoryRenderer extends DefaultListCellRenderer
  337. {
  338. private Font plainFont;
  339. private final Font boldFont;
  340. ParentDirectoryRenderer()
  341. {
  342. plainFont = UIManager.getFont("Tree.font");
  343. if(plainFont == null)
  344. plainFont = jEdit.getFontProperty("metal.secondary.font");
  345. boldFont = new Font(plainFont.getName(),Font.BOLD,plainFont.getSize());
  346. }
  347. @Override
  348. public Component getListCellRendererComponent(
  349. JList list,
  350. Object value,
  351. int index,
  352. boolean isSelected,
  353. boolean cellHasFocus)
  354. {
  355. super.getListCellRendererComponent(list,value,index,
  356. isSelected,cellHasFocus);
  357. ParentDirectoryRenderer.this.setBorder(new EmptyBorder(
  358. 1,index * 5 + 1,1,1));
  359. if(value instanceof LoadingPlaceholder)
  360. {
  361. ParentDirectoryRenderer.this.setFont(plainFont);
  362. setIcon(showIcons ? FileCellRenderer.loadingIcon : null);
  363. setText(jEdit.getProperty("vfs.browser.tree.loading"));
  364. }
  365. else if(value instanceof VFSFile)
  366. {
  367. VFSFile dirEntry = (VFSFile)value;
  368. ParentDirectoryRenderer.this.setFont(boldFont);
  369. setIcon(showIcons ? FileCellRenderer.getIconForFile(dirEntry,true)
  370. : null);
  371. setText(dirEntry.getName());
  372. }
  373. else if(value == null)
  374. setText("VFS does not follow VFS API");
  375. return this;
  376. }
  377. } //}}}
  378. //{{{ ParentMouseHandler class
  379. private class ParentMouseHandler extends MouseAdapter
  380. {
  381. @Override
  382. public void mousePressed(MouseEvent evt)
  383. {
  384. int row = parentDirectories.locationToIndex(evt.getPoint());
  385. if(row != -1)
  386. {
  387. Object obj = parentDirectories.getModel()
  388. .getElementAt(row);
  389. if(obj instanceof VFSFile)
  390. {
  391. VFSFile dirEntry = (VFSFile)obj;
  392. if(GUIUtilities.isPopupTrigger(evt))
  393. {
  394. if(popup != null && popup.isVisible())
  395. {
  396. popup.setVisible(false);
  397. popup = null;
  398. }
  399. else
  400. {
  401. parentDirectories.setSelectedIndex(row);
  402. showFilePopup(new VFSFile[] {
  403. dirEntry },parentDirectories,
  404. evt.getPoint());
  405. }
  406. }
  407. }
  408. }
  409. }
  410. @Override
  411. public void mouseReleased(MouseEvent evt)
  412. {
  413. if(evt.getClickCount() % 2 != 0 &&
  414. !GUIUtilities.isMiddleButton(evt.getModifiers()))
  415. return;
  416. int row = parentDirectories.locationToIndex(evt.getPoint());
  417. if(row != -1)
  418. {
  419. Object obj = parentDirectories.getModel()
  420. .getElementAt(row);
  421. if(obj instanceof VFSFile)
  422. {
  423. VFSFile dirEntry = (VFSFile)obj;
  424. if(!GUIUtilities.isPopupTrigger(evt))
  425. {
  426. browser.setDirectory(dirEntry.getPath());
  427. if(browser.getMode() == VFSBrowser.BROWSER)
  428. focusOnFileView();
  429. }
  430. }
  431. }
  432. }
  433. } //}}}
  434. //{{{ TableMouseHandler class
  435. private class TableMouseHandler extends MouseAdapter
  436. {
  437. //{{{ mouseClicked() method
  438. @Override
  439. public void mouseClicked(MouseEvent evt)
  440. {
  441. Point p = evt.getPoint();
  442. int row = table.rowAtPoint(p);
  443. int column = table.columnAtPoint(p);
  444. if(row == -1)
  445. return;
  446. if(column == 0)
  447. {
  448. VFSDirectoryEntryTableModel.Entry entry
  449. = (VFSDirectoryEntryTableModel.Entry)
  450. table.getModel().getValueAt(row,0);
  451. if(FileCellRenderer.ExpansionToggleBorder
  452. .isExpansionToggle(entry.level,p.x))
  453. {
  454. return;
  455. }
  456. }
  457. if((evt.getModifiers() & InputEvent.BUTTON1_MASK) != 0
  458. && evt.getClickCount() % 2 == 0)
  459. {
  460. browser.filesActivated(evt.isShiftDown()
  461. ? VFSBrowser.M_OPEN_NEW_VIEW
  462. : VFSBrowser.M_OPEN,true);
  463. }
  464. else if(GUIUtilities.isMiddleButton(evt.getModifiers()))
  465. {
  466. if(evt.isShiftDown())
  467. table.getSelectionModel().addSelectionInterval(row,row);
  468. else
  469. table.getSelectionModel().setSelectionInterval(row,row);
  470. browser.filesActivated(evt.isShiftDown()
  471. ? VFSBrowser.M_OPEN_NEW_VIEW
  472. : VFSBrowser.M_OPEN,true);
  473. }
  474. } //}}}
  475. //{{{ mousePressed() method
  476. @Override
  477. public void mousePressed(MouseEvent evt)
  478. {
  479. Point p = evt.getPoint();
  480. if(evt.getSource() != table)
  481. {
  482. p.x -= table.getX();
  483. p.y -= table.getY();
  484. }
  485. int row = table.rowAtPoint(p);
  486. int column = table.columnAtPoint(p);
  487. if(column == 0 && row != -1)
  488. {
  489. VFSDirectoryEntryTableModel.Entry entry
  490. = (VFSDirectoryEntryTableModel.Entry)
  491. table.getModel().getValueAt(row,0);
  492. if(FileCellRenderer.ExpansionToggleBorder
  493. .isExpansionToggle(entry.level,p.x))
  494. {
  495. table.toggleExpanded(row);
  496. return;
  497. }
  498. }
  499. if(GUIUtilities.isMiddleButton(evt.getModifiers()))
  500. {
  501. if(row == -1)
  502. /* nothing */;
  503. else if(evt.isShiftDown())
  504. table.getSelectionModel().addSelectionInterval(row,row);
  505. else
  506. table.getSelectionModel().setSelectionInterval(row,row);
  507. }
  508. else if(GUIUtilities.isPopupTrigger(evt))
  509. {
  510. if(popup != null && popup.isVisible())
  511. {
  512. popup.setVisible(false);
  513. popup = null;
  514. return;
  515. }
  516. if(row == -1)
  517. showFilePopup(null,table,evt.getPoint());
  518. else
  519. {
  520. if(!table.getSelectionModel().isSelectedIndex(row))
  521. table.getSelectionModel().setSelectionInterval(row,row);
  522. showFilePopup(getSelectedFiles(),table,evt.getPoint());
  523. }
  524. }
  525. } //}}}
  526. //{{{ mouseReleased() method
  527. @Override
  528. public void mouseReleased(MouseEvent evt)
  529. {
  530. if(!GUIUtilities.isPopupTrigger(evt)
  531. && table.getSelectedRow() != -1)
  532. {
  533. browser.filesSelected();
  534. }
  535. } //}}}
  536. } //}}}
  537. private static class LoadingPlaceholder {}
  538. //}}}
  539. class ParentDirectoryList extends JList
  540. {
  541. public String getPath(int row)
  542. {
  543. Collection<String> components = new LinkedList<String>();
  544. for (int i=1; i<=row; ++i)
  545. components.add(getModel().getElementAt(i).toString());
  546. return getModel().getElementAt(0) + TextUtilities.join(components, File.separator);
  547. }
  548. @Override
  549. protected void processKeyEvent(KeyEvent evt)
  550. {
  551. if (evt.getID() == KeyEvent.KEY_PRESSED)
  552. {
  553. ActionContext ac = VFSBrowser.getActionContext();
  554. int row = parentDirectories.getSelectedIndex();
  555. switch(evt.getKeyCode())
  556. {
  557. case KeyEvent.VK_DOWN:
  558. evt.consume();
  559. if (row < parentDirectories.getSize().height-1)
  560. parentDirectories.setSelectedIndex(++row);
  561. break;
  562. case KeyEvent.VK_LEFT:
  563. if ((evt.getModifiers() & KeyEvent.ALT_MASK)>0)
  564. {
  565. evt.consume();
  566. browser.previousDirectory();
  567. }
  568. else super.processEvent(evt);
  569. break;
  570. case KeyEvent.VK_RIGHT:
  571. if ((evt.getModifiers() & KeyEvent.ALT_MASK)>0)
  572. {
  573. evt.consume();
  574. browser.nextDirectory();
  575. }
  576. else super.processEvent(evt);
  577. break;
  578. case KeyEvent.VK_TAB:
  579. evt.consume();
  580. if ((evt.getModifiers() & KeyEvent.SHIFT_MASK) > 0)
  581. browser.focusOnDefaultComponent();
  582. else
  583. table.requestFocus();
  584. break;
  585. case KeyEvent.VK_UP :
  586. evt.consume();
  587. if (row > 0)
  588. {
  589. parentDirectories.setSelectedIndex(--row);
  590. }
  591. break;
  592. case KeyEvent.VK_BACK_SPACE:
  593. evt.consume();
  594. EditAction up = ac.getAction("vfs.browser.up");
  595. ac.invokeAction(evt, up);
  596. break;
  597. case KeyEvent.VK_F5:
  598. evt.consume();
  599. EditAction reload = ac.getAction("vfs.browser.reload");
  600. ac.invokeAction(evt, reload);
  601. break;
  602. case KeyEvent.VK_ENTER:
  603. evt.consume();
  604. String path = getPath(row);
  605. getBrowser().setDirectory(path);
  606. table.requestFocus();
  607. break;
  608. /* These actions don't work because they look at the EntryTable for the current selected
  609. * item. We need actions that look at the parentDirectoryList item instead.
  610. *
  611. case KeyEvent.VK_DELETE:
  612. evt.consume();
  613. ea = ac.getAction("vfs.browser.delete");
  614. ac.invokeAction(evt, ea);
  615. break;
  616. case KeyEvent.CTRL_MASK | KeyEvent.VK_N:
  617. evt.consume();
  618. ea = ac.getAction("vfs.browser.new-file");
  619. ac.invokeAction(evt, ea);
  620. break;
  621. case KeyEvent.VK_INSERT:
  622. evt.consume();
  623. ea = ac.getAction("vfs.browser.new-directory");
  624. ac.invokeAction(evt, ea);
  625. break; */
  626. }
  627. }
  628. else if(evt.getID() == KeyEvent.KEY_TYPED)
  629. {
  630. if(evt.isControlDown() || evt.isAltDown()
  631. || evt.isMetaDown())
  632. {
  633. evt.consume();
  634. return;
  635. }
  636. switch(evt.getKeyChar())
  637. {
  638. case '~':
  639. evt.consume();
  640. if(browser.getMode() == VFSBrowser.BROWSER)
  641. browser.setDirectory(System.getProperty(
  642. "user.home"));
  643. break;
  644. case '/':
  645. evt.consume();
  646. if(browser.getMode() == VFSBrowser.BROWSER)
  647. browser.rootDirectory();
  648. break;
  649. case '-':
  650. evt.consume();
  651. if(browser.getMode() == VFSBrowser.BROWSER)
  652. {
  653. browser.setDirectory(
  654. browser.getView().getBuffer()
  655. .getDirectory());
  656. }
  657. break;
  658. }
  659. }
  660. if (!evt.isConsumed())
  661. super.processKeyEvent(evt);
  662. }
  663. }
  664. }