/plugins/SVNPlugin/tags/0.9.1/src/ise/plugin/svn/gui/BrowseRepositoryPanel.java

# · Java · 971 lines · 841 code · 71 blank · 59 comment · 177 complexity · c39ac819268bc52d68b8edfa3409700e MD5 · raw file

  1. /*
  2. Copyright (c) 2007, Dale Anson
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without modification,
  5. are permitted provided that the following conditions are met:
  6. * Redistributions of source code must retain the above copyright notice,
  7. this list of conditions and the following disclaimer.
  8. * Redistributions in binary form must reproduce the above copyright notice,
  9. this list of conditions and the following disclaimer in the documentation
  10. and/or other materials provided with the distribution.
  11. * Neither the name of the author nor the names of its contributors
  12. may be used to endorse or promote products derived from this software without
  13. specific prior written permission.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  15. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  18. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  21. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. package ise.plugin.svn.gui;
  26. import java.awt.BorderLayout;
  27. import java.awt.Component;
  28. import java.awt.Cursor;
  29. import java.awt.Dimension;
  30. import java.awt.FlowLayout;
  31. import java.awt.event.*;
  32. import java.io.*;
  33. import java.util.*;
  34. import javax.swing.*;
  35. import javax.swing.event.*;
  36. import javax.swing.tree.*;
  37. import org.gjt.sp.jedit.View;
  38. import org.gjt.sp.jedit.jEdit;
  39. import ise.plugin.svn.action.*;
  40. import ise.plugin.svn.command.BrowseRepository;
  41. import ise.plugin.svn.data.CopyData;
  42. import ise.plugin.svn.data.DeleteData;
  43. import ise.plugin.svn.data.LogData;
  44. import ise.plugin.svn.data.PropertyData;
  45. import ise.plugin.svn.data.RepositoryData;
  46. import ise.plugin.svn.data.SVNData;
  47. import ise.plugin.svn.gui.CopyDialog;
  48. import ise.plugin.svn.gui.RepositoryComboBox;
  49. import ise.plugin.svn.gui.RevisionDialog;
  50. import ise.plugin.svn.gui.TagBranchDialog;
  51. import ise.plugin.svn.library.GUIUtils;
  52. import org.gjt.sp.jedit.GUIUtilities;
  53. import org.tmatesoft.svn.core.wc.*;
  54. /**
  55. * Tree display for an SVN repository.
  56. */
  57. public class BrowseRepositoryPanel extends JPanel {
  58. private View view = null;
  59. private RepositoryComboBox chooser = null;
  60. private JTree tree = null;
  61. private JPopupMenu popupMenu = null;
  62. private String repository_name = null;
  63. private String username = null;
  64. private String password = null;
  65. private JButton new_btn;
  66. private JButton edit_btn;
  67. private JButton remove_btn;
  68. private JButton refresh_btn;
  69. public BrowseRepositoryPanel( View view ) {
  70. this( view, true );
  71. }
  72. public BrowseRepositoryPanel( View view, boolean full ) {
  73. super( new BorderLayout() );
  74. this.view = view;
  75. init( full, null );
  76. }
  77. public BrowseRepositoryPanel( View view, String defaultDestination ) {
  78. this( view, defaultDestination, true );
  79. }
  80. public BrowseRepositoryPanel( View view, String defaultDestination, boolean full ) {
  81. super( new BorderLayout() );
  82. this.view = view;
  83. init( full, defaultDestination );
  84. }
  85. private void init( boolean full, String repositoryName ) {
  86. // for button panel, defined below.
  87. JPanel button_panel = null;
  88. // repository chooser
  89. chooser = new RepositoryComboBox();
  90. // the repository tree. This is lazy loaded.
  91. tree = new JTree( new DefaultTreeModel( new DirTreeNode( "SVN Browser", false ) ) );
  92. tree.setCellRenderer( new CellRenderer() );
  93. tree.getSelectionModel().setSelectionMode( TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION );
  94. ToolTipManager.sharedInstance().registerComponent( tree );
  95. // on expansion, call the repository and fetch the children
  96. tree.addTreeExpansionListener( new TreeExpansionListener() {
  97. public void treeCollapsed( TreeExpansionEvent event ) {}
  98. public void treeExpanded( TreeExpansionEvent event ) {
  99. TreePath path = event.getPath();
  100. DirTreeNode node = ( DirTreeNode ) path.getLastPathComponent();
  101. if ( node.getChildCount() == 0 ) {
  102. RepositoryData data = chooser.getSelectedRepository();
  103. data = new RepositoryData( data );
  104. String url;
  105. if ( node.isExternal() ) {
  106. url = node.getRepositoryLocation();
  107. }
  108. else {
  109. Object[] parts = path.getPath();
  110. StringBuilder sb = new StringBuilder();
  111. sb.append( parts[ 0 ] );
  112. for ( int i = 1; i < parts.length; i++ ) {
  113. sb.append( "/" ).append( parts[ i ].toString() );
  114. }
  115. url = sb.toString();
  116. }
  117. data.setURL( url );
  118. BrowseRepositoryAction action = new BrowseRepositoryAction( getView(), tree, node, data );
  119. action.actionPerformed( null );
  120. }
  121. }
  122. }
  123. );
  124. // on double click on a text file, fetch the file contents and show the file in jEdit
  125. if ( full ) {
  126. tree.addMouseListener( new MouseAdapter() {
  127. public void mouseClicked( MouseEvent me ) {
  128. if ( me.getClickCount() == 2 ) {
  129. // for double-click on a text file, open the file in jEdit
  130. TreePath path = tree.getClosestPathForLocation( me.getX(), me.getY() );
  131. DirTreeNode node = ( DirTreeNode ) path.getLastPathComponent();
  132. if ( node.isLeaf() ) {
  133. // show the wait cursor
  134. tree.setCursor( Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR ) );
  135. tree.setEditable( false );
  136. // leaf nodes should be files, not directories.
  137. // get url and path for the selected file
  138. RepositoryData data = chooser.getSelectedRepository();
  139. String url;
  140. String filepath;
  141. Object[] parts = path.getPath();
  142. StringBuilder sb = new StringBuilder();
  143. for ( int i = 1; i < parts.length; i++ ) {
  144. sb.append( "/" ).append( parts[ i ].toString() );
  145. }
  146. filepath = sb.toString().substring( 1 );
  147. if ( node.isExternal() ) {
  148. String rep = node.getRepositoryLocation();
  149. url = rep.substring( 0, rep.lastIndexOf( "/" ) );
  150. filepath = rep.substring( rep.lastIndexOf( "/" ) + 1 );
  151. }
  152. else {
  153. url = data.getURL();
  154. }
  155. // ask the user for the revision they want
  156. RevisionDialog rd = new RevisionDialog( BrowseRepositoryPanel.this.view, "Select Revision to View" );
  157. GUIUtils.center( BrowseRepositoryPanel.this.getView(), rd );
  158. rd.setVisible( true );
  159. SVNRevision revision = rd.getData();
  160. if ( revision == null ) {
  161. return ;
  162. }
  163. // fetch the file contents
  164. BrowseRepository br = new BrowseRepository();
  165. File outfile = br.getFile( url, filepath, revision, data.getUsername(), data.getPassword() );
  166. if ( outfile != null ) {
  167. jEdit.openFile( getView(), outfile.getAbsolutePath() );
  168. }
  169. tree.setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR ) );
  170. tree.setEditable( true );
  171. }
  172. }
  173. }
  174. }
  175. );
  176. // add listener to trigger context menu popup
  177. tree.addMouseListener( new TreeMouseListener() );
  178. // create the context menu
  179. popupMenu = createPopupMenu();
  180. // create the control buttons -- add repository
  181. Icon new_icon = GUIUtilities.loadIcon( "New.png" );
  182. new_btn = new JButton( new_icon );
  183. Dimension dim = new Dimension( new_icon.getIconWidth() + ( new_btn.getInsets().top * 2 ), new_icon.getIconHeight() + ( new_btn.getInsets().top * 2 ) );
  184. new_btn.setSize( dim );
  185. new_btn.setPreferredSize( dim );
  186. new_btn.setMaximumSize( dim );
  187. new_btn.setToolTipText( "Add new repository" );
  188. new_btn.addActionListener( new ActionListener() {
  189. public void actionPerformed( ActionEvent ae ) {
  190. AddRepositoryDialog dialog = new AddRepositoryDialog( getView() );
  191. GUIUtils.center( getView(), dialog );
  192. dialog.setVisible( true );
  193. RepositoryData data = dialog.getValues();
  194. if ( data == null ) {
  195. return ; // user canceled
  196. }
  197. //String name = data.getName() == null || data.getName().equals( "" ) ? data.getURL() : data.getName();
  198. chooser.addRepository( data );
  199. DirTreeNode root = new DirTreeNode( data.getURL(), false );
  200. tree.setModel( new DefaultTreeModel( root ) );
  201. BrowseRepositoryAction action = new BrowseRepositoryAction( getView(), tree, root, data );
  202. action.actionPerformed( ae );
  203. }
  204. }
  205. );
  206. // edit repository properties
  207. Icon edit_icon = GUIUtilities.loadIcon( "Preferences.png" );
  208. edit_btn = new JButton( edit_icon );
  209. dim = new Dimension( edit_icon.getIconWidth() + ( edit_btn.getInsets().top * 2 ), edit_icon.getIconHeight() + ( edit_btn.getInsets().top * 2 ) );
  210. edit_btn.setSize( dim );
  211. edit_btn.setPreferredSize( dim );
  212. edit_btn.setMaximumSize( dim );
  213. edit_btn.setToolTipText( "Edit repository properties" );
  214. edit_btn.setEnabled( false );
  215. edit_btn.addActionListener( new ActionListener() {
  216. public void actionPerformed( ActionEvent ae ) {
  217. RepositoryData old_data = chooser.getSelectedRepository();
  218. AddRepositoryDialog dialog = new AddRepositoryDialog( getView(), new RepositoryData( old_data ) );
  219. GUIUtils.center( getView(), dialog );
  220. dialog.setVisible( true );
  221. RepositoryData new_data = dialog.getValues(); // null indicates user canceled
  222. if ( new_data != null ) {
  223. chooser.removeRepository( old_data );
  224. chooser.save( new_data );
  225. DirTreeNode root = new DirTreeNode( new_data.getURL(), false );
  226. tree.setModel( new DefaultTreeModel( root ) );
  227. BrowseRepositoryAction action = new BrowseRepositoryAction( getView(), tree, root, new_data );
  228. action.actionPerformed( ae );
  229. }
  230. }
  231. }
  232. );
  233. // remove repository from chooser
  234. Icon remove_icon = GUIUtilities.loadIcon( "Minus.png" );
  235. remove_btn = new JButton( remove_icon );
  236. dim = new Dimension( remove_icon.getIconWidth() + ( remove_btn.getInsets().top * 2 ), remove_icon.getIconHeight() + ( remove_btn.getInsets().top * 2 ) );
  237. remove_btn.setSize( dim );
  238. remove_btn.setPreferredSize( dim );
  239. remove_btn.setMaximumSize( dim );
  240. remove_btn.setToolTipText( "Remove repository from browser" );
  241. remove_btn.setEnabled( false );
  242. remove_btn.addActionListener( new ActionListener() {
  243. public void actionPerformed( ActionEvent ae ) {
  244. RepositoryData data = chooser.getSelectedRepository();
  245. if ( data != null ) {
  246. int delete = JOptionPane.showConfirmDialog( BrowseRepositoryPanel.this.view, "Remove repository location " + data.getURL() + " ?\nThis only removes this repository from the browser, it does not delete any files.", "Confirm Remove", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE );
  247. if ( delete == JOptionPane.YES_OPTION ) {
  248. chooser.removeRepository( data );
  249. }
  250. }
  251. }
  252. }
  253. );
  254. // reload tree with current selection
  255. Icon refresh_icon = GUIUtilities.loadIcon( "Reload.png" );
  256. refresh_btn = new JButton( refresh_icon );
  257. dim = new Dimension( refresh_icon.getIconWidth() + ( refresh_btn.getInsets().top * 2 ), refresh_icon.getIconHeight() + ( refresh_btn.getInsets().top * 2 ) );
  258. refresh_btn.setSize( dim );
  259. refresh_btn.setPreferredSize( dim );
  260. refresh_btn.setMaximumSize( dim );
  261. refresh_btn.setToolTipText( "Refresh" );
  262. refresh_btn.setEnabled( false );
  263. // create a panel to hold the buttons
  264. button_panel = new JPanel( new FlowLayout( FlowLayout.LEFT, 0, 1 ) );
  265. button_panel.add( new_btn );
  266. button_panel.add( edit_btn );
  267. button_panel.add( remove_btn );
  268. button_panel.add( refresh_btn );
  269. }
  270. // action listener for repository chooser
  271. ActionListener al = new ActionListener() {
  272. public void actionPerformed( ActionEvent ae ) {
  273. RepositoryData data = chooser.getSelectedRepository();
  274. if ( data != null ) {
  275. DirTreeNode root = new DirTreeNode( data.getURL(), false );
  276. tree.setModel( new DefaultTreeModel( root ) );
  277. BrowseRepositoryAction action = new BrowseRepositoryAction( getView(), tree, root, data );
  278. action.actionPerformed( ae );
  279. }
  280. else {
  281. tree.setModel( new DefaultTreeModel( new DirTreeNode( "SVN Browser", false ) ) );
  282. }
  283. if ( edit_btn != null ) {
  284. edit_btn.setEnabled( data != null );
  285. }
  286. if ( remove_btn != null ) {
  287. remove_btn.setEnabled( data != null );
  288. }
  289. if ( refresh_btn != null ) {
  290. refresh_btn.setEnabled( data != null );
  291. }
  292. }
  293. };
  294. chooser.addActionListener( al );
  295. if ( full ) {
  296. refresh_btn.addActionListener( al );
  297. }
  298. if ( repositoryName != null ) {
  299. chooser.setSelectedItem( repositoryName );
  300. }
  301. // create a panel to hold the buttons and the repository chooser
  302. JPanel top_panel = new JPanel( new BorderLayout() );
  303. if ( full ) {
  304. top_panel.add( button_panel, BorderLayout.NORTH );
  305. }
  306. top_panel.add( chooser, BorderLayout.CENTER );
  307. // fill in the main panel
  308. add( top_panel, BorderLayout.NORTH );
  309. add( new JScrollPane( tree ), BorderLayout.CENTER );
  310. }
  311. public void setRoot( DirTreeNode root ) {
  312. if ( root != null ) {
  313. tree.setModel( new DefaultTreeModel( root, false ) );
  314. }
  315. }
  316. public View getView() {
  317. return view;
  318. }
  319. public String getSelectionPath() {
  320. TreePath tp = tree.getSelectionPath();
  321. StringBuilder sb = new StringBuilder();
  322. for ( Object part : tp.getPath() ) {
  323. String p = part.toString();
  324. if ( p.endsWith( "/" ) ) {
  325. p = p.substring( 0, p.length() - 1 );
  326. }
  327. sb.append( p ).append( "/" );
  328. }
  329. return sb.toString();
  330. }
  331. /**
  332. * MouseListener to popup context menu on the tree.
  333. */
  334. class TreeMouseListener extends MouseAdapter {
  335. public void mouseReleased( MouseEvent me ) {
  336. handleClick( me );
  337. }
  338. public void mousePressed( MouseEvent me ) {
  339. handleClick( me );
  340. }
  341. private void handleClick( MouseEvent me ) {
  342. if ( me.isPopupTrigger() ) {
  343. if ( tree.getSelectionCount() == 0 ) {
  344. TreePath path = tree.getClosestPathForLocation( me.getX(), me.getY() );
  345. tree.addSelectionPath( path );
  346. }
  347. GUIUtilities.showPopupMenu( popupMenu, BrowseRepositoryPanel.this, me.getX(), me.getY(), true );
  348. }
  349. }
  350. }
  351. /**
  352. * Create the context menu.
  353. */
  354. private JPopupMenu createPopupMenu() {
  355. // update, commit, revert, add, log, need to add others as appropriate
  356. final JPopupMenu pm = new JPopupMenu();
  357. JMenuItem mi = new JMenuItem( "Checkout..." );
  358. pm.add( mi );
  359. mi.addActionListener( new ActionListener() {
  360. public void actionPerformed( ActionEvent ae ) {
  361. TreePath[] tree_paths = tree.getSelectionPaths();
  362. if ( tree_paths.length == 0 ) {
  363. return ;
  364. }
  365. if ( tree_paths.length > 1 ) {
  366. JOptionPane.showMessageDialog( view, "Please select a single entry.", "Too many selections", JOptionPane.ERROR_MESSAGE );
  367. return ;
  368. }
  369. String url = null;
  370. for ( TreePath path : tree_paths ) {
  371. if ( path != null ) {
  372. Object[] parts = path.getPath();
  373. StringBuilder sb = new StringBuilder();
  374. sb.append( parts[ 0 ] );
  375. for ( int i = 1; i < parts.length; i++ ) {
  376. sb.append( "/" ).append( parts[ i ].toString() );
  377. }
  378. url = sb.toString();
  379. break;
  380. }
  381. }
  382. RepositoryData data = new RepositoryData();
  383. data.setURL( url );
  384. data.setUsername( username );
  385. data.setPassword( password );
  386. CheckoutAction action = new CheckoutAction( view, data );
  387. action.actionPerformed( ae );
  388. }
  389. }
  390. );
  391. mi = new JMenuItem( "Info" );
  392. pm.add( mi );
  393. mi.addActionListener( new ActionListener() {
  394. public void actionPerformed( ActionEvent ae ) {
  395. TreePath[] tree_paths = tree.getSelectionPaths();
  396. if ( tree_paths.length == 0 ) {
  397. return ;
  398. }
  399. List<String> paths = new ArrayList<String>();
  400. for ( TreePath path : tree_paths ) {
  401. if ( path != null ) {
  402. DirTreeNode node = ( DirTreeNode ) path.getLastPathComponent();
  403. if ( node.isExternal() ) {
  404. paths.add( node.getRepositoryLocation() );
  405. }
  406. else {
  407. Object[] parts = path.getPath();
  408. StringBuilder sb = new StringBuilder();
  409. sb.append( parts[ 0 ] );
  410. for ( int i = 1; i < parts.length; i++ ) {
  411. sb.append( "/" ).append( parts[ i ].toString() );
  412. }
  413. String url = sb.toString();
  414. paths.add( url );
  415. }
  416. }
  417. }
  418. SVNData data = new SVNData();
  419. data.setPaths( paths );
  420. data.setPathsAreURLs( true );
  421. data.setUsername( username );
  422. data.setPassword( password );
  423. InfoAction action = new InfoAction( view, data );
  424. action.actionPerformed( ae );
  425. }
  426. }
  427. );
  428. mi = new JMenuItem( "Log..." );
  429. pm.add( mi );
  430. mi.addActionListener( new ActionListener() {
  431. public void actionPerformed( ActionEvent ae ) {
  432. TreePath[] tree_paths = tree.getSelectionPaths();
  433. if ( tree_paths.length == 0 ) {
  434. return ;
  435. }
  436. List<String> paths = new ArrayList<String>();
  437. for ( TreePath path : tree_paths ) {
  438. if ( path != null ) {
  439. DirTreeNode node = ( DirTreeNode ) path.getLastPathComponent();
  440. if ( node.isExternal() ) {
  441. paths.add( node.getRepositoryLocation() );
  442. }
  443. else {
  444. Object[] parts = path.getPath();
  445. StringBuilder sb = new StringBuilder();
  446. sb.append( parts[ 0 ] );
  447. for ( int i = 1; i < parts.length; i++ ) {
  448. sb.append( "/" ).append( parts[ i ].toString() );
  449. }
  450. String url = sb.toString();
  451. paths.add( url );
  452. }
  453. }
  454. }
  455. LogData data = new LogData();
  456. data.setPaths( paths );
  457. data.setPathsAreURLs( true );
  458. data.setUsername( username );
  459. data.setPassword( password );
  460. LogAction action = new LogAction( view, data );
  461. action.actionPerformed( ae );
  462. }
  463. }
  464. );
  465. mi = new JMenuItem( "Properties" );
  466. pm.add( mi );
  467. mi.addActionListener( new ActionListener() {
  468. public void actionPerformed( ActionEvent ae ) {
  469. TreePath[] tree_paths = tree.getSelectionPaths();
  470. if ( tree_paths.length == 0 ) {
  471. return ;
  472. }
  473. boolean hasDirectory = false;
  474. List<String> paths = new ArrayList<String>();
  475. for ( TreePath path : tree_paths ) {
  476. if ( path != null ) {
  477. Object[] parts = path.getPath();
  478. StringBuilder sb = new StringBuilder();
  479. sb.append( parts[ 0 ] );
  480. for ( int i = 1; i < parts.length; i++ ) {
  481. sb.append( "/" ).append( parts[ i ].toString() );
  482. }
  483. String url = sb.toString();
  484. paths.add( url );
  485. DirTreeNode node = ( DirTreeNode ) path.getLastPathComponent();
  486. if ( !hasDirectory && !node.isLeaf() ) {
  487. hasDirectory = true;
  488. }
  489. }
  490. }
  491. PropertyData data = new PropertyData();
  492. data.setPaths( paths );
  493. data.setPathsAreURLs( true );
  494. data.setUsername( username );
  495. data.setPassword( password );
  496. data.setHasDirectory( hasDirectory );
  497. PropertyAction action = new PropertyAction( view, data );
  498. action.actionPerformed( ae );
  499. }
  500. }
  501. );
  502. pm.addSeparator();
  503. mi = new JMenuItem( "Copy..." );
  504. pm.add( mi );
  505. mi.addActionListener( new ActionListener() {
  506. public void actionPerformed( ActionEvent ae ) {
  507. TreePath[] tree_paths = tree.getSelectionPaths();
  508. if ( tree_paths.length == 0 ) {
  509. return ;
  510. }
  511. boolean hasDirectory = false;
  512. List<String> paths = new ArrayList<String>();
  513. for ( TreePath path : tree_paths ) {
  514. if ( path != null ) {
  515. Object[] parts = path.getPath();
  516. StringBuilder sb = new StringBuilder();
  517. sb.append( parts[ 0 ] );
  518. for ( int i = 1; i < parts.length; i++ ) {
  519. sb.append( "/" ).append( parts[ i ].toString() );
  520. }
  521. String url = sb.toString();
  522. paths.add( url );
  523. DirTreeNode node = ( DirTreeNode ) path.getLastPathComponent();
  524. if ( !hasDirectory && !node.isLeaf() ) {
  525. hasDirectory = true;
  526. }
  527. }
  528. }
  529. CopyDialog dialog = new CopyDialog( view, null, chooser.getSelectedItem().toString(), paths );
  530. GUIUtils.center( view, dialog );
  531. dialog.setVisible( true );
  532. CopyData data = dialog.getData();
  533. if ( data == null ) {
  534. return ; // user canceled
  535. }
  536. if ( username != null && password != null ) {
  537. data.setUsername( username );
  538. data.setPassword( password );
  539. }
  540. CopyAction action = new CopyAction( view, data );
  541. action.actionPerformed( null );
  542. }
  543. }
  544. );
  545. mi = new JMenuItem( "Make Directory..." );
  546. pm.add( mi );
  547. mi.addActionListener( new ActionListener() {
  548. public void actionPerformed( ActionEvent ae ) {
  549. TreePath[] tree_paths = tree.getSelectionPaths();
  550. if ( tree_paths.length == 0 ) {
  551. return ;
  552. }
  553. if ( tree_paths.length > 1 ) {
  554. JOptionPane.showMessageDialog( view, "Please select a single entry.", "Too many selections", JOptionPane.ERROR_MESSAGE );
  555. return ;
  556. }
  557. String defaultDestination = null;
  558. boolean hasDirectory = false;
  559. List<String> paths = new ArrayList<String>();
  560. for ( TreePath path : tree_paths ) { // one path, one loop
  561. if ( path != null ) {
  562. Object[] parts = path.getPath();
  563. StringBuilder from = new StringBuilder();
  564. String preface = parts[ 0 ].toString();
  565. if ( preface.endsWith( "/" ) ) {
  566. preface = preface.substring( 0, preface.length() - 1 );
  567. }
  568. from.append( preface );
  569. for ( int i = 1; i < parts.length; i++ ) {
  570. from.append( "/" ).append( parts[ i ].toString() );
  571. }
  572. defaultDestination = from.toString();
  573. paths.add( defaultDestination );
  574. DirTreeNode node = ( DirTreeNode ) path.getLastPathComponent();
  575. if ( !hasDirectory && !node.isLeaf() ) {
  576. hasDirectory = true;
  577. }
  578. }
  579. }
  580. if ( !hasDirectory ) {
  581. JOptionPane.showMessageDialog( view, "Please select a directory in which to create the new directory.", "Error", JOptionPane.ERROR_MESSAGE );
  582. return ;
  583. }
  584. MkDirAction action = new MkDirAction( view, paths, username, password, defaultDestination );
  585. action.actionPerformed( null );
  586. }
  587. }
  588. );
  589. mi = new JMenuItem( "Tag..." );
  590. pm.add( mi );
  591. mi.addActionListener( new ActionListener() {
  592. public void actionPerformed( ActionEvent ae ) {
  593. TreePath[] tree_paths = tree.getSelectionPaths();
  594. if ( tree_paths.length == 0 ) {
  595. return ;
  596. }
  597. if ( tree_paths.length > 1 ) {
  598. JOptionPane.showMessageDialog( view, "Please select a single entry.", "Too many selections", JOptionPane.ERROR_MESSAGE );
  599. return ;
  600. }
  601. String from_url = null;
  602. String defaultDestination = null;
  603. for ( TreePath path : tree_paths ) { // should be a single loop
  604. if ( path != null ) {
  605. Object[] parts = path.getPath();
  606. StringBuilder from = new StringBuilder();
  607. StringBuilder to = new StringBuilder();
  608. String preface = parts[ 0 ].toString();
  609. if ( preface.endsWith( "/" ) ) {
  610. preface = preface.substring( 0, preface.length() - 1 );
  611. }
  612. from.append( preface );
  613. to.append( preface );
  614. for ( int i = 1; i < parts.length; i++ ) {
  615. from.append( "/" ).append( parts[ i ].toString() );
  616. }
  617. for ( int i = 1; i < parts.length - 1; i++ ) {
  618. if ( parts[ i ].toString().equals( "branches" ) ) {
  619. continue;
  620. }
  621. to.append( "/" ).append( parts[ i ].toString() );
  622. }
  623. from_url = from.toString();
  624. defaultDestination = to.append( "/tags" ).toString();
  625. break;
  626. }
  627. }
  628. TagBranchDialog dialog = new TagBranchDialog( view, TagBranchDialog.TAG_DIALOG, from_url, defaultDestination );
  629. GUIUtils.center( view, dialog );
  630. dialog.setVisible( true );
  631. CopyData cd = dialog.getData();
  632. if ( cd != null ) {
  633. if ( username != null && password != null ) {
  634. cd.setUsername( username );
  635. cd.setPassword( password );
  636. }
  637. cd.setTitle( "Tag" );
  638. CopyAction action = new CopyAction( view, cd );
  639. action.actionPerformed( null );
  640. }
  641. }
  642. }
  643. );
  644. mi = new JMenuItem( "Branch..." );
  645. pm.add( mi );
  646. mi.addActionListener( new ActionListener() {
  647. public void actionPerformed( ActionEvent ae ) {
  648. TreePath[] tree_paths = tree.getSelectionPaths();
  649. if ( tree_paths.length == 0 ) {
  650. return ;
  651. }
  652. if ( tree_paths.length > 1 ) {
  653. JOptionPane.showMessageDialog( view, "Please select a single entry.", "Too many selections", JOptionPane.ERROR_MESSAGE );
  654. return ;
  655. }
  656. String from_url = null;
  657. String defaultDestination = null;
  658. for ( TreePath path : tree_paths ) { // should be a single loop
  659. if ( path != null ) {
  660. Object[] parts = path.getPath();
  661. StringBuilder from = new StringBuilder();
  662. StringBuilder to = new StringBuilder();
  663. String preface = parts[ 0 ].toString();
  664. if ( preface.endsWith( "/" ) ) {
  665. preface = preface.substring( 0, preface.length() - 1 );
  666. }
  667. from.append( preface );
  668. to.append( preface );
  669. for ( int i = 1; i < parts.length; i++ ) {
  670. from.append( "/" ).append( parts[ i ].toString() );
  671. }
  672. for ( int i = 1; i < parts.length - 1; i++ ) {
  673. to.append( "/" ).append( parts[ i ].toString() );
  674. }
  675. from_url = from.toString();
  676. defaultDestination = to.append( "/branches" ).toString();
  677. break;
  678. }
  679. }
  680. TagBranchDialog dialog = new TagBranchDialog( view, TagBranchDialog.BRANCH_DIALOG, from_url, defaultDestination );
  681. GUIUtils.center( view, dialog );
  682. dialog.setVisible( true );
  683. CopyData cd = dialog.getData();
  684. if ( cd != null ) {
  685. if ( username != null && password != null ) {
  686. cd.setUsername( username );
  687. cd.setPassword( password );
  688. }
  689. cd.setTitle( "Branch" );
  690. CopyAction action = new CopyAction( view, cd );
  691. action.actionPerformed( null );
  692. }
  693. }
  694. }
  695. );
  696. mi = new JMenuItem( "Move..." );
  697. pm.add( mi );
  698. mi.addActionListener( new ActionListener() {
  699. public void actionPerformed( ActionEvent ae ) {
  700. TreePath[] tree_paths = tree.getSelectionPaths();
  701. if ( tree_paths.length == 0 ) {
  702. return ;
  703. }
  704. String url = null;
  705. String defaultDestination = null;
  706. List<String> paths = new ArrayList<String>();
  707. for ( TreePath path : tree_paths ) {
  708. if ( path != null ) {
  709. Object[] parts = path.getPath();
  710. StringBuilder sb = new StringBuilder();
  711. sb.append( parts[ 0 ] );
  712. for ( int i = 1; i < parts.length; i++ ) {
  713. sb.append( "/" ).append( parts[ i ].toString() );
  714. }
  715. url = sb.toString();
  716. paths.add( url );
  717. defaultDestination = url;
  718. }
  719. }
  720. MoveDialog dialog = new MoveDialog( view, defaultDestination, paths );
  721. GUIUtils.center( view, dialog );
  722. dialog.setVisible( true );
  723. CopyData cd = dialog.getData();
  724. if ( cd != null ) {
  725. if ( username != null && password != null ) {
  726. cd.setUsername( username );
  727. cd.setPassword( password );
  728. }
  729. MoveAction action = new MoveAction( view, cd );
  730. action.actionPerformed( null );
  731. }
  732. }
  733. }
  734. );
  735. mi = new JMenuItem( "Import..." );
  736. pm.add( mi );
  737. mi.addActionListener( new ActionListener() {
  738. public void actionPerformed( ActionEvent ae ) {
  739. TreePath[] tree_paths = tree.getSelectionPaths();
  740. if ( tree_paths.length == 0 ) {
  741. return ;
  742. }
  743. if ( tree_paths.length > 1 ) {
  744. JOptionPane.showMessageDialog( view, "Please select a single entry.", "Too many selections", JOptionPane.ERROR_MESSAGE );
  745. return ;
  746. }
  747. ImportAction action = new ImportAction( view );
  748. action.actionPerformed( ae );
  749. }
  750. }
  751. );
  752. mi = new JMenuItem( "Export..." );
  753. pm.add( mi );
  754. mi.addActionListener( new ActionListener() {
  755. public void actionPerformed( ActionEvent ae ) {
  756. TreePath[] tree_paths = tree.getSelectionPaths();
  757. if ( tree_paths.length == 0 ) {
  758. return ;
  759. }
  760. if ( tree_paths.length > 1 ) {
  761. JOptionPane.showMessageDialog( view, "Please select a single entry.", "Too many selections", JOptionPane.ERROR_MESSAGE );
  762. return ;
  763. }
  764. List<String> paths = new ArrayList<String>();
  765. for ( TreePath path : tree_paths ) {
  766. if ( path != null ) {
  767. Object[] parts = path.getPath();
  768. StringBuilder sb = new StringBuilder();
  769. sb.append( parts[ 0 ] );
  770. for ( int i = 1; i < parts.length; i++ ) {
  771. sb.append( "/" ).append( parts[ i ].toString() );
  772. }
  773. String url = sb.toString();
  774. paths.add( url );
  775. }
  776. }
  777. ExportAction action = new ExportAction( view, username, password, paths );
  778. action.actionPerformed( ae );
  779. }
  780. }
  781. );
  782. pm.addSeparator();
  783. mi = new JMenuItem( "Delete" );
  784. pm.add( mi );
  785. mi.addActionListener( new ActionListener() {
  786. public void actionPerformed( ActionEvent ae ) {
  787. TreePath[] tree_paths = tree.getSelectionPaths();
  788. if ( tree_paths.length == 0 ) {
  789. return ;
  790. }
  791. List<String> paths = new ArrayList<String>();
  792. for ( TreePath path : tree_paths ) {
  793. if ( path != null ) {
  794. Object[] parts = path.getPath();
  795. StringBuilder sb = new StringBuilder();
  796. sb.append( parts[ 0 ] );
  797. for ( int i = 1; i < parts.length; i++ ) {
  798. sb.append( "/" ).append( parts[ i ].toString() );
  799. }
  800. String url = sb.toString();
  801. paths.add( url );
  802. }
  803. }
  804. DeleteData data = new DeleteData();
  805. data.setPaths( paths );
  806. data.setUsername( username );
  807. data.setPassword( password );
  808. data.setPathsAreURLs( true );
  809. DeleteAction action = new DeleteAction( view, data );
  810. action.actionPerformed( ae );
  811. }
  812. }
  813. );
  814. mi = new JMenuItem( "Lock" );
  815. pm.add( mi );
  816. mi.addActionListener( new ActionListener() {
  817. public void actionPerformed( ActionEvent ae ) {
  818. TreePath[] tree_paths = tree.getSelectionPaths();
  819. if ( tree_paths.length == 0 ) {
  820. return ;
  821. }
  822. List<String> paths = new ArrayList<String>();
  823. for ( TreePath path : tree_paths ) {
  824. if ( path != null ) {
  825. Object[] parts = path.getPath();
  826. StringBuilder sb = new StringBuilder();
  827. sb.append( parts[ 0 ] );
  828. for ( int i = 1; i < parts.length; i++ ) {
  829. sb.append( "/" ).append( parts[ i ].toString() );
  830. }
  831. String url = sb.toString();
  832. paths.add( url );
  833. }
  834. }
  835. LockAction action = new LockAction( view, paths, username, password, true );
  836. action.actionPerformed( ae );
  837. }
  838. }
  839. );
  840. mi = new JMenuItem( "Unlock" );
  841. pm.add( mi );
  842. mi.addActionListener( new ActionListener() {
  843. public void actionPerformed( ActionEvent ae ) {
  844. TreePath[] tree_paths = tree.getSelectionPaths();
  845. if ( tree_paths.length == 0 ) {
  846. return ;
  847. }
  848. List<String> paths = new ArrayList<String>();
  849. for ( TreePath path : tree_paths ) {
  850. if ( path != null ) {
  851. Object[] parts = path.getPath();
  852. StringBuilder sb = new StringBuilder();
  853. sb.append( parts[ 0 ] );
  854. for ( int i = 1; i < parts.length; i++ ) {
  855. sb.append( "/" ).append( parts[ i ].toString() );
  856. }
  857. String url = sb.toString();
  858. paths.add( url );
  859. }
  860. }
  861. UnlockAction action = new UnlockAction( view, paths, username, password, true );
  862. action.actionPerformed( ae );
  863. }
  864. }
  865. );
  866. return pm;
  867. }
  868. class CellRenderer extends DefaultTreeCellRenderer {
  869. public Component getTreeCellRendererComponent(
  870. JTree tree,
  871. Object value,
  872. boolean sel,
  873. boolean expanded,
  874. boolean leaf,
  875. int row,
  876. boolean hasFocus ) {
  877. Component r = super.getTreeCellRendererComponent(
  878. tree, value, sel,
  879. expanded, leaf, row,
  880. hasFocus );
  881. if ( r instanceof JLabel ) {
  882. JLabel label = ( JLabel ) r;
  883. DirTreeNode node = ( DirTreeNode ) value;
  884. String text = node.toString();
  885. if ( node.isExternal() ) {
  886. text = "<html><font color=blue>" + node.toString();
  887. label.setToolTipText( "<html><b>External: </b> " + node.getRepositoryLocation() );
  888. }
  889. if ( node.hasProperties() ) {
  890. text += " *";
  891. }
  892. label.setText( text );
  893. }
  894. return r;
  895. }
  896. }
  897. }