1 // TortoiseSVN - a Windows shell extension for easy version control
\r
3 // Copyright (C) 2007-2008 - TortoiseSVN
\r
5 // This program is free software; you can redistribute it and/or
\r
6 // modify it under the terms of the GNU General Public License
\r
7 // as published by the Free Software Foundation; either version 2
\r
8 // of the License, or (at your option) any later version.
\r
10 // This program is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with this program; if not, write to the Free Software Foundation,
\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
20 #include "RenameCommand.h"
\r
22 #include "MessageBox.h"
\r
23 #include "SVNProgressDlg.h"
\r
24 #include "ProgressDlg.h"
\r
25 #include "RenameDlg.h"
\r
26 #include "InputLogDlg.h"
\r
28 #include "DirFileEnum.h"
\r
29 #include "ShellUpdater.h"
\r
31 bool RenameCommand::Execute()
\r
34 CString filename = cmdLinePath.GetFileOrDirectoryName();
\r
35 CString basePath = cmdLinePath.GetContainingDirectory().GetWinPathString();
\r
36 ::SetCurrentDirectory(basePath);
\r
38 // show the rename dialog until the user either cancels or enters a new
\r
39 // name (one that's different to the original name
\r
44 dlg.m_name = filename;
\r
45 if (dlg.DoModal() != IDOK)
\r
47 sNewName = dlg.m_name;
\r
48 } while(PathIsRelative(sNewName) && !PathIsURL(sNewName) && (sNewName.IsEmpty() || (sNewName.Compare(filename)==0)));
\r
50 TRACE(_T("rename file %s to %s\n"), (LPCTSTR)cmdLinePath.GetWinPathString(), (LPCTSTR)sNewName);
\r
51 CTSVNPath destinationPath(basePath);
\r
52 if (PathIsRelative(sNewName) && !PathIsURL(sNewName))
\r
53 destinationPath.AppendPathString(sNewName);
\r
55 destinationPath.SetFromWin(sNewName);
\r
56 // check if a rename just with case is requested: that's not possible on windows file systems
\r
57 // and we have to show an error.
\r
58 if (cmdLinePath.GetWinPathString().CompareNoCase(destinationPath.GetWinPathString())==0)
\r
60 //rename to the same file!
\r
61 CString sHelpPath = theApp.m_pszHelpFilePath;
\r
62 sHelpPath += _T("::/tsvn-dug-rename.html#tsvn-dug-renameincase");
\r
63 CMessageBox::Show(hwndExplorer, IDS_PROC_CASERENAME, IDS_APPNAME, MB_OK|MB_HELP, sHelpPath);
\r
68 if (SVN::PathIsURL(cmdLinePath))
\r
71 // Ask for a commit message, then rename directly in
\r
76 svn.GetRepositoryRootAndUUID(cmdLinePath, sUUID);
\r
77 input.SetUUID(sUUID);
\r
79 sHint.Format(IDS_INPUT_MOVE, (LPCTSTR)cmdLinePath.GetSVNPathString(), (LPCTSTR)destinationPath.GetSVNPathString());
\r
80 input.SetActionText(sHint);
\r
81 if (input.DoModal() == IDOK)
\r
83 sMsg = input.GetLogMessage();
\r
90 if ((cmdLinePath.IsDirectory())||(pathList.GetCount() > 1))
\r
92 // renaming a directory can take a while: use the
\r
93 // progress dialog to show the progress of the renaming
\r
95 CSVNProgressDlg progDlg;
\r
96 progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Rename);
\r
97 if (parser.HasVal(_T("closeonend")))
\r
98 progDlg.SetAutoClose(parser.GetLongVal(_T("closeonend")));
\r
99 progDlg.SetPathList(pathList);
\r
100 progDlg.SetUrl(destinationPath.GetWinPathString());
\r
101 progDlg.SetCommitMessage(sMsg);
\r
102 progDlg.SetRevision(SVNRev::REV_WC);
\r
104 bRet = !progDlg.DidErrorsOccur();
\r
109 CString sFilemask = cmdLinePath.GetFilename();
\r
110 if (sFilemask.ReverseFind('.')>=0)
\r
112 sFilemask = sFilemask.Left(sFilemask.ReverseFind('.'));
\r
116 CString sNewMask = sNewName;
\r
117 if (sNewMask.ReverseFind('.'>=0))
\r
119 sNewMask = sNewMask.Left(sNewMask.ReverseFind('.'));
\r
124 if (((!sFilemask.IsEmpty()) && (parser.HasKey(_T("noquestion")))) ||
\r
125 (cmdLinePath.GetFileExtension().Compare(destinationPath.GetFileExtension())!=0))
\r
127 if (!svn.Move(CTSVNPathList(cmdLinePath), destinationPath, TRUE, sMsg))
\r
129 TRACE(_T("%s\n"), (LPCTSTR)svn.GetLastErrorMessage());
\r
130 CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);
\r
137 // when refactoring, multiple files have to be renamed
\r
138 // at once because those files belong together.
\r
139 // e.g. file.aspx, file.aspx.cs, file.aspx.resx
\r
140 CTSVNPathList renlist;
\r
141 CSimpleFileFind filefind(cmdLinePath.GetDirectory().GetWinPathString(), sFilemask+_T(".*"));
\r
142 while (filefind.FindNextFileNoDots())
\r
144 if (!filefind.IsDirectory())
\r
145 renlist.AddPath(CTSVNPath(filefind.GetFilePath()));
\r
147 if (renlist.GetCount()<=1)
\r
149 // we couldn't find any other matching files
\r
150 // just do the default...
\r
151 if (!svn.Move(CTSVNPathList(cmdLinePath), destinationPath, TRUE, sMsg))
\r
153 TRACE(_T("%s\n"), (LPCTSTR)svn.GetLastErrorMessage());
\r
154 CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);
\r
159 CShellUpdater::Instance().AddPathForUpdate(destinationPath);
\r
164 std::map<CString, CString> renmap;
\r
167 for (int i=0; i<renlist.GetCount(); ++i)
\r
169 CString sFilename = renlist[i].GetFilename();
\r
170 CString sNewFilename = sNewMask + sFilename.Mid(sFilemask.GetLength());
\r
171 sTemp.Format(_T("\n%s -> %s"), (LPCTSTR)sFilename, (LPCTSTR)sNewFilename);
\r
172 if (!renlist[i].IsEquivalentTo(cmdLinePath))
\r
174 renmap[renlist[i].GetWinPathString()] = renlist[i].GetContainingDirectory().GetWinPathString()+_T("\\")+sNewFilename;
\r
176 CString sRenameMultipleQuestion;
\r
177 sRenameMultipleQuestion.Format(IDS_PROC_MULTIRENAME, (LPCTSTR)sRenList);
\r
178 UINT idret = CMessageBox::Show(hwndExplorer, sRenameMultipleQuestion, _T("TortoiseSVN"), MB_ICONQUESTION|MB_YESNOCANCEL);
\r
179 if (idret == IDYES)
\r
181 CProgressDlg progress;
\r
182 progress.SetTitle(IDS_PROC_MOVING);
\r
183 progress.SetAnimation(IDR_MOVEANI);
\r
184 progress.SetTime(true);
\r
185 progress.ShowModeless(CWnd::FromHandle(hwndExplorer));
\r
187 for (std::map<CString, CString>::iterator it=renmap.begin(); it != renmap.end(); ++it)
\r
189 progress.FormatPathLine(1, IDS_PROC_MOVINGPROG, (LPCTSTR)it->first);
\r
190 progress.FormatPathLine(2, IDS_PROC_CPYMVPROG2, (LPCTSTR)it->second);
\r
191 progress.SetProgress(count, renmap.size());
\r
192 if (!svn.Move(CTSVNPathList(CTSVNPath(it->first)), CTSVNPath(it->second), TRUE, sMsg))
\r
194 if (svn.Err->apr_err == SVN_ERR_ENTRY_NOT_FOUND)
\r
196 bRet = !!MoveFile(it->first, it->second);
\r
200 TRACE(_T("%s\n"), (LPCTSTR)svn.GetLastErrorMessage());
\r
201 CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);
\r
208 CShellUpdater::Instance().AddPathForUpdate(CTSVNPath(it->second));
\r
213 else if (idret == IDNO)
\r
215 // no, user wants to just rename the file he selected
\r
216 if (!svn.Move(CTSVNPathList(cmdLinePath), destinationPath, TRUE, sMsg))
\r
218 TRACE(_T("%s\n"), (LPCTSTR)svn.GetLastErrorMessage());
\r
219 CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);
\r
224 CShellUpdater::Instance().AddPathForUpdate(destinationPath);
\r
227 else if (idret == IDCANCEL)
\r