CVS: Use new VCSBasePlugin-class.

Make the diff-base directory a property of VCSBaseEditor and use
everywhere.
This commit is contained in:
Friedemann Kleint
2009-12-09 12:41:10 +01:00
parent 0a5b2eed4c
commit 7ce3683143
12 changed files with 236 additions and 348 deletions

View File

@@ -30,6 +30,8 @@
#include "cvscontrol.h" #include "cvscontrol.h"
#include "cvsplugin.h" #include "cvsplugin.h"
#include <QtCore/QFileInfo>
using namespace CVS; using namespace CVS;
using namespace CVS::Internal; using namespace CVS::Internal;
@@ -66,12 +68,14 @@ bool CVSControl::vcsOpen(const QString & /* fileName */)
bool CVSControl::vcsAdd(const QString &fileName) bool CVSControl::vcsAdd(const QString &fileName)
{ {
return m_plugin->vcsAdd(fileName); const QFileInfo fi(fileName);
return m_plugin->vcsAdd(fi.absolutePath(), fi.fileName());
} }
bool CVSControl::vcsDelete(const QString &fileName) bool CVSControl::vcsDelete(const QString &fileName)
{ {
return m_plugin->vcsDelete(fileName); const QFileInfo fi(fileName);
return m_plugin->vcsDelete(fi.absolutePath(), fi.fileName());
} }
bool CVSControl::managesDirectory(const QString &directory) const bool CVSControl::managesDirectory(const QString &directory) const
@@ -93,4 +97,3 @@ void CVSControl::emitFilesChanged(const QStringList &l)
{ {
emit filesChanged(l); emit filesChanged(l);
} }

View File

@@ -142,35 +142,11 @@ QString CVSEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) cons
const int tabIndex = diffFileName.indexOf(QLatin1Char('\t')); const int tabIndex = diffFileName.indexOf(QLatin1Char('\t'));
if (tabIndex != -1) if (tabIndex != -1)
diffFileName.truncate(tabIndex); diffFileName.truncate(tabIndex);
// Add base dir return findDiffFile(diffFileName);
if (!m_diffBaseDir.isEmpty()) {
diffFileName.insert(0, QLatin1Char('/'));
diffFileName.insert(0, m_diffBaseDir);
}
if (CVS::Constants::debug)
qDebug() << "fileNameFromDiffSpecification" << m_diffBaseDir << diffFileName;
return diffFileName;
} }
} }
return QString(); return QString();
} }
QString CVSEditor::diffBaseDir() const
{
return m_diffBaseDir;
}
void CVSEditor::setDiffBaseDir(const QString &d)
{
m_diffBaseDir = d;
}
void CVSEditor::setDiffBaseDir(Core::IEditor *editor, const QString &db)
{
if (CVSEditor *cvsEditor = qobject_cast<CVSEditor*>(editor->widget()))
cvsEditor->setDiffBaseDir(db);
}
} }
} }

View File

@@ -45,13 +45,6 @@ public:
explicit CVSEditor(const VCSBase::VCSBaseEditorParameters *type, explicit CVSEditor(const VCSBase::VCSBaseEditorParameters *type,
QWidget *parent); QWidget *parent);
// Diff mode requires a base directory since CVS commands
// are run with relative paths (see plugin).
QString diffBaseDir() const;
void setDiffBaseDir(const QString &d);
static void setDiffBaseDir(Core::IEditor *editor, const QString &db);
private: private:
virtual QSet<QString> annotationChanges() const; virtual QSet<QString> annotationChanges() const;
virtual QString changeUnderCursor(const QTextCursor &) const; virtual QString changeUnderCursor(const QTextCursor &) const;

View File

@@ -41,8 +41,6 @@
#include <vcsbase/vcsbaseoutputwindow.h> #include <vcsbase/vcsbaseoutputwindow.h>
#include <utils/synchronousprocess.h> #include <utils/synchronousprocess.h>
#include <utils/parameteraction.h> #include <utils/parameteraction.h>
#include <projectexplorer/session.h>
#include <projectexplorer/project.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
@@ -53,7 +51,6 @@
#include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/vcsmanager.h> #include <coreplugin/vcsmanager.h>
#include <projectexplorer/projectexplorer.h>
#include <utils/stringutils.h> #include <utils/stringutils.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -152,7 +149,6 @@ CVSPlugin *CVSPlugin::m_cvsPluginInstance = 0;
CVSPlugin::CVSPlugin() : CVSPlugin::CVSPlugin() :
VCSBase::VCSBasePlugin(QLatin1String(CVS::Constants::CVSCOMMITEDITOR_KIND)), VCSBase::VCSBasePlugin(QLatin1String(CVS::Constants::CVSCOMMITEDITOR_KIND)),
m_projectExplorer(0),
m_addAction(0), m_addAction(0),
m_deleteAction(0), m_deleteAction(0),
m_revertAction(0), m_revertAction(0),
@@ -162,7 +158,7 @@ CVSPlugin::CVSPlugin() :
m_commitCurrentAction(0), m_commitCurrentAction(0),
m_filelogCurrentAction(0), m_filelogCurrentAction(0),
m_annotateCurrentAction(0), m_annotateCurrentAction(0),
m_statusAction(0), m_statusProjectAction(0),
m_updateProjectAction(0), m_updateProjectAction(0),
m_submitCurrentLogAction(0), m_submitCurrentLogAction(0),
m_submitDiffAction(0), m_submitDiffAction(0),
@@ -183,6 +179,7 @@ void CVSPlugin::cleanCommitMessageFile()
if (!m_commitMessageFileName.isEmpty()) { if (!m_commitMessageFileName.isEmpty()) {
QFile::remove(m_commitMessageFileName); QFile::remove(m_commitMessageFileName);
m_commitMessageFileName.clear(); m_commitMessageFileName.clear();
m_commitRepository.clear();
} }
} }
bool CVSPlugin::isCommitEditorOpen() const bool CVSPlugin::isCommitEditorOpen() const
@@ -275,9 +272,10 @@ bool CVSPlugin::initialize(const QStringList & /*arguments */, QString *errorMes
cvsMenu->addAction(createSeparator(this, ami, CMD_ID_SEPARATOR0, globalcontext)); cvsMenu->addAction(createSeparator(this, ami, CMD_ID_SEPARATOR0, globalcontext));
m_diffProjectAction = new QAction(tr("Diff Project"), this); m_diffProjectAction = new Utils::ParameterAction(tr("Diff Project"), tr("Diff Project \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
command = ami->registerAction(m_diffProjectAction, CMD_ID_DIFF_PROJECT, command = ami->registerAction(m_diffProjectAction, CMD_ID_DIFF_PROJECT,
globalcontext); globalcontext);
command->setAttribute(Core::Command::CA_UpdateText);
connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffProject())); connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffProject()));
cvsMenu->addAction(command); cvsMenu->addAction(command);
@@ -325,14 +323,16 @@ bool CVSPlugin::initialize(const QStringList & /*arguments */, QString *errorMes
cvsMenu->addAction(createSeparator(this, ami, CMD_ID_SEPARATOR3, globalcontext)); cvsMenu->addAction(createSeparator(this, ami, CMD_ID_SEPARATOR3, globalcontext));
m_statusAction = new QAction(tr("Project Status"), this); m_statusProjectAction = new Utils::ParameterAction(tr("Project Status"), tr("Status of Project \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
command = ami->registerAction(m_statusAction, CMD_ID_STATUS, command = ami->registerAction(m_statusProjectAction, CMD_ID_STATUS,
globalcontext); globalcontext);
connect(m_statusAction, SIGNAL(triggered()), this, SLOT(projectStatus())); command->setAttribute(Core::Command::CA_UpdateText);
connect(m_statusProjectAction, SIGNAL(triggered()), this, SLOT(projectStatus()));
cvsMenu->addAction(command); cvsMenu->addAction(command);
m_updateProjectAction = new QAction(tr("Update Project"), this); m_updateProjectAction = new Utils::ParameterAction(tr("Update Project"), tr("Update Project \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
command = ami->registerAction(m_updateProjectAction, CMD_ID_UPDATE, globalcontext); command = ami->registerAction(m_updateProjectAction, CMD_ID_UPDATE, globalcontext);
command->setAttribute(Core::Command::CA_UpdateText);
connect(m_updateProjectAction, SIGNAL(triggered()), this, SLOT(updateProject())); connect(m_updateProjectAction, SIGNAL(triggered()), this, SLOT(updateProject()));
cvsMenu->addAction(command); cvsMenu->addAction(command);
@@ -357,7 +357,6 @@ bool CVSPlugin::initialize(const QStringList & /*arguments */, QString *errorMes
void CVSPlugin::extensionsInitialized() void CVSPlugin::extensionsInitialized()
{ {
m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
} }
bool CVSPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor) bool CVSPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor)
@@ -410,27 +409,32 @@ bool CVSPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEdi
return closeEditor; return closeEditor;
} }
void CVSPlugin::diffFiles(const QStringList &files) void CVSPlugin::diffCommitFiles(const QStringList &files)
{ {
cvsDiff(files); cvsDiff(m_commitRepository, files);
} }
void CVSPlugin::cvsDiff(const QStringList &files, QString diffname) static inline void setDiffBaseDirectory(Core::IEditor *editor, const QString &db)
{
if (VCSBase::VCSBaseEditor *ve = qobject_cast<VCSBase::VCSBaseEditor*>(editor->widget()))
ve->setDiffBaseDirectory(db);
}
void CVSPlugin::cvsDiff(const QString &workingDir, const QStringList &files)
{ {
if (CVS::Constants::debug) if (CVS::Constants::debug)
qDebug() << Q_FUNC_INFO << files << diffname; qDebug() << Q_FUNC_INFO << files;
const QString source = files.empty() ? QString() : files.front(); const QString source = VCSBase::VCSBaseEditor::getSource(workingDir, files);
QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditor::getCodec(source); QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(workingDir, files);
const QString id = VCSBase::VCSBaseEditor::getTitleId(workingDir, files);
if (files.count() == 1 && diffname.isEmpty())
diffname = QFileInfo(files.front()).fileName();
QStringList args(QLatin1String("diff")); QStringList args(QLatin1String("diff"));
args << m_settings.cvsDiffOptions; args << m_settings.cvsDiffOptions;
args.append(files);
// CVS returns the diff exit code (1 if files differ), which is // CVS returns the diff exit code (1 if files differ), which is
// undistinguishable from a "file not found" error, unfortunately. // undistinguishable from a "file not found" error, unfortunately.
const CVSResponse response = runCVS(args, files, cvsShortTimeOut, false, codec); const CVSResponse response = runCVS(workingDir, args, cvsShortTimeOut, false, codec);
switch (response.result) { switch (response.result) {
case CVSResponse::NonNullExitCode: case CVSResponse::NonNullExitCode:
case CVSResponse::Ok: case CVSResponse::Ok:
@@ -446,18 +450,18 @@ void CVSPlugin::cvsDiff(const QStringList &files, QString diffname)
// the common usage pattern of continuously changing and diffing a file // the common usage pattern of continuously changing and diffing a file
if (files.count() == 1) { if (files.count() == 1) {
// Show in the same editor if diff has been executed before // Show in the same editor if diff has been executed before
if (Core::IEditor *editor = locateEditor("originalFileName", files.front())) { if (Core::IEditor *editor = locateEditor("originalFileName", id)) {
editor->createNew(output); editor->createNew(output);
Core::EditorManager::instance()->activateEditor(editor); Core::EditorManager::instance()->activateEditor(editor);
CVSEditor::setDiffBaseDir(editor, response.workingDirectory); setDiffBaseDirectory(editor, workingDir);
return; return;
} }
} }
const QString title = QString::fromLatin1("cvs diff %1").arg(diffname); const QString title = QString::fromLatin1("cvs diff %1").arg(id);
Core::IEditor *editor = showOutputInEditor(title, output, VCSBase::DiffOutput, source, codec); Core::IEditor *editor = showOutputInEditor(title, output, VCSBase::DiffOutput, source, codec);
if (files.count() == 1) if (files.count() == 1)
editor->setProperty("originalFileName", files.front()); editor->setProperty("originalFileName", id);
CVSEditor::setDiffBaseDir(editor, response.workingDirectory); setDiffBaseDirectory(editor, workingDir);
} }
CVSSubmitEditor *CVSPlugin::openCVSSubmitEditor(const QString &fileName) CVSSubmitEditor *CVSPlugin::openCVSSubmitEditor(const QString &fileName)
@@ -466,7 +470,7 @@ CVSSubmitEditor *CVSPlugin::openCVSSubmitEditor(const QString &fileName)
CVSSubmitEditor *submitEditor = qobject_cast<CVSSubmitEditor*>(editor); CVSSubmitEditor *submitEditor = qobject_cast<CVSSubmitEditor*>(editor);
QTC_ASSERT(submitEditor, /**/); QTC_ASSERT(submitEditor, /**/);
submitEditor->registerActions(m_submitUndoAction, m_submitRedoAction, m_submitCurrentLogAction, m_submitDiffAction); submitEditor->registerActions(m_submitUndoAction, m_submitRedoAction, m_submitCurrentLogAction, m_submitDiffAction);
connect(submitEditor, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(diffFiles(QStringList))); connect(submitEditor, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(diffCommitFiles(QStringList)));
return submitEditor; return submitEditor;
} }
@@ -476,45 +480,45 @@ void CVSPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction)) if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction))
return; return;
m_diffProjectAction->setEnabled(true); const QString currentFileName = currentState().currentFileName();
m_commitAllAction->setEnabled(true); m_addAction->setParameter(currentFileName);
m_statusAction->setEnabled(true); m_deleteAction->setParameter(currentFileName);
m_revertAction->setParameter(currentFileName);
m_diffCurrentAction->setParameter(currentFileName);
m_commitCurrentAction->setParameter(currentFileName);
m_filelogCurrentAction->setParameter(currentFileName);
m_annotateCurrentAction->setParameter(currentFileName);
const QString fileName = currentFileName(); const QString currentProjectName = currentState().currentProjectName();
const QString baseName = fileName.isEmpty() ? fileName : QFileInfo(fileName).fileName(); m_diffProjectAction->setParameter(currentProjectName);
m_statusProjectAction->setParameter(currentProjectName);
m_updateProjectAction->setParameter(currentProjectName);
m_addAction->setParameter(baseName); m_commitAllAction->setEnabled(currentState().hasTopLevel());
m_deleteAction->setParameter(baseName);
m_revertAction->setParameter(baseName);
m_diffCurrentAction->setParameter(baseName);
m_commitCurrentAction->setParameter(baseName);
m_filelogCurrentAction->setParameter(baseName);
m_annotateCurrentAction->setParameter(baseName);
} }
void CVSPlugin::addCurrentFile() void CVSPlugin::addCurrentFile()
{ {
const QString file = currentFileName(); const VCSBase::VCSBasePluginState state = currentState();
if (!file.isEmpty()) QTC_ASSERT(state.hasFile(), return)
vcsAdd(file); vcsAdd(state.currentFileTopLevel(), state.relativeCurrentFile());
} }
void CVSPlugin::deleteCurrentFile() void CVSPlugin::deleteCurrentFile()
{ {
const QString file = currentFileName(); const VCSBase::VCSBasePluginState state = currentState();
if (file.isEmpty()) QTC_ASSERT(state.hasFile(), return)
return; if (!Core::ICore::instance()->vcsManager()->showDeleteDialog(state.currentFile()))
if (!Core::ICore::instance()->vcsManager()->showDeleteDialog(file)) QMessageBox::warning(0, QLatin1String("CVS remove"), tr("The file '%1' could not be deleted.").arg(state.currentFile()), QMessageBox::Ok);
QMessageBox::warning(0, QLatin1String("CVS remove"), tr("The file '%1' could not be deleted.").arg(file), QMessageBox::Ok);
} }
void CVSPlugin::revertCurrentFile() void CVSPlugin::revertCurrentFile()
{ {
const QString file = currentFileName(); const VCSBase::VCSBasePluginState state = currentState();
if (file.isEmpty()) QTC_ASSERT(state.hasFile(), return)
return; QStringList args;
args << QLatin1String("diff") << state.relativeCurrentFile();
const CVSResponse diffResponse = runCVS(QStringList(QLatin1String("diff")), QStringList(file), cvsShortTimeOut, false); const CVSResponse diffResponse = runCVS(state.currentFileTopLevel(), args, cvsShortTimeOut, false);
switch (diffResponse.result) { switch (diffResponse.result) {
case CVSResponse::Ok: case CVSResponse::Ok:
return; // Not modified, diff exit code 0 return; // Not modified, diff exit code 0
@@ -530,132 +534,81 @@ void CVSPlugin::revertCurrentFile()
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
return; return;
Core::FileChangeBlocker fcb(file); Core::FileChangeBlocker fcb(state.currentFile());
// revert // revert
QStringList args(QLatin1String("update")); args.clear();
args.push_back(QLatin1String("-C")); args << QLatin1String("update") << QLatin1String("-C") << state.relativeCurrentFile();
const CVSResponse revertResponse = runCVS(state.currentFileTopLevel(), args, cvsShortTimeOut, true);
const QStringList files = QStringList(file);
const CVSResponse revertResponse = runCVS(args, files, cvsShortTimeOut, true);
if (revertResponse.result == CVSResponse::Ok) { if (revertResponse.result == CVSResponse::Ok) {
fcb.setModifiedReload(true); fcb.setModifiedReload(true);
cvsVersionControl()->emitFilesChanged(files); cvsVersionControl()->emitFilesChanged(QStringList(state.currentFile()));
} }
} }
// Get a unique set of toplevel directories for the current projects.
// To be used for "diff all" or "commit all".
QStringList CVSPlugin::currentProjectsTopLevels(QString *name) const
{
typedef QList<ProjectExplorer::Project *> ProjectList;
ProjectList projects;
// Compile list of projects
if (ProjectExplorer::Project *currentProject = m_projectExplorer->currentProject()) {
projects.push_back(currentProject);
} else {
if (const ProjectExplorer::SessionManager *session = m_projectExplorer->session())
projects.append(session->projects());
}
// Get unique set of toplevels and concat project names
QStringList toplevels;
const QChar blank(QLatin1Char(' '));
foreach (const ProjectExplorer::Project *p, projects) {
if (name) {
if (!name->isEmpty())
name->append(blank);
name->append(p->name());
}
const QString projectPath = QFileInfo(p->file()->fileName()).absolutePath();
const QString topLevel = findTopLevelForDirectory(projectPath);
if (!topLevel.isEmpty() && !toplevels.contains(topLevel))
toplevels.push_back(topLevel);
}
return toplevels;
}
void CVSPlugin::diffProject() void CVSPlugin::diffProject()
{ {
QString diffName; const VCSBase::VCSBasePluginState state = currentState();
const QStringList topLevels = currentProjectsTopLevels(&diffName); QTC_ASSERT(state.hasProject(), return)
if (!topLevels.isEmpty()) cvsDiff(state.currentProjectTopLevel(), state.relativeCurrentProject());
cvsDiff(topLevels, diffName);
} }
void CVSPlugin::diffCurrentFile() void CVSPlugin::diffCurrentFile()
{ {
cvsDiff(QStringList(currentFileName())); const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasFile(), return)
cvsDiff(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
} }
void CVSPlugin::startCommitCurrentFile() void CVSPlugin::startCommitCurrentFile()
{ {
const QString file = currentFileName(); const VCSBase::VCSBasePluginState state = currentState();
if (!file.isEmpty()) QTC_ASSERT(state.hasFile(), return)
startCommit(file); startCommit(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
} }
void CVSPlugin::startCommitAll() void CVSPlugin::startCommitAll()
{ {
// Make sure we have only repository for commit const VCSBase::VCSBasePluginState state = currentState();
const QStringList files = currentProjectsTopLevels(); QTC_ASSERT(state.hasTopLevel(), return)
switch (files.size()) { startCommit(state.topLevel());
case 0:
break;
case 1:
startCommit(files.front());
break;
default: {
const QString msg = tr("The commit list spans several repositories (%1). Please commit them one by one.").
arg(files.join(QString(QLatin1Char(' '))));
QMessageBox::warning(0, QLatin1String("cvs commit"), msg, QMessageBox::Ok);
}
break;
}
} }
/* Start commit of files of a single repository by displaying /* Start commit of files of a single repository by displaying
* template and files in a submit editor. On closing, the real * template and files in a submit editor. On closing, the real
* commit will start. */ * commit will start. */
void CVSPlugin::startCommit(const QString &source) void CVSPlugin::startCommit(const QString &workingDir, const QStringList &files)
{ {
if (source.isEmpty())
return;
if (VCSBase::VCSBaseSubmitEditor::raiseSubmitEditor()) if (VCSBase::VCSBaseSubmitEditor::raiseSubmitEditor())
return; return;
if (isCommitEditorOpen()) { if (isCommitEditorOpen()) {
VCSBase::VCSBaseOutputWindow::instance()->appendWarning(tr("Another commit is currently being executed.")); VCSBase::VCSBaseOutputWindow::instance()->appendWarning(tr("Another commit is currently being executed."));
return; return;
} }
const QFileInfo sourceFi(source);
const QString sourceDir = sourceFi.isDir() ? source : sourceFi.absolutePath();
const QString topLevel = findTopLevelForDirectory(sourceDir);
if (topLevel.isEmpty()) {
VCSBase::VCSBaseOutputWindow::instance()->appendError(msgCannotFindTopLevel(source));
return;
}
// We need the "Examining <subdir>" stderr output to tell // We need the "Examining <subdir>" stderr output to tell
// where we are, so, have stdout/stderr channels merged. // where we are, so, have stdout/stderr channels merged.
QStringList args = QStringList(QLatin1String("status")); QStringList args = QStringList(QLatin1String("status"));
if (sourceDir == topLevel) { const CVSResponse response = runCVS(workingDir, args, cvsShortTimeOut, false, 0, true);
args.push_back(QString(QLatin1Char('.')));
} else {
args.push_back(QDir(topLevel).relativeFilePath(source));
}
const CVSResponse response = runCVS(topLevel, args, cvsShortTimeOut, false, 0, true);
if (response.result != CVSResponse::Ok) if (response.result != CVSResponse::Ok)
return; return;
// Get list of added/modified/deleted files // Get list of added/modified/deleted files and purge out undesired ones
// As we run cvs in the repository directory, we need complete // (do not run status with relative arguments as it will omit the directories)
// the file names by the respective directory. StateList statusOutput = parseStatusOutput(QString(), response.stdOut);
const StateList statusOutput = parseStatusOutput(topLevel, response.stdOut); if (!files.isEmpty()) {
if (CVS::Constants::debug) for (StateList::iterator it = statusOutput.begin(); it != statusOutput.end() ; ) {
qDebug() << Q_FUNC_INFO << '\n' << source << "top" << topLevel; if (files.contains(it->second)) {
++it;
} else {
it = statusOutput.erase(it);
}
}
}
if (statusOutput.empty()) { if (statusOutput.empty()) {
VCSBase::VCSBaseOutputWindow::instance()->append(tr("There are no modified files.")); VCSBase::VCSBaseOutputWindow::instance()->append(tr("There are no modified files."));
return; return;
} }
m_commitRepository = workingDir;
// Create a new submit change file containing the submit template // Create a new submit change file containing the submit template
QTemporaryFile changeTmpFile; QTemporaryFile changeTmpFile;
@@ -683,62 +636,73 @@ bool CVSPlugin::commit(const QString &messageFile,
qDebug() << Q_FUNC_INFO << messageFile << fileList; qDebug() << Q_FUNC_INFO << messageFile << fileList;
QStringList args = QStringList(QLatin1String("commit")); QStringList args = QStringList(QLatin1String("commit"));
args << QLatin1String("-F") << messageFile; args << QLatin1String("-F") << messageFile;
const CVSResponse response = runCVS(args, fileList, cvsLongTimeOut, true); args.append(fileList);
const CVSResponse response = runCVS(m_commitRepository, args, cvsLongTimeOut, true);
return response.result == CVSResponse::Ok ; return response.result == CVSResponse::Ok ;
} }
void CVSPlugin::filelogCurrentFile() void CVSPlugin::filelogCurrentFile()
{ {
const QString file = currentFileName(); const VCSBase::VCSBasePluginState state = currentState();
if (!file.isEmpty()) QTC_ASSERT(state.hasFile(), return)
filelog(file); filelog(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
} }
void CVSPlugin::filelog(const QString &file) void CVSPlugin::filelog(const QString &workingDir, const QStringList &files)
{ {
QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(file); QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(workingDir, files);
// no need for temp file // no need for temp file
const CVSResponse response = runCVS(QStringList(QLatin1String("log")), QStringList(file), cvsShortTimeOut, false, codec); const QString id = VCSBase::VCSBaseEditor::getTitleId(workingDir, files);
const QString source = VCSBase::VCSBaseEditor::getSource(workingDir, files);
QStringList args;
args << QLatin1String("log");
args.append(files);
const CVSResponse response = runCVS(workingDir, args, cvsShortTimeOut, false, codec);
if (response.result != CVSResponse::Ok) if (response.result != CVSResponse::Ok)
return; return;
// Re-use an existing view if possible to support // Re-use an existing view if possible to support
// the common usage pattern of continuously changing and diffing a file // the common usage pattern of continuously changing and diffing a file
if (Core::IEditor *editor = locateEditor("logFileName", file)) { if (Core::IEditor *editor = locateEditor("logFileName", id)) {
editor->createNew(response.stdOut); editor->createNew(response.stdOut);
Core::EditorManager::instance()->activateEditor(editor); Core::EditorManager::instance()->activateEditor(editor);
} else { } else {
const QString title = QString::fromLatin1("cvs log %1").arg(QFileInfo(file).fileName()); const QString title = QString::fromLatin1("cvs log %1").arg(id);
Core::IEditor *newEditor = showOutputInEditor(title, response.stdOut, VCSBase::LogOutput, file, codec); Core::IEditor *newEditor = showOutputInEditor(title, response.stdOut, VCSBase::LogOutput, source, codec);
newEditor->setProperty("logFileName", file); newEditor->setProperty("logFileName", id);
} }
} }
void CVSPlugin::updateProject() void CVSPlugin::updateProject()
{ {
const QStringList topLevels = currentProjectsTopLevels(); const VCSBase::VCSBasePluginState state = currentState();
if (!topLevels.empty()) { QTC_ASSERT(state.hasProject(), return)
QStringList args(QLatin1String("update"));
args.push_back(QLatin1String("-dR")); QStringList args(QLatin1String("update"));
const CVSResponse response = runCVS(args, topLevels, cvsLongTimeOut, true); args.push_back(QLatin1String("-dR"));
if (response.result == CVSResponse::Ok) args.append(state.relativeCurrentProject());
foreach(const QString &topLevel, topLevels) const CVSResponse response = runCVS(state.currentProjectTopLevel(), args, cvsLongTimeOut, true);
cvsVersionControl()->emitRepositoryChanged(topLevel); if (response.result == CVSResponse::Ok)
} cvsVersionControl()->emitRepositoryChanged(state.currentProjectTopLevel());
} }
void CVSPlugin::annotateCurrentFile() void CVSPlugin::annotateCurrentFile()
{ {
const QString file = currentFileName(); const VCSBase::VCSBasePluginState state = currentState();
if (!file.isEmpty()) QTC_ASSERT(state.hasFile(), return)
annotate(file); annotate(state.currentFileTopLevel(), state.relativeCurrentFile());
} }
void CVSPlugin::annotate(const QString &file) void CVSPlugin::annotate(const QString &workingDir, const QString &file)
{ {
QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(file); const QStringList files(file);
const CVSResponse response = runCVS(QStringList(QLatin1String("annotate")), QStringList(file), cvsShortTimeOut, false, codec); QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(workingDir, files);
const QString id = VCSBase::VCSBaseEditor::getTitleId(workingDir, files);
const QString source = VCSBase::VCSBaseEditor::getSource(workingDir, file);
QStringList args;
args << QLatin1String("annotate") << file;
const CVSResponse response = runCVS(workingDir, args, cvsShortTimeOut, false, codec);
if (response.result != CVSResponse::Ok) if (response.result != CVSResponse::Ok)
return; return;
@@ -746,30 +710,27 @@ void CVSPlugin::annotate(const QString &file)
// the common usage pattern of continuously changing and diffing a file // the common usage pattern of continuously changing and diffing a file
const int lineNumber = VCSBase::VCSBaseEditor::lineNumberOfCurrentEditor(file); const int lineNumber = VCSBase::VCSBaseEditor::lineNumberOfCurrentEditor(file);
if (Core::IEditor *editor = locateEditor("annotateFileName", file)) { if (Core::IEditor *editor = locateEditor("annotateFileName", id)) {
editor->createNew(response.stdOut); editor->createNew(response.stdOut);
VCSBase::VCSBaseEditor::gotoLineOfEditor(editor, lineNumber); VCSBase::VCSBaseEditor::gotoLineOfEditor(editor, lineNumber);
Core::EditorManager::instance()->activateEditor(editor); Core::EditorManager::instance()->activateEditor(editor);
} else { } else {
const QString title = QString::fromLatin1("cvs annotate %1").arg(QFileInfo(file).fileName()); const QString title = QString::fromLatin1("cvs annotate %1").arg(id);
Core::IEditor *newEditor = showOutputInEditor(title, response.stdOut, VCSBase::AnnotateOutput, file, codec); Core::IEditor *newEditor = showOutputInEditor(title, response.stdOut, VCSBase::AnnotateOutput, source, codec);
newEditor->setProperty("annotateFileName", file); newEditor->setProperty("annotateFileName", id);
VCSBase::VCSBaseEditor::gotoLineOfEditor(newEditor, lineNumber); VCSBase::VCSBaseEditor::gotoLineOfEditor(newEditor, lineNumber);
} }
} }
void CVSPlugin::projectStatus() void CVSPlugin::projectStatus()
{ {
if (!m_projectExplorer) const VCSBase::VCSBasePluginState state = currentState();
return; QTC_ASSERT(state.hasProject(), return)
QStringList args;
const QStringList topLevels = currentProjectsTopLevels(); args << QLatin1String("status") << state.relativeCurrentProject();
if (topLevels.empty()) const CVSResponse response = runCVS(state.currentProjectTopLevel(), args, cvsShortTimeOut, false);
return;
const CVSResponse response = runCVS(QStringList(QLatin1String("status")), topLevels, cvsShortTimeOut, false);
if (response.result == CVSResponse::Ok) if (response.result == CVSResponse::Ok)
showOutputInEditor(tr("Project status"), response.stdOut, VCSBase::RegularCommandOutput, topLevels.front(), 0); showOutputInEditor(tr("Project status"), response.stdOut, VCSBase::RegularCommandOutput, state.currentProjectTopLevel(), 0);
} }
// Decrement version number "1.2" -> "1.1" // Decrement version number "1.2" -> "1.1"
@@ -797,6 +758,18 @@ void CVSPlugin::slotDescribe(const QString &source, const QString &changeNr)
bool CVSPlugin::describe(const QString &file, const QString &changeNr, QString *errorMessage) bool CVSPlugin::describe(const QString &file, const QString &changeNr, QString *errorMessage)
{ {
const QString toplevel = findTopLevelForDirectory(QFileInfo(file).absolutePath());
if (toplevel.isEmpty()) {
*errorMessage = msgCannotFindTopLevel(file);
return false;
}
return describe(toplevel, QDir(toplevel).relativeFilePath(file), changeNr, errorMessage);
}
bool CVSPlugin::describe(const QString &toplevel, const QString &file, const
QString &changeNr, QString *errorMessage)
{
// In CVS, revisions of files are normally unrelated, there is // In CVS, revisions of files are normally unrelated, there is
// no global revision/change number. The only thing that groups // no global revision/change number. The only thing that groups
// a commit is the "commit-id" (as shown in the log). // a commit is the "commit-id" (as shown in the log).
@@ -805,25 +778,20 @@ bool CVSPlugin::describe(const QString &file, const QString &changeNr, QString *
// if desired. // if desired.
if (CVS::Constants::debug) if (CVS::Constants::debug)
qDebug() << Q_FUNC_INFO << file << changeNr; qDebug() << Q_FUNC_INFO << file << changeNr;
const QString toplevel = findTopLevelForDirectory(QFileInfo(file).absolutePath());
if (toplevel.isEmpty()) {
*errorMessage = msgCannotFindTopLevel(file);
return false;
}
// Number must be > 1 // Number must be > 1
if (isFirstRevision(changeNr)) { if (isFirstRevision(changeNr)) {
*errorMessage = tr("The initial revision %1 cannot be described.").arg(changeNr); *errorMessage = tr("The initial revision %1 cannot be described.").arg(changeNr);
return false; return false;
} }
// Run log to obtain commit id and details // Run log to obtain commit id and details
QStringList args(QLatin1String("log")); QStringList args;
args.push_back(QLatin1String("-r") + changeNr); args << QLatin1String("log") << (QLatin1String("-r") + changeNr) << file;
const CVSResponse logResponse = runCVS(args, QStringList(file), cvsShortTimeOut, false); const CVSResponse logResponse = runCVS(toplevel, args, cvsShortTimeOut, false);
if (logResponse.result != CVSResponse::Ok) { if (logResponse.result != CVSResponse::Ok) {
*errorMessage = logResponse.message; *errorMessage = logResponse.message;
return false; return false;
} }
const QList<CVS_LogEntry> fileLog = parseLogEntries(logResponse.stdOut, logResponse.workingDirectory); const QList<CVS_LogEntry> fileLog = parseLogEntries(logResponse.stdOut);
if (fileLog.empty() || fileLog.front().revisions.empty()) { if (fileLog.empty() || fileLog.front().revisions.empty()) {
*errorMessage = msgLogParsingFailed(); *errorMessage = msgLogParsingFailed();
return false; return false;
@@ -838,13 +806,14 @@ bool CVSPlugin::describe(const QString &file, const QString &changeNr, QString *
const QString nextDayS = date.addDays(1).toString(Qt::ISODate); const QString nextDayS = date.addDays(1).toString(Qt::ISODate);
args.clear(); args.clear();
args << QLatin1String("log") << QLatin1String("-d") << (dateS + QLatin1Char('<') + nextDayS); args << QLatin1String("log") << QLatin1String("-d") << (dateS + QLatin1Char('<') + nextDayS);
const CVSResponse repoLogResponse = runCVS(args, QStringList(toplevel), cvsLongTimeOut, false);
const CVSResponse repoLogResponse = runCVS(toplevel, args, cvsLongTimeOut, false);
if (repoLogResponse.result != CVSResponse::Ok) { if (repoLogResponse.result != CVSResponse::Ok) {
*errorMessage = repoLogResponse.message; *errorMessage = repoLogResponse.message;
return false; return false;
} }
// Describe all files found, pass on dir to obtain correct absolute paths. // Describe all files found, pass on dir to obtain correct absolute paths.
const QList<CVS_LogEntry> repoEntries = parseLogEntries(repoLogResponse.stdOut, QFileInfo(toplevel).absolutePath(), commitId); const QList<CVS_LogEntry> repoEntries = parseLogEntries(repoLogResponse.stdOut, QString(), commitId);
if (repoEntries.empty()) { if (repoEntries.empty()) {
*errorMessage = tr("Could not find commits of id '%1' on %2.").arg(commitId, dateS); *errorMessage = tr("Could not find commits of id '%1' on %2.").arg(commitId, dateS);
return false; return false;
@@ -859,20 +828,18 @@ bool CVSPlugin::describe(const QString &file, const QString &changeNr, QString *
// Describe a set of files and revisions by // Describe a set of files and revisions by
// concatenating log and diffs to previous revisions // concatenating log and diffs to previous revisions
bool CVSPlugin::describe(const QString &repositoryPath, QList<CVS_LogEntry> entries, bool CVSPlugin::describe(const QString &repositoryPath,
QList<CVS_LogEntry> entries,
QString *errorMessage) QString *errorMessage)
{ {
// Collect logs // Collect logs
QString output; QString output;
const QDir repository(repositoryPath);
QTextCodec *codec = 0; QTextCodec *codec = 0;
const QList<CVS_LogEntry>::iterator lend = entries.end(); const QList<CVS_LogEntry>::iterator lend = entries.end();
for (QList<CVS_LogEntry>::iterator it = entries.begin(); it != lend; ++it) { for (QList<CVS_LogEntry>::iterator it = entries.begin(); it != lend; ++it) {
// Before fiddling file names, try to find codec // Before fiddling file names, try to find codec
if (!codec) if (!codec)
codec = VCSBase::VCSBaseEditor::getCodec(it->file); codec = VCSBase::VCSBaseEditor::getCodec(repositoryPath, QStringList(it->file));
// Make the files relative to the repository directory.
it->file = repository.relativeFilePath(it->file);
// Run log // Run log
QStringList args(QLatin1String("log")); QStringList args(QLatin1String("log"));
args << (QLatin1String("-r") + it->revisions.front().revision) << it->file; args << (QLatin1String("-r") + it->revisions.front().revision) << it->file;
@@ -915,12 +882,12 @@ bool CVSPlugin::describe(const QString &repositoryPath, QList<CVS_LogEntry> entr
if (Core::IEditor *editor = locateEditor("describeChange", commitId)) { if (Core::IEditor *editor = locateEditor("describeChange", commitId)) {
editor->createNew(output); editor->createNew(output);
Core::EditorManager::instance()->activateEditor(editor); Core::EditorManager::instance()->activateEditor(editor);
CVSEditor::setDiffBaseDir(editor, repositoryPath); setDiffBaseDirectory(editor, repositoryPath);
} else { } else {
const QString title = QString::fromLatin1("cvs describe %1").arg(commitId); const QString title = QString::fromLatin1("cvs describe %1").arg(commitId);
Core::IEditor *newEditor = showOutputInEditor(title, output, VCSBase::DiffOutput, entries.front().file, codec); Core::IEditor *newEditor = showOutputInEditor(title, output, VCSBase::DiffOutput, entries.front().file, codec);
newEditor->setProperty("describeChange", commitId); newEditor->setProperty("describeChange", commitId);
CVSEditor::setDiffBaseDir(newEditor, repositoryPath); setDiffBaseDirectory(editor, repositoryPath);
} }
return true; return true;
} }
@@ -932,56 +899,11 @@ void CVSPlugin::submitCurrentLog()
<< Core::EditorManager::instance()->currentEditor()); << Core::EditorManager::instance()->currentEditor());
} }
QString CVSPlugin::currentFileName() const
{
const QString fileName = Core::ICore::instance()->fileManager()->currentFile();
if (!fileName.isEmpty()) {
const QFileInfo fi(fileName);
if (fi.exists())
return fi.canonicalFilePath();
}
return QString();
}
static inline QString processStdErr(QProcess &proc) static inline QString processStdErr(QProcess &proc)
{ {
return QString::fromLocal8Bit(proc.readAllStandardError()).remove(QLatin1Char('\r')); return QString::fromLocal8Bit(proc.readAllStandardError()).remove(QLatin1Char('\r'));
} }
/* Tortoise CVS does not allow for absolute path names
* (which it claims to be CVS standard behaviour).
* So, try to figure out the common root of the file arguments,
* remove it from the files and return it as working directory for
* the process. Note that it is principle possible to have
* projects with differing repositories open in a session,
* so, trying to find a common repository is not an option.
* Usually, there is only one file argument, which is not
* problematic; it is just split using QFileInfo. */
static inline QString fixFileArgs(QStringList *files)
{
switch (files->size()) {
case 0:
return QString();
case 1: { // Easy, just one
const QFileInfo fi(files->at(0));
(*files)[0] = fi.fileName();
return fi.absolutePath();
}
default:
break;
}
// Find common directory part: "C:\foo\bar" -> "C:\foo"
const QString common = Utils::commonPath(*files);
// remove up until slash from the files
const int commonLength = common.size() + 1;
const QStringList::iterator end = files->end();
for (QStringList::iterator it = files->begin(); it != end; ++it) {
it->remove(0, commonLength);
}
return common;
}
// Format log entry for command // Format log entry for command
static inline QString msgExecutionLogEntry(const QString &workingDir, const QString &executable, const QStringList &arguments) static inline QString msgExecutionLogEntry(const QString &workingDir, const QString &executable, const QStringList &arguments)
{ {
@@ -992,19 +914,6 @@ static inline QString msgExecutionLogEntry(const QString &workingDir, const QStr
return CVSPlugin::tr("Executing in %1: %2 %3\n").arg(workingDir, executable, args); return CVSPlugin::tr("Executing in %1: %2 %3\n").arg(workingDir, executable, args);
} }
// Figure out a working directory for the process,
// fix the file arguments accordingly and run CVS.
CVSResponse CVSPlugin::runCVS(const QStringList &arguments,
QStringList files,
int timeOut,
bool showStdOutInOutputWindow,
QTextCodec *outputCodec,
bool mergeStderr)
{
const QString workingDirectory = fixFileArgs(&files);
return runCVS( workingDirectory, arguments + files, timeOut, showStdOutInOutputWindow, outputCodec, mergeStderr);
}
// Run CVS. At this point, file arguments must be relative to // Run CVS. At this point, file arguments must be relative to
// the working directory (see above). // the working directory (see above).
CVSResponse CVSPlugin::runCVS(const QString &workingDirectory, CVSResponse CVSPlugin::runCVS(const QString &workingDirectory,
@@ -1021,10 +930,9 @@ CVSResponse CVSPlugin::runCVS(const QString &workingDirectory,
return response; return response;
} }
// Fix files and compile complete arguments // Fix files and compile complete arguments
response.workingDirectory = workingDirectory;
const QStringList allArgs = m_settings.addOptions(arguments); const QStringList allArgs = m_settings.addOptions(arguments);
const QString outputText = msgExecutionLogEntry(response.workingDirectory, executable, allArgs); const QString outputText = msgExecutionLogEntry(workingDirectory, executable, allArgs);
VCSBase::VCSBaseOutputWindow::instance()->appendCommand(outputText); VCSBase::VCSBaseOutputWindow::instance()->appendCommand(outputText);
if (CVS::Constants::debug) if (CVS::Constants::debug)
@@ -1032,8 +940,8 @@ CVSResponse CVSPlugin::runCVS(const QString &workingDirectory,
// Run, connect stderr to the output window // Run, connect stderr to the output window
Utils::SynchronousProcess process; Utils::SynchronousProcess process;
if (!response.workingDirectory.isEmpty()) if (!workingDirectory.isEmpty())
process.setWorkingDirectory(response.workingDirectory); process.setWorkingDirectory(workingDirectory);
if (mergeStderr) if (mergeStderr)
process.setProcessChannelMode(QProcess::MergedChannels); process.setProcessChannelMode(QProcess::MergedChannels);
@@ -1124,17 +1032,19 @@ CVSPlugin *CVSPlugin::cvsPluginInstance()
return m_cvsPluginInstance; return m_cvsPluginInstance;
} }
bool CVSPlugin::vcsAdd(const QString &rawFileName) bool CVSPlugin::vcsAdd(const QString &workingDir, const QString &rawFileName)
{ {
const CVSResponse response = runCVS(QStringList(QLatin1String("add")), QStringList(rawFileName), cvsShortTimeOut, true); QStringList args;
args << QLatin1String("add") << rawFileName;
const CVSResponse response = runCVS(workingDir, args, cvsShortTimeOut, true);
return response.result == CVSResponse::Ok; return response.result == CVSResponse::Ok;
} }
bool CVSPlugin::vcsDelete(const QString &rawFileName) bool CVSPlugin::vcsDelete(const QString &workingDir, const QString &rawFileName)
{ {
QStringList args(QLatin1String("remove")); QStringList args;
args << QLatin1String("-f"); args << QLatin1String("remove") << QLatin1String("-f") << rawFileName;
const CVSResponse response = runCVS(args, QStringList(rawFileName), cvsShortTimeOut, true); const CVSResponse response = runCVS(workingDir, args, cvsShortTimeOut, true);
return response.result == CVSResponse::Ok; return response.result == CVSResponse::Ok;
} }

View File

@@ -50,10 +50,6 @@ namespace Utils {
class ParameterAction; class ParameterAction;
} }
namespace ProjectExplorer {
class ProjectExplorerPlugin;
}
namespace VCSBase { namespace VCSBase {
class VCSBaseSubmitEditor; class VCSBaseSubmitEditor;
} }
@@ -73,16 +69,8 @@ struct CVSResponse
QString stdOut; QString stdOut;
QString stdErr; QString stdErr;
QString message; QString message;
QString workingDirectory;
}; };
/* This plugin differs from the other VCS plugins in that it
* runs CVS commands from a working directory using relative
* path specifications, which is a requirement imposed by
* Tortoise CVS. This has to be taken into account; for example,
* the diff editor has an additional property specifying the
* base directory for its interaction to work. */
class CVSPlugin : public VCSBase::VCSBasePlugin class CVSPlugin : public VCSBase::VCSBasePlugin
{ {
Q_OBJECT Q_OBJECT
@@ -94,7 +82,7 @@ public:
virtual bool initialize(const QStringList &arguments, QString *error_message); virtual bool initialize(const QStringList &arguments, QString *error_message);
virtual void extensionsInitialized(); virtual void extensionsInitialized();
void cvsDiff(const QStringList &files, QString diffname = QString()); void cvsDiff(const QString &workingDir, const QStringList &files);
CVSSubmitEditor *openCVSSubmitEditor(const QString &fileName); CVSSubmitEditor *openCVSSubmitEditor(const QString &fileName);
@@ -102,8 +90,8 @@ public:
void setSettings(const CVSSettings &s); void setSettings(const CVSSettings &s);
// IVersionControl // IVersionControl
bool vcsAdd(const QString &fileName); bool vcsAdd(const QString &workingDir, const QString &fileName);
bool vcsDelete(const QString &fileName); bool vcsDelete(const QString &workingDir, const QString &fileName);
bool managesDirectory(const QString &directory) const; bool managesDirectory(const QString &directory) const;
QString findTopLevelForDirectory(const QString &directory) const; QString findTopLevelForDirectory(const QString &directory) const;
@@ -123,7 +111,7 @@ private slots:
void slotDescribe(const QString &source, const QString &changeNr); void slotDescribe(const QString &source, const QString &changeNr);
void updateProject(); void updateProject();
void submitCurrentLog(); void submitCurrentLog();
void diffFiles(const QStringList &); void diffCommitFiles(const QStringList &);
protected: protected:
virtual void updateActions(VCSBase::VCSBasePlugin::ActionState); virtual void updateActions(VCSBase::VCSBasePlugin::ActionState);
@@ -131,15 +119,9 @@ protected:
private: private:
bool isCommitEditorOpen() const; bool isCommitEditorOpen() const;
QString currentFileName() const;
Core::IEditor * showOutputInEditor(const QString& title, const QString &output, Core::IEditor * showOutputInEditor(const QString& title, const QString &output,
int editorType, const QString &source, int editorType, const QString &source,
QTextCodec *codec); QTextCodec *codec);
CVSResponse runCVS(const QStringList &arguments,
QStringList fileArguments,
int timeOut,
bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0,
bool mergeStderr = false);
CVSResponse runCVS(const QString &workingDirectory, CVSResponse runCVS(const QString &workingDirectory,
const QStringList &arguments, const QStringList &arguments,
@@ -147,34 +129,33 @@ private:
bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0, bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0,
bool mergeStderr = false); bool mergeStderr = false);
void annotate(const QString &file); void annotate(const QString &workingDir, const QString &file);
bool describe(const QString &source, const QString &changeNr, QString *errorMessage); bool describe(const QString &source, const QString &changeNr, QString *errorMessage);
bool describe(const QString &toplevel, const QString &source, const QString &changeNr, QString *errorMessage);
bool describe(const QString &repository, QList<CVS_LogEntry> entries, QString *errorMessage); bool describe(const QString &repository, QList<CVS_LogEntry> entries, QString *errorMessage);
void filelog(const QString &file); void filelog(const QString &workingDir, const QStringList &files = QStringList());
bool managesDirectory(const QDir &directory) const; bool managesDirectory(const QDir &directory) const;
QString findTopLevelForDirectoryI(const QString &directory) const; QString findTopLevelForDirectoryI(const QString &directory) const;
QStringList currentProjectsTopLevels(QString *name = 0) const; void startCommit(const QString &workingDir, const QStringList &files = QStringList());
void startCommit(const QString &file);
bool commit(const QString &messageFile, const QStringList &subVersionFileList); bool commit(const QString &messageFile, const QStringList &subVersionFileList);
void cleanCommitMessageFile(); void cleanCommitMessageFile();
inline CVSControl *cvsVersionControl() const; inline CVSControl *cvsVersionControl() const;
CVSSettings m_settings; CVSSettings m_settings;
QString m_commitMessageFileName; QString m_commitMessageFileName;
QString m_commitRepository;
ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
Utils::ParameterAction *m_addAction; Utils::ParameterAction *m_addAction;
Utils::ParameterAction *m_deleteAction; Utils::ParameterAction *m_deleteAction;
Utils::ParameterAction *m_revertAction; Utils::ParameterAction *m_revertAction;
QAction *m_diffProjectAction; Utils::ParameterAction *m_diffProjectAction;
Utils::ParameterAction *m_diffCurrentAction; Utils::ParameterAction *m_diffCurrentAction;
QAction *m_commitAllAction; QAction *m_commitAllAction;
Utils::ParameterAction *m_commitCurrentAction; Utils::ParameterAction *m_commitCurrentAction;
Utils::ParameterAction *m_filelogCurrentAction; Utils::ParameterAction *m_filelogCurrentAction;
Utils::ParameterAction *m_annotateCurrentAction; Utils::ParameterAction *m_annotateCurrentAction;
QAction *m_statusAction; Utils::ParameterAction *m_statusProjectAction;
QAction *m_updateProjectAction; Utils::ParameterAction *m_updateProjectAction;
QAction *m_submitCurrentLogAction; QAction *m_submitCurrentLogAction;
QAction *m_submitDiffAction; QAction *m_submitDiffAction;

View File

@@ -196,6 +196,7 @@ void GitClient::diff(const QString &workingDirectory,
const QString title = tr("Git Diff"); const QString title = tr("Git Diff");
VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, workingDirectory, true, "originalFileName", workingDirectory); VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, workingDirectory, true, "originalFileName", workingDirectory);
editor->setDiffBaseDirectory(workingDirectory);
// Create a batch of 2 commands to be run after each other in case // Create a batch of 2 commands to be run after each other in case
// we have a mixture of staged/unstaged files as is the case // we have a mixture of staged/unstaged files as is the case

View File

@@ -30,9 +30,9 @@
#include "giteditor.h" #include "giteditor.h"
#include "annotationhighlighter.h" #include "annotationhighlighter.h"
#include "gitclient.h"
#include "gitconstants.h" #include "gitconstants.h"
#include "gitplugin.h" #include "gitplugin.h"
#include "gitsettings.h"
#include <QtCore/QTextCodec> #include <QtCore/QTextCodec>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
@@ -122,21 +122,14 @@ VCSBase::BaseAnnotationHighlighter *GitEditor::createAnnotationHighlighter(const
QString GitEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const QString GitEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const
{ {
QString errorMessage; // Check for "+++ b/src/plugins/git/giteditor.cpp" (blame and diff)
// Check for "+++ b/src/plugins/git/giteditor.cpp" (blame and diff)
// Go back chunks. // Go back chunks.
const QString newFileIndicator = QLatin1String("+++ b/"); const QString newFileIndicator = QLatin1String("+++ b/");
for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) { for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) {
QString diffFileName = block.text(); QString diffFileName = block.text();
if (diffFileName.startsWith(newFileIndicator)) { if (diffFileName.startsWith(newFileIndicator)) {
diffFileName.remove(0, newFileIndicator.size()); diffFileName.remove(0, newFileIndicator.size());
const QString fileOrDir = source(); return findDiffFile(diffFileName, GitPlugin::instance()->versionControl());
const QString repo = QFileInfo(fileOrDir).isDir() ?
GitClient::findRepositoryForDirectory(fileOrDir) : GitClient::findRepositoryForFile(fileOrDir);
const QString absPath = QDir(repo).absoluteFilePath(diffFileName);
if (Git::Constants::debug)
qDebug() << "fileNameFromDiffSpecification" << repo << diffFileName << absPath;
return absPath;
} }
} }
return QString(); return QString();
@@ -195,3 +188,4 @@ void GitEditor::commandFinishedGotoLine(bool ok, const QVariant &v)
} // namespace Internal } // namespace Internal
} // namespace Git } // namespace Git

View File

@@ -190,6 +190,7 @@ void MercurialClient::diff(const QString &workingDir, const QStringList &files)
const QString source = VCSBase::VCSBaseEditor::getSource(workingDir, files); const QString source = VCSBase::VCSBaseEditor::getSource(workingDir, files);
VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, source, true, VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, source, true,
"diff", id); "diff", id);
editor->setDiffBaseDirectory(workingDir);
QSharedPointer<HgTask> job(new HgTask(workingDir, args, editor)); QSharedPointer<HgTask> job(new HgTask(workingDir, args, editor));
enqueueJob(job); enqueueJob(job);

View File

@@ -30,7 +30,7 @@
#include "mercurialeditor.h" #include "mercurialeditor.h"
#include "annotationhighlighter.h" #include "annotationhighlighter.h"
#include "constants.h" #include "constants.h"
#include "mercurialclient.h" #include "mercurialplugin.h"
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <vcsbase/diffhighlighter.h> #include <vcsbase/diffhighlighter.h>
@@ -103,10 +103,8 @@ QString MercurialEditor::fileNameFromDiffSpecification(const QTextBlock &diffFil
QTextFragment fragment = iterator.fragment(); QTextFragment fragment = iterator.fragment();
if(fragment.isValid()) { if(fragment.isValid()) {
if (fragment.text().startsWith(filechangeId)) { if (fragment.text().startsWith(filechangeId)) {
const QFileInfo sourceFile(source());
const QDir repository(MercurialClient::findTopLevelForFile(sourceFile));
const QString filename = fragment.text().remove(0, filechangeId.size()); const QString filename = fragment.text().remove(0, filechangeId.size());
return repository.absoluteFilePath(filename); return findDiffFile(filename, MercurialPlugin::instance()->versionControl());
} }
} }
} }

View File

@@ -451,6 +451,12 @@ void SubversionPlugin::diffCommitFiles(const QStringList &files)
svnDiff(m_commitRepository, files); svnDiff(m_commitRepository, files);
} }
static inline void setDiffBaseDirectory(Core::IEditor *editor, const QString &db)
{
if (VCSBase::VCSBaseEditor *ve = qobject_cast<VCSBase::VCSBaseEditor*>(editor->widget()))
ve->setDiffBaseDirectory(db);
}
void SubversionPlugin::svnDiff(const QString &workingDir, const QStringList &files, QString diffname) void SubversionPlugin::svnDiff(const QString &workingDir, const QStringList &files, QString diffname)
{ {
if (Subversion::Constants::debug) if (Subversion::Constants::debug)
@@ -475,11 +481,13 @@ void SubversionPlugin::svnDiff(const QString &workingDir, const QStringList &fil
if (Core::IEditor *editor = locateEditor("originalFileName", files.front())) { if (Core::IEditor *editor = locateEditor("originalFileName", files.front())) {
editor->createNew(response.stdOut); editor->createNew(response.stdOut);
Core::EditorManager::instance()->activateEditor(editor); Core::EditorManager::instance()->activateEditor(editor);
setDiffBaseDirectory(editor, workingDir);
return; return;
} }
} }
const QString title = QString::fromLatin1("svn diff %1").arg(diffname); const QString title = QString::fromLatin1("svn diff %1").arg(diffname);
Core::IEditor *editor = showOutputInEditor(title, response.stdOut, VCSBase::DiffOutput, source, codec); Core::IEditor *editor = showOutputInEditor(title, response.stdOut, VCSBase::DiffOutput, source, codec);
setDiffBaseDirectory(editor, workingDir);
if (files.count() == 1) if (files.count() == 1)
editor->setProperty("originalFileName", files.front()); editor->setProperty("originalFileName", files.front());
} }

View File

@@ -147,6 +147,7 @@ struct VCSBaseEditorPrivate
QAction *m_describeAction; QAction *m_describeAction;
QString m_currentChange; QString m_currentChange;
QString m_source; QString m_source;
QString m_diffBaseDirectory;
QRegExp m_diffFilePattern; QRegExp m_diffFilePattern;
QList<int> m_diffSections; // line number where this section starts QList<int> m_diffSections; // line number where this section starts
@@ -210,6 +211,16 @@ void VCSBaseEditor::setSource(const QString &source)
d->m_source = source; d->m_source = source;
} }
QString VCSBaseEditor::diffBaseDirectory() const
{
return d->m_diffBaseDirectory;
}
void VCSBaseEditor::setDiffBaseDirectory(const QString &bd)
{
d->m_diffBaseDirectory = bd;
}
QTextCodec *VCSBaseEditor::codec() const QTextCodec *VCSBaseEditor::codec() const
{ {
return baseTextDocument()->codec(); return baseTextDocument()->codec();
@@ -678,18 +689,25 @@ QString VCSBaseEditor::getTitleId(const QString &workingDirectory, const QString
// Find the complete file from a diff relative specification. // Find the complete file from a diff relative specification.
QString VCSBaseEditor::findDiffFile(const QString &f, Core::IVersionControl *control /* = 0 */) const QString VCSBaseEditor::findDiffFile(const QString &f, Core::IVersionControl *control /* = 0 */) const
{ {
// Try the file. // Try the file itself, expand to absolute.
const QFileInfo in(f); const QFileInfo in(f);
if (in.isAbsolute()) if (in.isAbsolute())
return in.isFile() ? f : QString(); return in.isFile() ? f : QString();
if (in.isFile()) if (in.isFile())
return in.absoluteFilePath(); return in.absoluteFilePath();
// Try in source directory // 1) Try base dir
const QChar slash = QLatin1Char('/');
if (!d->m_diffBaseDirectory.isEmpty()) {
const QFileInfo baseFileInfo(d->m_diffBaseDirectory + slash + f);
if (baseFileInfo.isFile())
return baseFileInfo.absoluteFilePath();
}
// 2) Try in source (which can be file or directory)
if (source().isEmpty()) if (source().isEmpty())
return QString(); return QString();
const QFileInfo sourceInfo(source()); const QFileInfo sourceInfo(source());
const QString sourceDir = sourceInfo.isDir() ? sourceInfo.absoluteFilePath() : sourceInfo.absolutePath(); const QString sourceDir = sourceInfo.isDir() ? sourceInfo.absoluteFilePath() : sourceInfo.absolutePath();
const QFileInfo sourceFileInfo(sourceDir + QLatin1Char('/') + f); const QFileInfo sourceFileInfo(sourceDir + slash + f);
if (sourceFileInfo.isFile()) if (sourceFileInfo.isFile())
return sourceFileInfo.absoluteFilePath(); return sourceFileInfo.absoluteFilePath();
// Try to locate via repository. // Try to locate via repository.
@@ -698,7 +716,7 @@ QString VCSBaseEditor::findDiffFile(const QString &f, Core::IVersionControl *con
const QString topLevel = control->findTopLevelForDirectory(sourceDir); const QString topLevel = control->findTopLevelForDirectory(sourceDir);
if (topLevel.isEmpty()) if (topLevel.isEmpty())
return QString(); return QString();
const QFileInfo topLevelFileInfo(topLevel + QLatin1Char('/') + f); const QFileInfo topLevelFileInfo(topLevel + slash + f);
if (topLevelFileInfo.isFile()) if (topLevelFileInfo.isFile())
return topLevelFileInfo.absoluteFilePath(); return topLevelFileInfo.absoluteFilePath();
return QString(); return QString();

View File

@@ -87,6 +87,7 @@ struct VCSBASE_EXPORT VCSBaseEditorParameters {
class VCSBASE_EXPORT VCSBaseEditor : public TextEditor::BaseTextEditor class VCSBASE_EXPORT VCSBaseEditor : public TextEditor::BaseTextEditor
{ {
Q_PROPERTY(QString source READ source WRITE setSource) Q_PROPERTY(QString source READ source WRITE setSource)
Q_PROPERTY(QString diffBaseDirectory READ diffBaseDirectory WRITE setDiffBaseDirectory)
Q_PROPERTY(QTextCodec *codec READ codec WRITE setCodec) Q_PROPERTY(QTextCodec *codec READ codec WRITE setCodec)
Q_OBJECT Q_OBJECT
protected: protected:
@@ -105,6 +106,10 @@ public:
QTextCodec *codec() const; QTextCodec *codec() const;
void setCodec(QTextCodec *); void setCodec(QTextCodec *);
// Base directory for diff views
QString diffBaseDirectory() const;
void setDiffBaseDirectory(const QString &d);
bool isModified() const; bool isModified() const;
EditorContentType contentType() const; EditorContentType contentType() const;
@@ -137,7 +142,7 @@ public:
// editor if one has a call consisting of working directory and file arguments. // editor if one has a call consisting of working directory and file arguments.
// ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file'). // ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file').
static QString getSource(const QString &workingDirectory, const QString &fileName); static QString getSource(const QString &workingDirectory, const QString &fileName);
static QString getSource(const QString &workingDirectory, const QStringList &fileNames); static QString getSource(const QString &workingDirectory, const QStringList &fileNames);
// Convenience functions to determine an title/id to identify the editor // Convenience functions to determine an title/id to identify the editor
// from the arguments (','-joined arguments or directory). // from the arguments (','-joined arguments or directory).
static QString getTitleId(const QString &workingDirectory, const QStringList &fileNames); static QString getTitleId(const QString &workingDirectory, const QStringList &fileNames);
@@ -171,8 +176,8 @@ private slots:
protected: protected:
/* A helper that can be used to locate a file in a diff in case it /* A helper that can be used to locate a file in a diff in case it
* is relative. Tries to derive the directory from source and * is relative. Tries to derive the directory from base directory,
* version control. */ * source and version control. */
QString findDiffFile(const QString &f, Core::IVersionControl *control = 0) const; QString findDiffFile(const QString &f, Core::IVersionControl *control = 0) const;
private: private: