From: <dal...@us...> - 2008-05-07 04:00:27
|
Revision: 12580 http://jedit.svn.sourceforge.net/jedit/?rev=12580&view=rev Author: daleanson Date: 2008-05-06 21:00:25 -0700 (Tue, 06 May 2008) Log Message: ----------- Initial support for blame command. Only works from text area context menu at the moment. Modified Paths: -------------- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/TextAreaContextMenu.java Added Paths: ----------- plugins/SVNPlugin/trunk/src/ise/plugin/svn/action/BlameAction.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/command/Blame.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BasicBlamePaneUI.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlameModel.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlamePane.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlamePaneUI.java Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/action/BlameAction.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/action/BlameAction.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/action/BlameAction.java 2008-05-07 04:00:25 UTC (rev 12580) @@ -0,0 +1,151 @@ +/* +Copyright (c) 2007, Dale Anson +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +* Neither the name of the author nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package ise.plugin.svn.action; + +import ise.plugin.svn.gui.OutputPanel; + +import ise.plugin.svn.SVNPlugin; +import ise.plugin.svn.command.Blame; +import ise.plugin.svn.data.LogData; +import ise.plugin.svn.io.ConsolePrintStream; +import ise.plugin.svn.library.swingworker.*; +import ise.plugin.svn.gui.component.*; +import java.awt.event.ActionEvent; +import java.io.*; +import java.util.*; +import java.util.logging.*; +import org.gjt.sp.jedit.View; + +/** + * ActionListener to perform an svn blame. + * This is not dependent on ProjectViewer. + */ +public class BlameAction extends SVNAction { + + private List<String> paths = null; + private boolean pathsAreUrls = false; + private LogData data = null; + + /** + * @param view the View in which to display results + * @param paths a list of paths to be processed (note that the Blame.java class only handles one file at a time.) + * @param username the username for the svn repository + * @param password the password for the username + */ + public BlameAction( View view, List<String> paths, String username, String password ) { + super( view, "Blame" ); + if ( paths == null ) + throw new IllegalArgumentException( "paths may not be null" ); + this.paths = paths; + setUsername( username ); + setPassword( password ); + } + + public BlameAction( View view, LogData data ) { + super( view, "Blame" ); + if ( data == null ) + throw new IllegalArgumentException( "data may not be null" ); + if ( data.getPaths() == null ) + throw new IllegalArgumentException( "paths may not be null" ); + this.paths = data.getPaths(); + this.pathsAreUrls = data.pathsAreURLs(); + setUsername( data.getUsername() ); + setPassword( data.getPassword() ); + } + + public void actionPerformed( ActionEvent ae ) { + if ( paths != null && paths.size() > 0 ) { + data = new LogData(); + data.setPaths( paths ); + data.setPathsAreURLs( pathsAreUrls ); + + if ( getUsername() == null ) { + verifyLogin( paths.get( 0 ) ); + if ( isCanceled() ) { + return ; + } + data.setUsername( getUsername() ); + data.setPassword( getPassword() ); + } + + data.setOut( new ConsolePrintStream( getView() ) ); + + getView().getDockableWindowManager().showDockableWindow( "subversion" ); + final OutputPanel panel = SVNPlugin.getOutputPanel( getView() ); + panel.showConsole(); + final Logger logger = panel.getLogger(); + logger.log( Level.INFO, "Fetching annotation info ..." ); + for ( Handler handler : logger.getHandlers() ) { + handler.flush(); + } + + class Runner extends SwingWorker < ArrayList<String> , Object > { + + @Override + public ArrayList<String> doInBackground() { + try { + Blame blame = new Blame(); + return blame.getBlame( data ); + } + catch ( Exception e ) { + data.getOut().printError( e.getMessage() ); + } + finally { + data.getOut().close(); + } + return null; + } + + @Override + protected void done() { + try { + logger.log( Level.INFO, "Formatting annotation info ..." ); + BlameModel model = new BlameModel(); + model.setBlame( get() ); + model.setTextArea( getView().getEditPane().getTextArea() ); + BlamePane pane = new BlamePane(); + pane.setModel( model ); + getView().getEditPane().getTextArea().addLeftOfScrollBar( pane ); + getView().getEditPane().getTextArea().addTopComponent( pane.getCloser( getView() ) ); + getView().getEditPane().getTextArea().addCaretListener( pane ); + getView().invalidate(); + getView().validate(); + + } + catch ( Exception e ) { + // ignored + e.printStackTrace(); + } + } + } + ( new Runner() ).execute(); + + } + } +} \ No newline at end of file Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/command/Blame.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/command/Blame.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/command/Blame.java 2008-05-07 04:00:25 UTC (rev 12580) @@ -0,0 +1,133 @@ +/* +Copyright (c) 2007, Dale Anson +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +* Neither the name of the author nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package ise.plugin.svn.command; + +import java.io.*; +import java.util.*; + +import org.tmatesoft.svn.cli.command.SVNCommandEventProcessor; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.wc.ISVNAnnotateHandler; +import org.tmatesoft.svn.core.wc.ISVNOptions; +import org.tmatesoft.svn.core.wc.SVNClientManager; +import org.tmatesoft.svn.core.wc.SVNLogClient; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc.SVNWCUtil; + +import org.tmatesoft.svn.core.SVNException; + +import ise.plugin.svn.data.LogData; + + +public class Blame { + + private ArrayList<String> results = new ArrayList<String>(); + private PrintStream out = null; + + /** + * @return a list of revision and author, one entry per line of the file. + */ + public ArrayList<String> getBlame( LogData data ) throws CommandInitializationException, SVNException { + SVNKit.setupLibrary(); + + // validate data values + if ( data.getPaths() == null ) { + return null; // nothing to do + } + if ( data.getOut() == null ) { + throw new CommandInitializationException( "Invalid output stream." ); + } + if ( data.getErr() == null ) { + data.setErr( data.getOut() ); + } + + // convert first path to a file. This method only works on one file at + // a time. + String path = data.getPaths().get( 0 ); + File file = null; + if ( !data.pathsAreURLs() ) { + file = new File( path ); + } + + // use default svn config options + ISVNOptions options = SVNWCUtil.createDefaultOptions( true ); + + // use the svnkit client manager + SVNClientManager clientManager = SVNClientManager.newInstance( options, data.getUsername(), data.getDecryptedPassword() ); + + // get a client + SVNLogClient client = clientManager.getLogClient(); + + // set an event handler so that messages go to the commit data streams for display + client.setEventHandler( new SVNCommandEventProcessor( data.getOut(), data.getErr(), false ) ); + + out = data.getOut(); + + ISVNAnnotateHandler handler = new ISVNAnnotateHandler() { + public void handleLine( Date date, long revision, + String author, String line ) { + results.add( revision + " " + author ); + } + }; + + if ( data.pathsAreURLs() ) { + SVNURL svnurl = SVNURL.parseURIDecoded( path ); + client.doAnnotate( svnurl, SVNRevision.create( 0L ), data.getStartRevision(), data.getEndRevision(), handler ); + } + else { + client.doAnnotate( file, SVNRevision.HEAD, data.getStartRevision(), data.getEndRevision(), handler ); + } + + out.flush(); + out.close(); + + return results; + } + public static void main (String[] args) { + // for testing + LogData data = new LogData(); + data.setUsername("danson"); + data.setPassword(""); + List<String> paths = new ArrayList<String>(); + paths.add("/home/danson/tmp/anothertest/test3/test/BigIntModTest2.java"); + data.setPaths(paths); + data.setOut(new ise.plugin.svn.io.ConsolePrintStream(new ise.plugin.svn.io.LogOutputStream(null))); + Blame blame = new Blame(); + try { + org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory.setup(); + org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl.setup(); + org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory.setup(); + ArrayList<String> results = blame.getBlame(data); + System.out.println(results); + } + catch(Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file Modified: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/TextAreaContextMenu.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/TextAreaContextMenu.java 2008-05-07 03:58:32 UTC (rev 12579) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/TextAreaContextMenu.java 2008-05-07 04:00:25 UTC (rev 12580) @@ -113,6 +113,9 @@ item = new JMenuItem( "Log..." ); item.addActionListener( getLogActionListener() ); add( item ); + item = new JMenuItem( "Blame..." ); + item.addActionListener( getBlameActionListener() ); + add( item ); item = new JMenuItem( "Properties..." ); item.addActionListener( getPropertyActionListener() ); add( item ); @@ -237,6 +240,15 @@ }; } + private ActionListener getBlameActionListener() { + return new ActionListener() { + public void actionPerformed( ActionEvent ae ) { + BlameAction action = new BlameAction( view, getPaths(), null, null ); + action.actionPerformed( ae ); + } + }; + } + private ActionListener getPropertyActionListener() { return new ActionListener() { public void actionPerformed( ActionEvent ae ) { Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BasicBlamePaneUI.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BasicBlamePaneUI.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BasicBlamePaneUI.java 2008-05-07 04:00:25 UTC (rev 12580) @@ -0,0 +1,128 @@ +/* +* Copyright (c) 2008, Dale Anson +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package ise.plugin.svn.gui.component; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.plaf.ComponentUI; + +public class BasicBlamePaneUI extends BlamePaneUI implements ChangeListener { + + private BlamePane blamePane; + private BlameRendererPane blameRendererPane; + + public static ComponentUI createUI( JComponent c ) { + return new BasicBlamePaneUI(); + } + + public void installUI( JComponent c ) { + blamePane = ( BlamePane ) c; + blamePane.setLayout( createLayoutManager() ); + installDefaults(); + installComponents(); + installListeners(); + + } + + public void uninstallUI( JComponent c ) { + c.setLayout( null ); + uninstallListeners(); + uninstallComponents(); + uninstallDefaults(); + + blamePane = null; + } + + public void installDefaults() {} + + public void installComponents() { + blameRendererPane = new BlameRendererPane(); + blamePane.add( blameRendererPane, BorderLayout.CENTER ); + } + + public void installListeners() { + blamePane.addChangeListener( this ); + } + + public void uninstallDefaults() {} + + public void uninstallComponents() { + blamePane.remove( blameRendererPane ); + blamePane = null; + } + + public void uninstallListeners() { + blamePane.removeChangeListener( this ); + } + + protected LayoutManager createLayoutManager() { + return new BorderLayout(); + } + + public void stateChanged( ChangeEvent event ) { + blameRendererPane.repaint(); + } + + public class BlameRendererPane extends JPanel { + + public BlameRendererPane( ) { + BlameModel model = blamePane.getModel(); + Dimension dim = getPreferredSize(); + if ( model == null ) { + dim.width = 60; + setPreferredSize( dim ); + } + else { + int max_width = 0; + FontMetrics fm = model.getTextArea().getPainter().getFontMetrics(); + for ( String line : model.getBlame() ) { + int width = fm.stringWidth( line ); + max_width = width > max_width ? width : max_width; + } + dim.width = max_width + 3; + setPreferredSize( dim ); + } + } + + public void paintComponent( Graphics gfx ) { + super.paintComponent( gfx ); + + Rectangle size = getBounds(); + gfx.setColor( getBackground() ); + gfx.fillRect( 0, 0, size.width, size.height ); + + // get the visible lines, draw the corresponding blame lines + BlameModel model = blamePane.getModel(); + int pixelsPerLine = model.getTextArea().getPainter().getFontMetrics().getHeight(); + int firstLine = model.getTextArea().getFirstPhysicalLine(); + int lastLine = model.getTextArea().getLastPhysicalLine(); + gfx.setColor( Color.BLACK ); + java.util.List<String> blame = model.getBlame(); + for ( int i = firstLine; i <= lastLine; i++ ) { + int offset = i - firstLine; + if ( offset >= 0 && offset < blame.size() ) { + gfx.drawString( blame.get( i ), 3, ( i - firstLine + 1 ) * pixelsPerLine ); + } + } + } + } +} \ No newline at end of file Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlameModel.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlameModel.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlameModel.java 2008-05-07 04:00:25 UTC (rev 12580) @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2008, Dale Anson +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package ise.plugin.svn.gui.component; + +import java.util.List; +import org.gjt.sp.jedit.textarea.JEditTextArea; + +public class BlameModel { + + private JEditTextArea textArea = null; + private List<String> blame = null; + + public BlameModel() { + + } + + public BlameModel(JEditTextArea textarea, List<String> blame) { + this.textArea = textarea; + this.blame = blame; + } + + public void setTextArea(JEditTextArea textarea) { + textArea = textarea; + } + + public JEditTextArea getTextArea() { + return textArea; + } + + public void setBlame(List<String> blame) { + this.blame = blame; + } + + public List<String> getBlame() { + return blame; + } +} \ No newline at end of file Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlamePane.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlamePane.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlamePane.java 2008-05-07 04:00:25 UTC (rev 12580) @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2008, Dale Anson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +package ise.plugin.svn.gui.component; + +import java.util.*; + +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.*; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.gjt.sp.jedit.View; +import org.gjt.sp.jedit.textarea.JEditTextArea; + +public class BlamePane extends JComponent implements CaretListener { + + private static final String uiClassID = "BlamePaneUI"; + private Set<ChangeListener> changeListeners = new HashSet<ChangeListener>(); + private BlameModel model = null; + + public BlamePane() { + updateUI(); + } + + public void setUI( BlamePaneUI ui ) { + super.setUI( ui ); + } + + public void updateUI() { + if ( UIManager.get( getUIClassID() ) != null ) { + setUI( ( BlamePaneUI ) UIManager.getUI( this ) ); + } + else { + setUI( new BasicBlamePaneUI() ); + } + } + + public BlamePaneUI getUI() { + return ( BlamePaneUI ) ui; + } + + public String getUIClassID() { + return uiClassID; + } + + public void caretUpdate( final CaretEvent e ) { + if ( e.getSource() instanceof JEditTextArea ) { + fireStateChanged(); + } + } + + public void addChangeListener( ChangeListener cl ) { + if ( cl != null ) { + changeListeners.add( cl ); + } + } + + public void removeChangeListener( ChangeListener cl ) { + if ( cl != null ) { + changeListeners.remove( cl ); + } + } + + public void fireStateChanged() { + if ( changeListeners.size() > 0 ) { + ChangeEvent event = new ChangeEvent( this ); + for ( ChangeListener cl : changeListeners ) { + cl.stateChanged( event ); + } + } + } + + /** + * Model is a list of strings, one per line in the source file. Each string + * in the model provides the blame information about that line, probably just + * author and revision. This list is provided by the i.p.s.command.Blame command. + */ + public void setModel( BlameModel model ) { + this.model = model; + updateUI(); + } + + public BlameModel getModel() { + return model; + } + + public JPanel getCloser(final View view) { + final JPanel panel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + JButton button = new JButton("Close Blame"); + panel.add(button); + button.addActionListener( + new ActionListener() { + public void actionPerformed( ActionEvent ae ) { + getUI().uninstallUI(BlamePane.this); + view.getEditPane().getTextArea().removeTopComponent(panel); + view.getEditPane().getTextArea().removeLeftOfScrollBar(BlamePane.this); + model.getTextArea().removeCaretListener(BlamePane.this); + view.invalidate(); + view.validate(); + } + } + ); + return panel; + } +} Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlamePaneUI.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlamePaneUI.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/component/BlamePaneUI.java 2008-05-07 04:00:25 UTC (rev 12580) @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008, Dale Anson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +package ise.plugin.svn.gui.component; + +import javax.swing.plaf.ComponentUI; + +public abstract class BlamePaneUI extends ComponentUI { +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |