/*
*
* Perforce/JBuilder Opentool
* Copyright (C) 2002 Mark Ackerman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.dafreels.opentools.actions.ui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.text.*;
import javax.swing.table.*;
import javax.swing.event.*;
import java.util.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.dnd.peer.*;
import java.io.*;
import com.dafreels.opentools.actions.*;
import com.dafreels.opentools.properties.*;
import com.dafreels.opentools.*;
import com.dafreels.vcs.command.*;
import com.dafreels.vcs.util.*;
import com.borland.primetime.actions.*;
import com.borland.primetime.ide.*;
/**
* <p>Title: Perforce Open Tool </p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2002</p>
* <p>Company: RMA</p>
* @author Mark Ackerman
*
*/
public class ChangeListDialog extends JDialog
{
private static final String SLASH_SLASH = "//";
private static final String DEFAULT = "default";
private static final String CHANGE = "change";
private static final String NEW = "new";
private DnDJTree _changeListTree;
private DefaultMutableTreeNode _root;
private JPopupMenu _changeNodePopup, _rootNodePopup, _fileNodePopup;
private AbstractAction _newChangeListAction,
_revertAllAction, // revert all files
_revertAction, // revert a single file
_submitAction, // submit the changelist
_refreshAction, // _refresh the dialog
_diffAction, // diff a file
_deleteChangeListAction, // delete an empty changelist
_propertiesAction, // properties for a file
_historyAction,
_lockAction,
_unlockAction;
private JMenuItem _submitActionMenu,
_deleteChangeListActionMenu,
_lockActionMenu,
_unlockActionMenu;
private boolean _hasPacked = false;
/**
*
* <p>Title: Perforce Opentool</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: </p>
* @author Mark Ackerman
* @version 1.0
*/
private class ChangeNode extends DefaultMutableTreeNode
{
private String _description;
private String _toString;
ChangeNode(String change)
{
super(change);
}
public String getChangeNumber()
{
String changeDesc = (String)getUserObject();
if ( changeDesc.startsWith(DEFAULT))
{
return "default";
}
else if ( changeDesc.startsWith(CHANGE))
{
int idx = changeDesc.indexOf(" ");
return changeDesc.substring(idx+1);
}
return "";
}
public void setDescription(String desc)
{
_description = desc;
_toString = null;
}
public String toString()
{
if ( _toString == null )
{
if ( _description != null && _description.length() > 0 )
{
_toString = (String)getUserObject()+ " {"+_description+"}";
}
else
{
_toString = (String)getUserObject();
}
}
return _toString;
}
}
/**
*
* <p>Title: Perforce Opentool</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: </p>
* @author Mark Ackerman
* @version 1.0
*/
private class ChangeFileNode extends DefaultMutableTreeNode
{
private ChangeInfo _changeInfo;
ChangeFileNode(ChangeInfo info)
{
super(info);
_changeInfo = info;
}
public String toString()
{
return _changeInfo.toString();
}
public boolean isLocked()
{
return _changeInfo.isLocked();
}
public boolean isAdd()
{
return _changeInfo.isAdd();
}
public boolean isEdit()
{
return _changeInfo.isEdit();
}
public boolean isDelete()
{
return _changeInfo.isDelete();
}
public boolean getIntegrate()
{
return _changeInfo.getIntegrate();
}
public boolean getAllowsChildren()
{
return false;
}
public String getFile()
{
return _changeInfo.getFile();
}
public String getFileNoRevision()
{
String file = _changeInfo.getFile();
int idx = file.indexOf("#");
if ( idx > -1 )
{
return file.substring(0, idx);
}
idx = file.indexOf("@");
if ( idx > -1 )
{
return file.substring(0, idx);
}
return file;
}
}
/**
* Renderer for the ChangeListTree
*
* @author Mark Ackerman
*
*/
public class ChangeListTreeRenderer extends DefaultTreeCellRenderer
{
private HashMap _iconMap = new HashMap();
private TreeIcon _icon;
private Icon _rootIcon;
private Icon _folderIcon;
public ChangeListTreeRenderer()
{
_icon = new TreeIcon(false);
_rootIcon = ActionImages.P4_CHANGELIST_ROOT;
_folderIcon = ActionImages.P4_CHANGELIST_NODE;
}
/**
* Configures the renderer based on the passed in components.
* The value is set from messaging the tree with
* <code>convertValueToText</code>, which ultimately invokes
* <code>toString</code> on <code>value</code>.
* The foreground color is set based on the selection and the icon
* is set based on on leaf and expanded.
*/
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel,
boolean expanded,
boolean leaf, int row,
boolean hasFocus)
{
String stringValue = tree.convertValueToText(value, sel,
expanded, leaf, row, hasFocus);
this.hasFocus = hasFocus;
setText(stringValue);
if(sel)
setForeground(getTextSelectionColor());
else
setForeground(getTextNonSelectionColor());
if (!tree.isEnabled())
{
setEnabled(false);
if (leaf)
{
setDisabledIcon(getLeafIcon(value, row));
}
else if (expanded)
{
setDisabledIcon(getOpenIcon(value, row));
}
else
{
setDisabledIcon(getClosedIcon(value, row));
}
}
else
{
setEnabled(true);
if (leaf)
{
setIcon(getLeafIcon(value, row));
}
else if (expanded)
{
setIcon(getOpenIcon(value, row));
}
else
{
setIcon(getClosedIcon(value, row));
}
}
setComponentOrientation(tree.getComponentOrientation());
selected = sel;
return this;
}
Icon getLeafIcon(Object value, int row)
{
if ( value == null ) return super.getLeafIcon();
Icon icon = getIcon(value, row);
if ( icon == null ) return super.getLeafIcon();
return icon;
}
Icon getOpenIcon(Object value, int row)
{
if ( value == null ) return super.getOpenIcon();
Icon icon = getIcon(value, row);
if ( icon == null ) return super.getOpenIcon();
return icon;
}
Icon getClosedIcon(Object value, int row)
{
if ( value == null ) return super.getClosedIcon();
Icon icon = getIcon(value, row);
if ( icon == null ) return super.getClosedIcon();
return icon;
}
Icon getIcon(Object value, int row)
{
Class cls = value.getClass();
Icon icon = null;
if ( value == _root )
{
return _rootIcon;
}
if ( value instanceof ChangeFileNode )
{
ChangeFileNode cn = (ChangeFileNode)value;
_icon.setAdd(cn.isAdd());
_icon.setDelete(cn.isDelete());
_icon.setLocked(cn.isLocked());
_icon.setEdit(cn.isEdit());
_icon.setIntegrate(cn.getIntegrate());
return _icon;
}
return _folderIcon;
}
}
/**
* create a new ChangeList dialog
* @param parent the Frame owner
* @param modal true for a modal dialog
*/
public ChangeListDialog(Frame parent, boolean modal)
{
super(parent, modal);
getContentPane().setLayout(new BorderLayout());
JPanel centerPanel = new JPanel(new GridBagLayout());
getContentPane().add(centerPanel, BorderLayout.CENTER);
createToolbar();
setTitle("Pending ChangeLists");
_root = new DefaultMutableTreeNode("Pending ChangeLists (client "+Main.m_props.getClientSpec()+")");
_changeListTree = new DnDJTree(_root, parent);
_changeListTree.setCellRenderer(new ChangeListTreeRenderer());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 1;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.fill = GridBagConstraints.BOTH;
gbc.insets = new Insets(5,5,0,5);
gbc.weightx = 1.0;
gbc.weighty = 1.0;
centerPanel.add(new JScrollPane(_changeListTree), gbc);
JButton okButton = new JButton("Close");
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 1;
gbc.anchor = GridBagConstraints.SOUTH;
gbc.fill = GridBagConstraints.NONE;
gbc.insets = new Insets(5,5,0,5);
centerPanel.add(okButton, gbc);
okButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setVisible(false);
dispose();
}
});
createFileNodePopup();
_changeListTree.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
if ( e.isPopupTrigger() || SwingUtilities.isRightMouseButton(e))
{
TreePath path = _changeListTree.getSelectionPath();
if ( path == null )
{
path = _changeListTree.getPathForLocation(e.getX(), e.getY());
if ( path == null )
{
return;
}
_changeListTree.setSelectionPath(path);
}
DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
JPopupMenu popup = null;
if ( node == _root )
{
if ( _rootNodePopup == null )
{
_rootNodePopup = createRootNodePopup();
}
popup = _rootNodePopup;
}
else if ( node instanceof ChangeNode )
{
if ( _changeNodePopup == null )
{
_changeNodePopup = createChangeNodePopup();
}
popup = _changeNodePopup;
boolean hasChildren = node.getChildCount() == 0;
_submitActionMenu.setVisible(!hasChildren);
_deleteChangeListActionMenu.setVisible(hasChildren);
}
else if ( node instanceof ChangeFileNode )
{
if ( _fileNodePopup == null )
{
_fileNodePopup = createFileNodePopup();
}
popup = _fileNodePopup;
}
if ( popup == null )
{
return;
}
popup.show(_changeListTree, e.getX(), e.getY());
}
}
});
_changeListTree.addTreeSelectionListener(new TreeSelectionListener()
{
public void valueChanged(TreeSelectionEvent e)
{
TreePath path = e.getNewLeadSelectionPath();
if ( path == null )
{
_diffAction.setEnabled(false);
_submitAction.setEnabled(false);
return;
}
Object obj = path.getLastPathComponent();
if ( obj instanceof ChangeFileNode )
{
_diffAction.setEnabled(true);
_submitAction.setEnabled(true);
ChangeFileNode cfnode = (ChangeFileNode)obj;
if ( cfnode.isLocked() )
{
_lockActionMenu.setVisible(false);
_unlockActionMenu.setVisible(true);
}
else
{
_lockActionMenu.setVisible(true);
_unlockActionMenu.setVisible(false);
}
}
else if ( obj instanceof ChangeNode )
{
_diffAction.setEnabled(false);
_submitAction.setEnabled(true);
}
else
{
_diffAction.setEnabled(false);
_submitAction.setEnabled(false);
}
}
});
getRootPane().registerKeyboardAction( new ActionListener() {
public void actionPerformed(ActionEvent e) { refreshDialog(); }
}, KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0, true),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
}
private void createToolbar()
{
ActionGroup ag = new ActionGroup();
ag.add(getRefreshAction());
ag.add(getRevertAllFilesAction());
ag.add(getNewChangeListAction());
ag.add(getSubmitChangeListAction());
ag.add(getDiffAction());
ActionToolBar toolbar = new ActionToolBar(this, ag);
/*
JToolBar toolbar = new JToolBar();
toolbar.add(getRefreshAction());
toolbar.addSeparator();
toolbar.add(getRevertFilesAction());
toolbar.addSeparator();
toolbar.add(getSubmitChangeListAction());
toolbar.addSeparator();
toolbar.add(getDiffAction());
*/
getContentPane().add(toolbar,BorderLayout.NORTH);
}
private JPopupMenu createRootNodePopup()
{
JPopupMenu menu = new JPopupMenu();
menu.add(getNewChangeListAction());
menu.add(getRefreshAction());
return menu;
}
private JPopupMenu createChangeNodePopup()
{
JPopupMenu menu = new JPopupMenu();
_submitActionMenu = new JMenuItem(getSubmitChangeListAction());
menu.add(_submitActionMenu);
_deleteChangeListActionMenu = new JMenuItem(getDeleteChangeListAction());
menu.add(_deleteChangeListActionMenu);
menu.addSeparator();
menu.add(getRevertAllFilesAction());
menu.addSeparator();
menu.add(getNewChangeListAction());
menu.add(getRefreshAction());
return menu;
}
private JPopupMenu createFileNodePopup()
{
JPopupMenu popupMenu = new JPopupMenu();
popupMenu.add(getSubmitChangeListAction());
popupMenu.addSeparator();
popupMenu.add(getDiffAction());
_lockActionMenu = new JMenuItem(getLockAction());
_lockActionMenu.setVisible(false);
popupMenu.add(_lockActionMenu);
_unlockActionMenu = new JMenuItem(getUnlockAction());
_unlockActionMenu.setVisible(false);
popupMenu.add(_unlockActionMenu);
popupMenu.add(getHistoryAction());
popupMenu.add(getPropertiesAction());
popupMenu.addSeparator();
popupMenu.add(getRevertFileAction());
return popupMenu;
}
/**
* get the Revert All Files Action
* @return
*/
private Action getRevertAllFilesAction()
{
if ( _revertAllAction == null )
{
_revertAllAction = new AbstractAction("Revert Unchanged Files")
{
public void actionPerformed(ActionEvent e)
{
revertFiles();
}
};
_revertAllAction.putValue(Action.SMALL_ICON, ActionImages.P4_REVERT);
_revertAllAction.putValue(Action.SHORT_DESCRIPTION, "Revert Selected Files");
}
return _revertAllAction;
}
private Action getRevertFileAction()
{
if ( _revertAction == null )
{
_revertAction = new AbstractAction("Revert")
{
public void actionPerformed(ActionEvent e)
{
revertFiles();
}
};
_revertAction.putValue(Action.SMALL_ICON, ActionImages.P4_REVERT);
_revertAction.putValue(Action.SHORT_DESCRIPTION, "Revert Changes to File");
}
return _revertAction;
}
private Action getLockAction()
{
if ( _lockAction == null )
{
_lockAction = new AbstractAction("Lock")
{
public void actionPerformed(ActionEvent e)
{
lockFiles();
}
};
_lockAction.putValue(Action.SMALL_ICON, ActionImages.P4_LOCK);
_lockAction.putValue(Action.SHORT_DESCRIPTION, "Lock File at Depot");
}
return _lockAction;
}
private Action getUnlockAction()
{
if ( _unlockAction == null )
{
_unlockAction = new AbstractAction("Unlock")
{
public void actionPerformed(ActionEvent e)
{
unlockFiles();
}
};
_unlockAction.putValue(Action.SMALL_ICON, ActionImages.P4_UNLOCK);
_unlockAction.putValue(Action.SHORT_DESCRIPTION, "Unlock File at Depot");
}
return _unlockAction;
}
/**
*
* @return
*/
private Action getHistoryAction()
{
if ( _historyAction == null )
{
_historyAction = new AbstractAction("Revision History")
{
public void actionPerformed(ActionEvent e)
{
history();
}
};
_historyAction.putValue(Action.SMALL_ICON, ActionImages.P4_HISTORY);
_historyAction.putValue(Action.SHORT_DESCRIPTION, "Show Revision History");
}
return _historyAction;
}
/**
*
* @return
*/
private Action getPropertiesAction()
{
if ( _propertiesAction == null )
{
_propertiesAction = new AbstractAction("Properties...")
{
public void actionPerformed(ActionEvent e)
{
properties();
}
};
_propertiesAction.putValue(Action.SHORT_DESCRIPTION, "Display File Information");
}
return _propertiesAction;
}
/**
* get the Diff Action
* @return
*/
private Action getDiffAction()
{
if ( _diffAction == null )
{
_diffAction = new AbstractAction("Diff")
{
public void actionPerformed(ActionEvent e)
{
diff();
}
};
// not yet implemented
_diffAction.putValue(Action.SMALL_ICON, ActionImages.P4_DIFF);
_diffAction.putValue(Action.SHORT_DESCRIPTION, "Diff vs. Depot File");
}
return _diffAction;
}
/**
* get the Submit Changelist Action
* @return
*/
private Action getSubmitChangeListAction()
{
if ( _submitAction == null )
{
_submitAction = new AbstractAction("Submit...")
{
public void actionPerformed(ActionEvent e)
{
TreePath[] paths = _changeListTree.getSelectionPaths();
if ( paths == null )
{
return;
}
ArrayList files = new ArrayList(paths.length);
ChangeNode changeNode = null;
for (int i = 0; i < paths.length; i++ )
{
Object obj = paths[i].getLastPathComponent();
if ( obj instanceof ChangeFileNode )
{
if ( changeNode != null )
{
if ( ((ChangeFileNode)obj).getParent() != changeNode)
{
continue;
}
}
changeNode = (ChangeNode)((ChangeFileNode)obj).getParent();
files.add(((ChangeFileNode)obj).getFileNoRevision());
}
else if ( obj instanceof ChangeNode )
{
if ( changeNode == null )
{
changeNode = (ChangeNode)obj;
}
}
else
{
continue;
}
}
if ( changeNode != null )
{
String changeNumber = changeNode.getChangeNumber();
if ( ChangeListDialog.DEFAULT.equals(changeNumber))
{
changeNumber = null;
}
if ( new SubmitAction().submit(changeNumber, files))
{
refreshDialog();
}
}
}
};
_submitAction.putValue(Action.SMALL_ICON, ActionImages.P4_SUBMIT);
_submitAction.putValue(Action.SHORT_DESCRIPTION, "Submit the ChangeList");
}
return _submitAction;
}
private Action getDeleteChangeListAction()
{
if ( _deleteChangeListAction == null )
{
_deleteChangeListAction = new AbstractAction("Delete Empty Changelist")
{
public void actionPerformed(ActionEvent e)
{
TreePath path = _changeListTree.getSelectionPath();
Object obj = path.getLastPathComponent();
if ( obj instanceof ChangeNode )
{
ChangeNode cnode = (ChangeNode)obj;
if ( cnode.getChildCount() == 0 )
{
CommandTool.runCommand("change -d " + cnode.getChangeNumber(),
Main.m_props);
MessageWriter.outputErrorMessages(MessageFormatter.getInstance());
refreshDialog();
}
}
}
};
}
return _deleteChangeListAction;
}
private Action getNewChangeListAction()
{
if ( _newChangeListAction == null )
{
_newChangeListAction = new AbstractAction("New ChangeList")
{
public void actionPerformed(ActionEvent e)
{
newChangeList();
refreshDialog();
}
};
_newChangeListAction.putValue(Action.SMALL_ICON, ActionImages.P4_CHANGELIST_NEW);
_newChangeListAction.putValue(Action.SHORT_DESCRIPTION, "Create a new ChangeList");
}
return _newChangeListAction;
}
private void newChangeList()
{
CommandTool.runCommand(new Command(Command.CHANGELIST_NEW), Main.m_props);
MessageWriter.outputErrorMessages(MessageFormatter.getInstance());
java.util.Vector data = new java.util.Vector();
java.util.Vector files = new java.util.Vector();
java.util.Vector dataInteg = new java.util.Vector();
//Create a file list
String tmp = "";
//while(cl.indexOf(newLine) != -1)
//Get a list of files
int idx;
while( (tmp = MessageFormatter.getNextMessage()) != null)
{
data = new java.util.Vector();
//tmp = cl.substring(0, cl.indexOf(newLine));
//cl = cl.substring(cl.indexOf(newLine) + newLine.length());
if((idx = tmp.lastIndexOf("//")) != -1)
{
tmp = tmp.substring(idx);//tmp.lastIndexOf("//"));
}
if((idx = tmp.indexOf("#")) > -1)
{
tmp = tmp.substring(0, idx); //tmp.indexOf("#"));
}
if(!dataInteg.contains(tmp) && tmp.indexOf("//") == 0)
{
data.add(new Boolean("true"));
tmp = tmp.trim();
data.add(tmp);
dataInteg.add(tmp);
files.add(data);
}
}
dataInteg = null;
SubmitDialog dialog = new SubmitDialog((Frame)getParent(),
"Perforce Change Specification", true);
dialog.showSubmit(null, files, null);
if(!dialog.getState())
{
return;
}
String newLine = System.getProperty("line.separator");
StringBuffer changeList = new StringBuffer("Change: ");
changeList.append(dialog.getChangeNumber());
changeList.append(newLine);
changeList.append(" "+newLine);
changeList.append("Client: "+PerforceGroup.CLIENTSPEC.getValue(Browser.getActiveBrowser().getActiveProject())+newLine);
changeList.append(" "+newLine);
changeList.append("User: "+PerforceGroup.USERNAME.getValue(Browser.getActiveBrowser().getActiveProject())+newLine);
changeList.append(" "+newLine);
changeList.append("Status: ");
changeList.append(dialog.getStatus());
changeList.append(newLine);
changeList.append(" "+newLine);
changeList.append("Description: "+newLine);
//Add the description given by the user
changeList.append(dialog.getDescription());
changeList.append(" "+newLine);
changeList.append("Files: "+newLine);
//Get the files list from the dialog
files = dialog.getFiles();
Vector v;
//Add the files to the changeList
for(int i = 0; i < files.size(); i++)
{
v = (Vector) files.elementAt(i);
changeList.append("\t"+v.elementAt(1)+newLine);
}
//Create the command
StringBuffer sb = new StringBuffer("change -i");
//Run the command
CommandTool.runCommand(sb.toString(), true, true, false, Main.m_props);
while(!CommandTool.isStreamReady())
{
//do nothing
}
CommandTool.writeToOut(changeList.toString());
//Output the p4 messages
MessageWriter.outputErrorMessages(MessageFormatter.getInstance());
if ( Main.m_props.showOutput())
{
MessageWriter.outputMessages(MessageFormatter.getInstance());
}
refreshDialog();
}
private Action getRefreshAction()
{
if ( _refreshAction == null )
{
_refreshAction = new AbstractAction("Refresh F5")
{
public void actionPerformed(ActionEvent e)
{
refreshDialog();
}
};
_refreshAction.putValue(Action.SMALL_ICON, ActionImages.P4_REFRESH);
_refreshAction.putValue(Action.SHORT_DESCRIPTION, "Refresh");
}
return _refreshAction;
}
/**
* rerun the opened command
*/
protected void refreshDialog()
{
try
{
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
//Run the command
CommandTool.runCommand(new Command(Command.OPENED), Main.m_props);
//Output the p4 messages
MessageWriter.outputErrorMessages(MessageFormatter.getInstance());
fillForm(MessageFormatter.getInstance());
}
finally
{
setCursor(Cursor.getDefaultCursor());
}
}
private void history()
{
TreePath[] paths = _changeListTree.getSelectionPaths();
if ( paths == null || paths.length == 0 )
{
return;
}
DefaultMutableTreeNode node;
for (int i = 0; i < paths.length; i++ )
{
node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
if ( node instanceof ChangeFileNode )
{
fileHistory(((ChangeFileNode)node).getFile());
}
}
}
private void fileHistory(String fileName)
{
Command cmd = new Command(Command.FILEHISTORY);
cmd.addPath(fileName);
CommandTool.runCommand(cmd, Main.m_props);
HistoryDialog dialog = new HistoryDialog(Browser.getActiveBrowser(),
"File Information", false);
dialog.fillForm(fileName, MessageFormatter.getInstance());
dialog.setVisible(true);
}
/**
* get the file properties for the selected files
*/
private void properties()
{
TreePath[] paths = _changeListTree.getSelectionPaths();
if ( paths == null || paths.length == 0 )
{
return;
}
DefaultMutableTreeNode node;
for (int i = 0; i < paths.length; i++ )
{
node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
if ( node instanceof ChangeFileNode )
{
fileProperties(((ChangeFileNode)node).getFile());
}
}
}
/**
* run the fstat command for the file
* @param file
*/
private void fileProperties(String file)
{
Command cmd = new Command(Command.STATUS);
cmd.addPath(file);
CommandTool.runCommand(cmd, Main.m_props);
StatusDialog dialog = new StatusDialog(Browser.getActiveBrowser(),
"File Information", false);
dialog.fillForm(MessageFormatter.getInstance());
dialog.setVisible(true);
}
/**
* diff the selected files
*/
private void diff()
{
TreePath[] paths = _changeListTree.getSelectionPaths();
if ( paths == null || paths.length == 0 )
{
return;
}
DefaultMutableTreeNode node;
for (int i = 0; i < paths.length; i++ )
{
node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
if ( node instanceof ChangeFileNode )
{
diffFile(((ChangeFileNode)node).getFile());
}
}
}
/**
* run the diff command for the file
* @param file
*/
private void diffFile(String file)
{
// really should let the DiffAction handle this
Command cmd = new Command(Command.DIFF);
cmd.addPath(file);
//StringBuffer sb = new StringBuffer("diff -f ");
//sb.append(file);
//Run the command
//CommandTool.runCommand(sb.toString(), Main.m_props);
CommandTool.runCommand(cmd, Main.m_props);
//Output the p4 messages
MessageWriter.outputErrorMessages(MessageFormatter.getInstance());
MessageWriter.outputMessages(MessageFormatter.getInstance());
}
/**
* revert the selected files
*/
private void revertFiles()
{
TreePath[] paths = _changeListTree.getSelectionPaths();
if ( paths == null || paths.length == 0 )
{
return;
}
DefaultMutableTreeNode node;
ArrayList files = new ArrayList(paths.length);
for (int i = 0; i < paths.length; i++ )
{
node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
if ( node instanceof ChangeFileNode )
{
files.add(((ChangeFileNode)node).getFileNoRevision());
}
}
if ( files.size() > 0 )
{
revertFiles(files);
}
}
/**
* revert the files in the List files
* @param files the files to revert
*/
private void revertFiles(java.util.List files)
{
Command cmd = new Command(Command.REVERT);
cmd.addPaths(files);
java.util.List paths = cmd.getPaths();
if ( paths.size() == 0 )
{
return;
}
StringBuffer buf = new StringBuffer(200);
java.util.Iterator i = paths.iterator();
while (i.hasNext() )
{
buf.append(i.next());
if ( i.hasNext())
{
buf.append("<br>");
}
}
int opt = JOptionPane.showConfirmDialog(this,
"<html>Confirm Reverting of the following files:<br><font=+0 Color=blue>"+
buf.toString()+"</font></html>", "Changes will be lost",
JOptionPane.OK_CANCEL_OPTION);
if ( opt == JOptionPane.OK_OPTION )
{
CommandTool.runCommand(cmd, Main.m_props);
MessageWriter.outputErrorMessages(MessageFormatter.getInstance());
MessageWriter.outputMessages(MessageFormatter.getInstance());
refreshDialog();
}
}
/**
*
*/
private void unlockFiles()
{
TreePath[] paths = _changeListTree.getSelectionPaths();
if ( paths == null || paths.length == 0 )
{
return;
}
DefaultMutableTreeNode node;
ChangeFileNode cfNode;
ArrayList files = new ArrayList(paths.length);
for (int i = 0; i < paths.length; i++ )
{
node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
if ( node instanceof ChangeFileNode )
{
cfNode = (ChangeFileNode)node;
if ( cfNode.isLocked() )
{
files.add(cfNode.getFileNoRevision());
}
}
}
if ( files.size() > 0 )
{
lockFiles(files, Command.UNLOCK);
}
}
/**
* lock the selected files that aren't locked
*/
private void lockFiles()
{
TreePath[] paths = _changeListTree.getSelectionPaths();
if ( paths == null || paths.length == 0 )
{
return;
}
DefaultMutableTreeNode node;
ChangeFileNode cfNode;
ArrayList files = new ArrayList(paths.length);
for (int i = 0; i < paths.length; i++ )
{
node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
if ( node instanceof ChangeFileNode )
{
cfNode = (ChangeFileNode)node;
if ( !cfNode.isLocked() )
{
files.add(cfNode.getFileNoRevision());
}
}
}
if ( files.size() > 0 )
{
lockFiles(files, Command.LOCK);
}
}
private void lockFiles(java.util.List files, String perforceCmd)
{
Command cmd = new Command(perforceCmd);
cmd.addPaths(files);
CommandTool.runCommand(cmd, Main.m_props);
MessageWriter.outputErrorMessages(MessageFormatter.getInstance());
MessageWriter.outputMessages(MessageFormatter.getInstance());
refreshDialog();
}
/**
* fill this dialog with the contents of formatter
* @param formatter the output from the <code>opened</code> command
*/
public void fillForm(MessageFormatter formatter)
{
String message, arg;
SimpleAttributeSet attrs;
PropertyInterface props = Main.m_props;
DefaultListModel model = new DefaultListModel();
formatter.getNextMessage(); // throw away first line
MessageWriter.outputErrorMessages(MessageFormatter.getInstance());
int idx;
ChangeFileNode node;
ChangeInfo info;
ChangeNode changeNumberNode;
String file, cmd, change, type;
boolean locked;
_root.removeAllChildren();
while( (message = formatter.getNextMessage()) != null)
{
if ( !message.startsWith(SLASH_SLASH))
{
continue;
}
message = message.trim();
idx = message.indexOf(" - ");
if ( idx == -1 )
{
continue;
}
// format of message
//hecjavadev/code/hec/client/ClientWorkspace.java#1 - edit change 171 (text) *locked*
file = message.substring(0, idx);
message = message.substring(idx+3);
idx = message.indexOf(" ");
cmd = message.substring(0, idx);
message = message.substring(idx);
idx = message.indexOf("(");
change = message.substring(0, idx).trim();
message = message.substring(idx);
idx = message.indexOf(")");
type = message.substring(1,idx);
locked = message.endsWith("*locked*");
node = new ChangeFileNode(new ChangeInfo(file, cmd, type, locked));
changeNumberNode = findChangeNumberNode(change);
changeNumberNode.add(node);
}
// now get a list of any changes that don't show with opened
CommandTool.runCommand("changes -s pending", Main.m_props);
MessageWriter.outputErrorMessages(MessageFormatter.getInstance());
String client = Main.m_props.getUserName()+"@"+Main.m_props.getClientSpec();
String desc;
while( (message = formatter.getNextMessage()) != null)
{
// format of line is
// Change 208 on 2002/05/02 by mark@Q *pending* 'ResPrm '
if ( message.indexOf(client) > -1 )
{ // a line for my client
idx = message.indexOf(" ");
idx = message.indexOf(" ", idx+1);
change = message.substring(0, idx).toLowerCase();
changeNumberNode = findChangeNumberNode(change);
idx = message.indexOf("'");
desc = message.substring(idx+1, message.length()-2);
changeNumberNode.setDescription(desc);
}
}
// look for an integrations that need to be performed
CommandTool.runCommand("resolve -n", Main.m_props);
MessageWriter.outputErrorMessages(MessageFormatter.getInstance());
while ( (message = formatter.getNextMessage()) != null )
{
// format of line is
// <local file> - merging <depot file>#<num>
if ( (idx = message.indexOf("merging ")) > -1 )
{
idx+=8;
file = message.substring(idx).trim();
idx = file.indexOf("#");
if ( idx > -1 )
{
file = file.substring(0, idx);
}
node =findFileNode(file);
if ( node != null )
{
node._changeInfo.setIntegrate(true);
}
else
{
System.out.println("fillForm: failed to find file node for "
+file);
}
}
}
((DefaultTreeModel)_changeListTree.getModel()).nodeStructureChanged(_root);
int rows = _changeListTree.getRowCount();
for (int i = 0; i < rows; i++ )
{
_changeListTree.expandRow(i);
}
if ( !isVisible())
{
if ( !_hasPacked )
{
pack();
_hasPacked = true;
}
setLocationRelativeTo(getParent());
}
}
/**
* find the node in the tree with the filename of depotFileName
* @param depotFileName the name of the depot file
* @return the ChangeFileNode or null if not found
*/
ChangeFileNode findFileNode(String depotFileName)
{
if ( depotFileName == null )
{
return null;
}
Enumeration e = _root.children();
Enumeration childE;
ChangeNode node;
ChangeFileNode fileNode;
while ( e.hasMoreElements())
{
node = (ChangeNode)e.nextElement();
childE = node.children();
while (childE.hasMoreElements())
{
fileNode = (ChangeFileNode)childE.nextElement();
if (fileNode.getFileNoRevision().equals(depotFileName))
{
return fileNode;
}
}
}
return null;
}
ChangeNode findChangeNumberNode(String change)
{
Enumeration e = _root.children();
ChangeNode node;
while ( e.hasMoreElements() )
{
node = (ChangeNode)e.nextElement();
if ( change.equals(node.getUserObject()))
{
return node;
}
}
node = new ChangeNode(change);
if ( "default change".equals(change))
{
_root.insert(node, 0);
}
else
{
_root.add(node);
}
return node;
}
public class DnDJTree extends JTree
implements TreeSelectionListener,
DragGestureListener, DropTargetListener,
DragSourceListener
{
/** Stores the parent Dialog of the component */
private Frame _parent = null;
/** Stores the selected node info */
protected TreePath _selectedTreePath = null;
protected ChangeFileNode _selectedNode = null;
/** Variables needed for DnD */
private DragSource _dragSource = null;
private DragSourceContext _dragSourceContext = null;
/** Constructor
* @param root The root node of the tree
* @param parent Parent JFrame of the JTree
*/
public DnDJTree(DefaultMutableTreeNode root, Frame parent)
{
super(root);
_parent = parent;
addTreeSelectionListener(DnDJTree.this);
_dragSource = DragSource.getDefaultDragSource() ;
DragGestureRecognizer dgr =
_dragSource.createDefaultDragGestureRecognizer(
this, //DragSource
DnDConstants.ACTION_MOVE, //specifies valid actions
this //DragGestureListener
);
/* Eliminates right mouse clicks as valid actions - useful especially
* if you implement a JPopupMenu for the JTree
*/
dgr.setSourceActions(dgr.getSourceActions() & ~InputEvent.BUTTON3_MASK);
/* First argument: Component to associate the target with
* Second argument: DropTargetListener
*/
DropTarget dropTarget = new DropTarget(this, this);
//unnecessary, but gives FileManager look
putClientProperty("JTree.lineStyle", "Angled");
//MetalTreeUI ui = (MetalTreeUI) getUI();
}
/** Returns The selected node */
public ChangeFileNode getSelectedNode()
{
return _selectedNode;
}
///////////////////////// Interface stuff ////////////////////
/** DragGestureListener interface method */
public void dragGestureRecognized(DragGestureEvent e)
{
//Get the selected node
ChangeFileNode dragNode = getSelectedNode();
if (dragNode != null)
{
//Get the Transferable Object
Transferable transferable = (Transferable) dragNode.getUserObject();
if ( transferable == null )
{
return;
}
//Select the appropriate cursor;
Cursor cursor = DragSource.DefaultMoveNoDrop;
int action = e.getDragAction();
if (action == DnDConstants.ACTION_MOVE)
{
cursor = DragSource.DefaultMoveNoDrop;
}
//In fact the cursor is set to NoDrop because once an action is rejected
// by a dropTarget, the dragSourceListener are no more invoked.
// Setting the cursor to no drop by default is so more logical, because
// when the drop is accepted by a component, then the cursor is changed by the
// dropActionChanged of the default DragSource.
//begin the drag
_dragSource.startDrag(e, cursor, transferable, this);
}
}
/** DragSourceListener interface method */
public void dragDropEnd(DragSourceDropEvent dsde)
{
}
/** DragSourceListener interface method */
public void dragEnter(DragSourceDragEvent dsde)
{
DragSourceContext context = dsde.getDragSourceContext();
//intersection of the users selected action, and the source and target actions
int myaction = dsde.getDropAction();
if( (myaction & DnDConstants.ACTION_MOVE) != 0) {
context.setCursor(DragSource.DefaultCopyDrop);
} else {
context.setCursor(DragSource.DefaultCopyNoDrop);
}
}
/** DragSourceListener interface method */
public void dragOver(DragSourceDragEvent dsde)
{
DragSourceContext context = dsde.getDragSourceContext();
//intersection of the users selected action, and the source and target actions
int myaction = dsde.getDropAction();
if( (myaction & DnDConstants.ACTION_MOVE) != 0) {
context.setCursor(DragSource.DefaultCopyDrop);
} else {
context.setCursor(DragSource.DefaultCopyNoDrop);
}
}
/** DragSourceListener interface method */
public void dropActionChanged(DragSourceDragEvent dsde)
{
}
/** DragSourceListener interface method */
public void dragExit(DragSourceEvent dsde)
{
DragSourceContext context = dsde.getDragSourceContext();
context.setCursor(DragSource.DefaultCopyNoDrop);
}
/** DropTargetListener interface method - What we do when drag is released */
public void drop(DropTargetDropEvent e)
{
try
{
Transferable tr = e.getTransferable();
//flavor not supported, reject drop
if (!tr.isDataFlavorSupported( ChangeInfo.INFO_FLAVOR))
{
e.rejectDrop();
}
//cast into appropriate data type
ChangeInfo childInfo = (ChangeInfo) tr.getTransferData( ChangeInfo.INFO_FLAVOR );
//get new parent node
Point loc = e.getLocation();
TreePath destinationPath = getPathForLocation(loc.x, loc.y);
final String msg = testDropTarget(destinationPath, _selectedTreePath);
if (msg != null)
{
e.rejectDrop();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
JOptionPane.showMessageDialog(
DnDJTree.this, msg, "Error Dialog", JOptionPane.ERROR_MESSAGE
);
}
});
return;
}
// reopen the node
DefaultMutableTreeNode node = (DefaultMutableTreeNode)destinationPath.getLastPathComponent();
if ( !(node instanceof ChangeNode ))
{
e.rejectDrop();
return;
}
ChangeNode cNode = (ChangeNode)node;
ChangeFileNode cfNode =(ChangeFileNode)_selectedTreePath.getLastPathComponent();
String file = cfNode.getFile();
int idx = file.indexOf("#");
if ( idx > -1 )
{ // strip off "#2"
file = cfNode.getFile().substring(0,idx);
}
String cmd = "reopen -c "+cNode.getChangeNumber()+ " " + file;
CommandTool.runCommand(cmd, Main.m_props);
// if an error occured reject drop
if ( MessageFormatter.getErrorMessageCount() != 0 )
{
MessageWriter.outputErrorMessages(MessageFormatter.getInstance());
e.rejectDrop();
return;
}
DefaultMutableTreeNode newParent =
(DefaultMutableTreeNode) destinationPath.getLastPathComponent();
//get old parent node
DefaultMutableTreeNode oldParent = (DefaultMutableTreeNode)getSelectedNode().getParent();
int action = e.getDropAction();
//boolean copyAction = (action == DnDConstants.ACTION_COPY);
//make new child node
ChangeFileNode newChild = new ChangeFileNode(childInfo);
try
{
/*if (!copyAction)*/
oldParent.remove(getSelectedNode());
newParent.add(newChild);
//if (copyAction) e.acceptDrop (DnDConstants.ACTION_COPY);
//else
e.acceptDrop (DnDConstants.ACTION_MOVE);
}
catch (java.lang.IllegalStateException ils)
{
e.rejectDrop();
}
e.getDropTargetContext().dropComplete(true);
//expand nodes appropriately - this probably isnt the best way...
DefaultTreeModel model = (DefaultTreeModel) getModel();
model.reload(oldParent);
model.reload(newParent);
TreePath parentPath = new TreePath(newParent.getPath());
expandPath(parentPath);
}
catch (IOException io) { e.rejectDrop(); }
catch (UnsupportedFlavorException ufe) {e.rejectDrop();}
}
/** DropTaregetListener interface method */
public void dragEnter(DropTargetDragEvent e)
{
}
/** DropTaregetListener interface method */
public void dragExit(DropTargetEvent e)
{
}
/** DropTargetListener interface method */
public void dragOver(DropTargetDragEvent e)
{
//set cursor location. Needed in setCursor method
Point loc = e.getLocation();
TreePath destinationPath = getPathForLocation(loc.x, loc.y);
// if destination path is okay accept drop...
String msg = testDropTarget(destinationPath, _selectedTreePath);
if (msg == null)
{
e.acceptDrag(DnDConstants.ACTION_MOVE ) ;
}
// ...otherwise reject drop
else
{
e.rejectDrag();
}
}
/** DropTaregetListener interface method */
public void dropActionChanged(DropTargetDragEvent e)
{
}
/** TreeSelectionListener - sets selected node */
public void valueChanged(TreeSelectionEvent evt)
{
_selectedTreePath = evt.getNewLeadSelectionPath();
if (_selectedTreePath == null)
{
_selectedNode = null;
return;
}
if ( _selectedTreePath.getLastPathComponent() instanceof ChangeFileNode )
{
_selectedNode = (ChangeFileNode)_selectedTreePath.getLastPathComponent();
}
}
/** Convenience method to test whether drop location is valid
* @param destination The destination path
* @param dropper The path for the node to be dropped
* @return null if no problems, otherwise an explanation
*/
private String testDropTarget(TreePath destination, TreePath dropper)
{
//Typical Tests for dropping
//Test 1.
boolean destinationPathIsNull = destination == null;
if (destinationPathIsNull)
{
return "Invalid drop location.";
}
//Test 2.
DefaultMutableTreeNode node = (DefaultMutableTreeNode) destination.getLastPathComponent();
if ( !node.getAllowsChildren() )
{
return "This node does not allow children";
}
if ( destination.getLastPathComponent() == _root )
{
return "Can't drop on root";
}
if (destination.equals(dropper))
{
return "Destination cannot be same as source";
}
//Test 3.
if ( dropper.isDescendant(destination))
{
return "Destination node cannot be a descendant.";
}
//Test 4.
if ( dropper.getParentPath().equals(destination))
{
return "Destination node cannot be a parent.";
}
return null;
}
} //end of DnDJTree
static class ChangeInfo implements Transferable, java.io.Serializable
{
public final static DataFlavor INFO_FLAVOR =
new DataFlavor(ChangeInfo.class, "Change Information");
static DataFlavor flavors[] = {INFO_FLAVOR };
private String _file;
private String _type;
private String _cmd;
private boolean _locked;
private String _toString;
private boolean _integrate;
public ChangeInfo (String fileName, String cmd, String type, boolean locked)
{
_file = fileName;
_type = type;
_cmd = cmd;
_locked = locked;
}
public String toString()
{
if ( _toString == null )
{
_toString = _file + " <"+_type+"><"+_cmd+">";
}
return _toString;
}
public boolean isLocked()
{
return _locked;
}
public boolean isAdd()
{
return "add".equalsIgnoreCase(_cmd);
}
public boolean isEdit()
{
return "edit".equalsIgnoreCase(_cmd);
}
public boolean isDelete()
{
return "delete".equalsIgnoreCase(_cmd);
}
public boolean getIntegrate()
{
return _integrate;
}
public void setIntegrate(boolean integrate)
{
_integrate = integrate;
}
public String getFile()
{
return _file;
}
// --------- Transferable --------------
public boolean isDataFlavorSupported(DataFlavor df)
{
return df.equals(INFO_FLAVOR);
}
/** implements Transferable interface */
public Object getTransferData(DataFlavor df)
throws UnsupportedFlavorException, IOException
{
if (df.equals(INFO_FLAVOR))
{
return this;
}
else throw new UnsupportedFlavorException(df);
}
/** implements Transferable interface */
public DataFlavor[] getTransferDataFlavors()
{
return flavors;
}
}
}