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

View File

@@ -142,35 +142,11 @@ QString CVSEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) cons
const int tabIndex = diffFileName.indexOf(QLatin1Char('\t'));
if (tabIndex != -1)
diffFileName.truncate(tabIndex);
// Add base dir
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 findDiffFile(diffFileName);
}
}
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,
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:
virtual QSet<QString> annotationChanges() const;
virtual QString changeUnderCursor(const QTextCursor &) const;

View File

@@ -41,8 +41,6 @@
#include <vcsbase/vcsbaseoutputwindow.h>
#include <utils/synchronousprocess.h>
#include <utils/parameteraction.h>
#include <projectexplorer/session.h>
#include <projectexplorer/project.h>
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
@@ -53,7 +51,6 @@
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/vcsmanager.h>
#include <projectexplorer/projectexplorer.h>
#include <utils/stringutils.h>
#include <utils/qtcassert.h>
@@ -152,7 +149,6 @@ CVSPlugin *CVSPlugin::m_cvsPluginInstance = 0;
CVSPlugin::CVSPlugin() :
VCSBase::VCSBasePlugin(QLatin1String(CVS::Constants::CVSCOMMITEDITOR_KIND)),
m_projectExplorer(0),
m_addAction(0),
m_deleteAction(0),
m_revertAction(0),
@@ -162,7 +158,7 @@ CVSPlugin::CVSPlugin() :
m_commitCurrentAction(0),
m_filelogCurrentAction(0),
m_annotateCurrentAction(0),
m_statusAction(0),
m_statusProjectAction(0),
m_updateProjectAction(0),
m_submitCurrentLogAction(0),
m_submitDiffAction(0),
@@ -183,6 +179,7 @@ void CVSPlugin::cleanCommitMessageFile()
if (!m_commitMessageFileName.isEmpty()) {
QFile::remove(m_commitMessageFileName);
m_commitMessageFileName.clear();
m_commitRepository.clear();
}
}
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));
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,
globalcontext);
command->setAttribute(Core::Command::CA_UpdateText);
connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffProject()));
cvsMenu->addAction(command);
@@ -325,14 +323,16 @@ bool CVSPlugin::initialize(const QStringList & /*arguments */, QString *errorMes
cvsMenu->addAction(createSeparator(this, ami, CMD_ID_SEPARATOR3, globalcontext));
m_statusAction = new QAction(tr("Project Status"), this);
command = ami->registerAction(m_statusAction, CMD_ID_STATUS,
m_statusProjectAction = new Utils::ParameterAction(tr("Project Status"), tr("Status of Project \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
command = ami->registerAction(m_statusProjectAction, CMD_ID_STATUS,
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);
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->setAttribute(Core::Command::CA_UpdateText);
connect(m_updateProjectAction, SIGNAL(triggered()), this, SLOT(updateProject()));
cvsMenu->addAction(command);
@@ -357,7 +357,6 @@ bool CVSPlugin::initialize(const QStringList & /*arguments */, QString *errorMes
void CVSPlugin::extensionsInitialized()
{
m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
}
bool CVSPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor)
@@ -410,27 +409,32 @@ bool CVSPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEdi
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)
qDebug() << Q_FUNC_INFO << files << diffname;
const QString source = files.empty() ? QString() : files.front();
QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditor::getCodec(source);
if (files.count() == 1 && diffname.isEmpty())
diffname = QFileInfo(files.front()).fileName();
qDebug() << Q_FUNC_INFO << files;
const QString source = VCSBase::VCSBaseEditor::getSource(workingDir, files);
QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(workingDir, files);
const QString id = VCSBase::VCSBaseEditor::getTitleId(workingDir, files);
QStringList args(QLatin1String("diff"));
args << m_settings.cvsDiffOptions;
args.append(files);
// CVS returns the diff exit code (1 if files differ), which is
// 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) {
case CVSResponse::NonNullExitCode:
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
if (files.count() == 1) {
// 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);
Core::EditorManager::instance()->activateEditor(editor);
CVSEditor::setDiffBaseDir(editor, response.workingDirectory);
setDiffBaseDirectory(editor, workingDir);
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);
if (files.count() == 1)
editor->setProperty("originalFileName", files.front());
CVSEditor::setDiffBaseDir(editor, response.workingDirectory);
editor->setProperty("originalFileName", id);
setDiffBaseDirectory(editor, workingDir);
}
CVSSubmitEditor *CVSPlugin::openCVSSubmitEditor(const QString &fileName)
@@ -466,7 +470,7 @@ CVSSubmitEditor *CVSPlugin::openCVSSubmitEditor(const QString &fileName)
CVSSubmitEditor *submitEditor = qobject_cast<CVSSubmitEditor*>(editor);
QTC_ASSERT(submitEditor, /**/);
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;
}
@@ -476,45 +480,45 @@ void CVSPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction))
return;
m_diffProjectAction->setEnabled(true);
m_commitAllAction->setEnabled(true);
m_statusAction->setEnabled(true);
const QString currentFileName = currentState().currentFileName();
m_addAction->setParameter(currentFileName);
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 baseName = fileName.isEmpty() ? fileName : QFileInfo(fileName).fileName();
const QString currentProjectName = currentState().currentProjectName();
m_diffProjectAction->setParameter(currentProjectName);
m_statusProjectAction->setParameter(currentProjectName);
m_updateProjectAction->setParameter(currentProjectName);
m_addAction->setParameter(baseName);
m_deleteAction->setParameter(baseName);
m_revertAction->setParameter(baseName);
m_diffCurrentAction->setParameter(baseName);
m_commitCurrentAction->setParameter(baseName);
m_filelogCurrentAction->setParameter(baseName);
m_annotateCurrentAction->setParameter(baseName);
m_commitAllAction->setEnabled(currentState().hasTopLevel());
}
void CVSPlugin::addCurrentFile()
{
const QString file = currentFileName();
if (!file.isEmpty())
vcsAdd(file);
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasFile(), return)
vcsAdd(state.currentFileTopLevel(), state.relativeCurrentFile());
}
void CVSPlugin::deleteCurrentFile()
{
const QString file = currentFileName();
if (file.isEmpty())
return;
if (!Core::ICore::instance()->vcsManager()->showDeleteDialog(file))
QMessageBox::warning(0, QLatin1String("CVS remove"), tr("The file '%1' could not be deleted.").arg(file), QMessageBox::Ok);
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasFile(), return)
if (!Core::ICore::instance()->vcsManager()->showDeleteDialog(state.currentFile()))
QMessageBox::warning(0, QLatin1String("CVS remove"), tr("The file '%1' could not be deleted.").arg(state.currentFile()), QMessageBox::Ok);
}
void CVSPlugin::revertCurrentFile()
{
const QString file = currentFileName();
if (file.isEmpty())
return;
const CVSResponse diffResponse = runCVS(QStringList(QLatin1String("diff")), QStringList(file), cvsShortTimeOut, false);
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasFile(), return)
QStringList args;
args << QLatin1String("diff") << state.relativeCurrentFile();
const CVSResponse diffResponse = runCVS(state.currentFileTopLevel(), args, cvsShortTimeOut, false);
switch (diffResponse.result) {
case CVSResponse::Ok:
return; // Not modified, diff exit code 0
@@ -530,132 +534,81 @@ void CVSPlugin::revertCurrentFile()
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
return;
Core::FileChangeBlocker fcb(file);
Core::FileChangeBlocker fcb(state.currentFile());
// revert
QStringList args(QLatin1String("update"));
args.push_back(QLatin1String("-C"));
const QStringList files = QStringList(file);
const CVSResponse revertResponse = runCVS(args, files, cvsShortTimeOut, true);
args.clear();
args << QLatin1String("update") << QLatin1String("-C") << state.relativeCurrentFile();
const CVSResponse revertResponse = runCVS(state.currentFileTopLevel(), args, cvsShortTimeOut, true);
if (revertResponse.result == CVSResponse::Ok) {
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()
{
QString diffName;
const QStringList topLevels = currentProjectsTopLevels(&diffName);
if (!topLevels.isEmpty())
cvsDiff(topLevels, diffName);
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasProject(), return)
cvsDiff(state.currentProjectTopLevel(), state.relativeCurrentProject());
}
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()
{
const QString file = currentFileName();
if (!file.isEmpty())
startCommit(file);
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasFile(), return)
startCommit(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
}
void CVSPlugin::startCommitAll()
{
// Make sure we have only repository for commit
const QStringList files = currentProjectsTopLevels();
switch (files.size()) {
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;
}
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasTopLevel(), return)
startCommit(state.topLevel());
}
/* Start commit of files of a single repository by displaying
* template and files in a submit editor. On closing, the real
* 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())
return;
if (isCommitEditorOpen()) {
VCSBase::VCSBaseOutputWindow::instance()->appendWarning(tr("Another commit is currently being executed."));
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
// where we are, so, have stdout/stderr channels merged.
QStringList args = QStringList(QLatin1String("status"));
if (sourceDir == topLevel) {
args.push_back(QString(QLatin1Char('.')));
} else {
args.push_back(QDir(topLevel).relativeFilePath(source));
}
const CVSResponse response = runCVS(topLevel, args, cvsShortTimeOut, false, 0, true);
const CVSResponse response = runCVS(workingDir, args, cvsShortTimeOut, false, 0, true);
if (response.result != CVSResponse::Ok)
return;
// Get list of added/modified/deleted files
// As we run cvs in the repository directory, we need complete
// the file names by the respective directory.
const StateList statusOutput = parseStatusOutput(topLevel, response.stdOut);
if (CVS::Constants::debug)
qDebug() << Q_FUNC_INFO << '\n' << source << "top" << topLevel;
// Get list of added/modified/deleted files and purge out undesired ones
// (do not run status with relative arguments as it will omit the directories)
StateList statusOutput = parseStatusOutput(QString(), response.stdOut);
if (!files.isEmpty()) {
for (StateList::iterator it = statusOutput.begin(); it != statusOutput.end() ; ) {
if (files.contains(it->second)) {
++it;
} else {
it = statusOutput.erase(it);
}
}
}
if (statusOutput.empty()) {
VCSBase::VCSBaseOutputWindow::instance()->append(tr("There are no modified files."));
return;
}
m_commitRepository = workingDir;
// Create a new submit change file containing the submit template
QTemporaryFile changeTmpFile;
@@ -683,62 +636,73 @@ bool CVSPlugin::commit(const QString &messageFile,
qDebug() << Q_FUNC_INFO << messageFile << fileList;
QStringList args = QStringList(QLatin1String("commit"));
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 ;
}
void CVSPlugin::filelogCurrentFile()
{
const QString file = currentFileName();
if (!file.isEmpty())
filelog(file);
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasFile(), return)
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
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)
return;
// Re-use an existing view if possible to support
// 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);
Core::EditorManager::instance()->activateEditor(editor);
} else {
const QString title = QString::fromLatin1("cvs log %1").arg(QFileInfo(file).fileName());
Core::IEditor *newEditor = showOutputInEditor(title, response.stdOut, VCSBase::LogOutput, file, codec);
newEditor->setProperty("logFileName", file);
const QString title = QString::fromLatin1("cvs log %1").arg(id);
Core::IEditor *newEditor = showOutputInEditor(title, response.stdOut, VCSBase::LogOutput, source, codec);
newEditor->setProperty("logFileName", id);
}
}
void CVSPlugin::updateProject()
{
const QStringList topLevels = currentProjectsTopLevels();
if (!topLevels.empty()) {
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasProject(), return)
QStringList args(QLatin1String("update"));
args.push_back(QLatin1String("-dR"));
const CVSResponse response = runCVS(args, topLevels, cvsLongTimeOut, true);
args.append(state.relativeCurrentProject());
const CVSResponse response = runCVS(state.currentProjectTopLevel(), args, cvsLongTimeOut, true);
if (response.result == CVSResponse::Ok)
foreach(const QString &topLevel, topLevels)
cvsVersionControl()->emitRepositoryChanged(topLevel);
}
cvsVersionControl()->emitRepositoryChanged(state.currentProjectTopLevel());
}
void CVSPlugin::annotateCurrentFile()
{
const QString file = currentFileName();
if (!file.isEmpty())
annotate(file);
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasFile(), return)
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 CVSResponse response = runCVS(QStringList(QLatin1String("annotate")), QStringList(file), cvsShortTimeOut, false, codec);
const QStringList files(file);
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)
return;
@@ -746,30 +710,27 @@ void CVSPlugin::annotate(const QString &file)
// the common usage pattern of continuously changing and diffing a 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);
VCSBase::VCSBaseEditor::gotoLineOfEditor(editor, lineNumber);
Core::EditorManager::instance()->activateEditor(editor);
} else {
const QString title = QString::fromLatin1("cvs annotate %1").arg(QFileInfo(file).fileName());
Core::IEditor *newEditor = showOutputInEditor(title, response.stdOut, VCSBase::AnnotateOutput, file, codec);
newEditor->setProperty("annotateFileName", file);
const QString title = QString::fromLatin1("cvs annotate %1").arg(id);
Core::IEditor *newEditor = showOutputInEditor(title, response.stdOut, VCSBase::AnnotateOutput, source, codec);
newEditor->setProperty("annotateFileName", id);
VCSBase::VCSBaseEditor::gotoLineOfEditor(newEditor, lineNumber);
}
}
void CVSPlugin::projectStatus()
{
if (!m_projectExplorer)
return;
const QStringList topLevels = currentProjectsTopLevels();
if (topLevels.empty())
return;
const CVSResponse response = runCVS(QStringList(QLatin1String("status")), topLevels, cvsShortTimeOut, false);
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasProject(), return)
QStringList args;
args << QLatin1String("status") << state.relativeCurrentProject();
const CVSResponse response = runCVS(state.currentProjectTopLevel(), args, cvsShortTimeOut, false);
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"
@@ -797,6 +758,18 @@ void CVSPlugin::slotDescribe(const QString &source, const QString &changeNr)
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
// no global revision/change number. The only thing that groups
// 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 (CVS::Constants::debug)
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
if (isFirstRevision(changeNr)) {
*errorMessage = tr("The initial revision %1 cannot be described.").arg(changeNr);
return false;
}
// Run log to obtain commit id and details
QStringList args(QLatin1String("log"));
args.push_back(QLatin1String("-r") + changeNr);
const CVSResponse logResponse = runCVS(args, QStringList(file), cvsShortTimeOut, false);
QStringList args;
args << QLatin1String("log") << (QLatin1String("-r") + changeNr) << file;
const CVSResponse logResponse = runCVS(toplevel, args, cvsShortTimeOut, false);
if (logResponse.result != CVSResponse::Ok) {
*errorMessage = logResponse.message;
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()) {
*errorMessage = msgLogParsingFailed();
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);
args.clear();
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) {
*errorMessage = repoLogResponse.message;
return false;
}
// 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()) {
*errorMessage = tr("Could not find commits of id '%1' on %2.").arg(commitId, dateS);
return false;
@@ -859,20 +828,18 @@ bool CVSPlugin::describe(const QString &file, const QString &changeNr, QString *
// Describe a set of files and revisions by
// 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)
{
// Collect logs
QString output;
const QDir repository(repositoryPath);
QTextCodec *codec = 0;
const QList<CVS_LogEntry>::iterator lend = entries.end();
for (QList<CVS_LogEntry>::iterator it = entries.begin(); it != lend; ++it) {
// Before fiddling file names, try to find codec
if (!codec)
codec = VCSBase::VCSBaseEditor::getCodec(it->file);
// Make the files relative to the repository directory.
it->file = repository.relativeFilePath(it->file);
codec = VCSBase::VCSBaseEditor::getCodec(repositoryPath, QStringList(it->file));
// Run log
QStringList args(QLatin1String("log"));
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)) {
editor->createNew(output);
Core::EditorManager::instance()->activateEditor(editor);
CVSEditor::setDiffBaseDir(editor, repositoryPath);
setDiffBaseDirectory(editor, repositoryPath);
} else {
const QString title = QString::fromLatin1("cvs describe %1").arg(commitId);
Core::IEditor *newEditor = showOutputInEditor(title, output, VCSBase::DiffOutput, entries.front().file, codec);
newEditor->setProperty("describeChange", commitId);
CVSEditor::setDiffBaseDir(newEditor, repositoryPath);
setDiffBaseDirectory(editor, repositoryPath);
}
return true;
}
@@ -932,56 +899,11 @@ void CVSPlugin::submitCurrentLog()
<< 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)
{
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
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);
}
// 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
// the working directory (see above).
CVSResponse CVSPlugin::runCVS(const QString &workingDirectory,
@@ -1021,10 +930,9 @@ CVSResponse CVSPlugin::runCVS(const QString &workingDirectory,
return response;
}
// Fix files and compile complete arguments
response.workingDirectory = workingDirectory;
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);
if (CVS::Constants::debug)
@@ -1032,8 +940,8 @@ CVSResponse CVSPlugin::runCVS(const QString &workingDirectory,
// Run, connect stderr to the output window
Utils::SynchronousProcess process;
if (!response.workingDirectory.isEmpty())
process.setWorkingDirectory(response.workingDirectory);
if (!workingDirectory.isEmpty())
process.setWorkingDirectory(workingDirectory);
if (mergeStderr)
process.setProcessChannelMode(QProcess::MergedChannels);
@@ -1124,17 +1032,19 @@ CVSPlugin *CVSPlugin::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;
}
bool CVSPlugin::vcsDelete(const QString &rawFileName)
bool CVSPlugin::vcsDelete(const QString &workingDir, const QString &rawFileName)
{
QStringList args(QLatin1String("remove"));
args << QLatin1String("-f");
const CVSResponse response = runCVS(args, QStringList(rawFileName), cvsShortTimeOut, true);
QStringList args;
args << QLatin1String("remove") << QLatin1String("-f") << rawFileName;
const CVSResponse response = runCVS(workingDir, args, cvsShortTimeOut, true);
return response.result == CVSResponse::Ok;
}

View File

@@ -50,10 +50,6 @@ namespace Utils {
class ParameterAction;
}
namespace ProjectExplorer {
class ProjectExplorerPlugin;
}
namespace VCSBase {
class VCSBaseSubmitEditor;
}
@@ -73,16 +69,8 @@ struct CVSResponse
QString stdOut;
QString stdErr;
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
{
Q_OBJECT
@@ -94,7 +82,7 @@ public:
virtual bool initialize(const QStringList &arguments, QString *error_message);
virtual void extensionsInitialized();
void cvsDiff(const QStringList &files, QString diffname = QString());
void cvsDiff(const QString &workingDir, const QStringList &files);
CVSSubmitEditor *openCVSSubmitEditor(const QString &fileName);
@@ -102,8 +90,8 @@ public:
void setSettings(const CVSSettings &s);
// IVersionControl
bool vcsAdd(const QString &fileName);
bool vcsDelete(const QString &fileName);
bool vcsAdd(const QString &workingDir, const QString &fileName);
bool vcsDelete(const QString &workingDir, const QString &fileName);
bool managesDirectory(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 updateProject();
void submitCurrentLog();
void diffFiles(const QStringList &);
void diffCommitFiles(const QStringList &);
protected:
virtual void updateActions(VCSBase::VCSBasePlugin::ActionState);
@@ -131,15 +119,9 @@ protected:
private:
bool isCommitEditorOpen() const;
QString currentFileName() const;
Core::IEditor * showOutputInEditor(const QString& title, const QString &output,
int editorType, const QString &source,
QTextCodec *codec);
CVSResponse runCVS(const QStringList &arguments,
QStringList fileArguments,
int timeOut,
bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0,
bool mergeStderr = false);
CVSResponse runCVS(const QString &workingDirectory,
const QStringList &arguments,
@@ -147,34 +129,33 @@ private:
bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0,
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 &toplevel, const QString &source, const QString &changeNr, 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;
QString findTopLevelForDirectoryI(const QString &directory) const;
QStringList currentProjectsTopLevels(QString *name = 0) const;
void startCommit(const QString &file);
void startCommit(const QString &workingDir, const QStringList &files = QStringList());
bool commit(const QString &messageFile, const QStringList &subVersionFileList);
void cleanCommitMessageFile();
inline CVSControl *cvsVersionControl() const;
CVSSettings m_settings;
QString m_commitMessageFileName;
ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
QString m_commitRepository;
Utils::ParameterAction *m_addAction;
Utils::ParameterAction *m_deleteAction;
Utils::ParameterAction *m_revertAction;
QAction *m_diffProjectAction;
Utils::ParameterAction *m_diffProjectAction;
Utils::ParameterAction *m_diffCurrentAction;
QAction *m_commitAllAction;
Utils::ParameterAction *m_commitCurrentAction;
Utils::ParameterAction *m_filelogCurrentAction;
Utils::ParameterAction *m_annotateCurrentAction;
QAction *m_statusAction;
QAction *m_updateProjectAction;
Utils::ParameterAction *m_statusProjectAction;
Utils::ParameterAction *m_updateProjectAction;
QAction *m_submitCurrentLogAction;
QAction *m_submitDiffAction;

View File

@@ -196,6 +196,7 @@ void GitClient::diff(const QString &workingDirectory,
const QString title = tr("Git Diff");
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
// we have a mixture of staged/unstaged files as is the case

View File

@@ -30,9 +30,9 @@
#include "giteditor.h"
#include "annotationhighlighter.h"
#include "gitclient.h"
#include "gitconstants.h"
#include "gitplugin.h"
#include "gitsettings.h"
#include <QtCore/QTextCodec>
#include <coreplugin/editormanager/editormanager.h>
@@ -122,7 +122,6 @@ VCSBase::BaseAnnotationHighlighter *GitEditor::createAnnotationHighlighter(const
QString GitEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const
{
QString errorMessage;
// Check for "+++ b/src/plugins/git/giteditor.cpp" (blame and diff)
// Go back chunks.
const QString newFileIndicator = QLatin1String("+++ b/");
@@ -130,13 +129,7 @@ QString GitEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) cons
QString diffFileName = block.text();
if (diffFileName.startsWith(newFileIndicator)) {
diffFileName.remove(0, newFileIndicator.size());
const QString fileOrDir = source();
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 findDiffFile(diffFileName, GitPlugin::instance()->versionControl());
}
}
return QString();
@@ -195,3 +188,4 @@ void GitEditor::commandFinishedGotoLine(bool ok, const QVariant &v)
} // namespace Internal
} // 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);
VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, source, true,
"diff", id);
editor->setDiffBaseDirectory(workingDir);
QSharedPointer<HgTask> job(new HgTask(workingDir, args, editor));
enqueueJob(job);

View File

@@ -30,7 +30,7 @@
#include "mercurialeditor.h"
#include "annotationhighlighter.h"
#include "constants.h"
#include "mercurialclient.h"
#include "mercurialplugin.h"
#include <coreplugin/editormanager/editormanager.h>
#include <vcsbase/diffhighlighter.h>
@@ -103,10 +103,8 @@ QString MercurialEditor::fileNameFromDiffSpecification(const QTextBlock &diffFil
QTextFragment fragment = iterator.fragment();
if(fragment.isValid()) {
if (fragment.text().startsWith(filechangeId)) {
const QFileInfo sourceFile(source());
const QDir repository(MercurialClient::findTopLevelForFile(sourceFile));
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);
}
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)
{
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())) {
editor->createNew(response.stdOut);
Core::EditorManager::instance()->activateEditor(editor);
setDiffBaseDirectory(editor, workingDir);
return;
}
}
const QString title = QString::fromLatin1("svn diff %1").arg(diffname);
Core::IEditor *editor = showOutputInEditor(title, response.stdOut, VCSBase::DiffOutput, source, codec);
setDiffBaseDirectory(editor, workingDir);
if (files.count() == 1)
editor->setProperty("originalFileName", files.front());
}

View File

@@ -147,6 +147,7 @@ struct VCSBaseEditorPrivate
QAction *m_describeAction;
QString m_currentChange;
QString m_source;
QString m_diffBaseDirectory;
QRegExp m_diffFilePattern;
QList<int> m_diffSections; // line number where this section starts
@@ -210,6 +211,16 @@ void VCSBaseEditor::setSource(const QString &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
{
return baseTextDocument()->codec();
@@ -678,18 +689,25 @@ QString VCSBaseEditor::getTitleId(const QString &workingDirectory, const QString
// Find the complete file from a diff relative specification.
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);
if (in.isAbsolute())
return in.isFile() ? f : QString();
if (in.isFile())
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())
return QString();
const QFileInfo sourceInfo(source());
const QString sourceDir = sourceInfo.isDir() ? sourceInfo.absoluteFilePath() : sourceInfo.absolutePath();
const QFileInfo sourceFileInfo(sourceDir + QLatin1Char('/') + f);
const QFileInfo sourceFileInfo(sourceDir + slash + f);
if (sourceFileInfo.isFile())
return sourceFileInfo.absoluteFilePath();
// Try to locate via repository.
@@ -698,7 +716,7 @@ QString VCSBaseEditor::findDiffFile(const QString &f, Core::IVersionControl *con
const QString topLevel = control->findTopLevelForDirectory(sourceDir);
if (topLevel.isEmpty())
return QString();
const QFileInfo topLevelFileInfo(topLevel + QLatin1Char('/') + f);
const QFileInfo topLevelFileInfo(topLevel + slash + f);
if (topLevelFileInfo.isFile())
return topLevelFileInfo.absoluteFilePath();
return QString();

View File

@@ -87,6 +87,7 @@ struct VCSBASE_EXPORT VCSBaseEditorParameters {
class VCSBASE_EXPORT VCSBaseEditor : public TextEditor::BaseTextEditor
{
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_OBJECT
protected:
@@ -105,6 +106,10 @@ public:
QTextCodec *codec() const;
void setCodec(QTextCodec *);
// Base directory for diff views
QString diffBaseDirectory() const;
void setDiffBaseDirectory(const QString &d);
bool isModified() const;
EditorContentType contentType() const;
@@ -171,8 +176,8 @@ private slots:
protected:
/* 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
* version control. */
* is relative. Tries to derive the directory from base directory,
* source and version control. */
QString findDiffFile(const QString &f, Core::IVersionControl *control = 0) const;
private: