/****************************************************************************
**
** Copyright (C) 2001-2006 Frank Hemer <frank@hemer.org>,
** Tilo Riemer <riemer@crossvc.com>,
** Jose Hernandez <joseh@tesco.net>,
** Tom Mishima <tmishima@mail.at-m.or.jp>
**
**
**----------------------------------------------------------------------------
**
**----------------------------------------------------------------------------
**
** CrossVC is available under two different licenses:
**
** If CrossVC is linked against the GPLed version of Qt
** CrossVC is released under the terms of GPL also.
**
** If CrossVC is linked against a nonGPLed version of Qt
** CrossVC is released under the terms of the
** CrossVC License for non-Unix platforms (CLNU)
**
**
** CrossVC License for non-Unix platforms (CLNU):
**
** Redistribution and use in binary form, without modification,
** are permitted provided that the following conditions are met:
**
** 1. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 2. It is not permitted to distribute the binary package under a name
** different than CrossVC.
** 3. The name of the authors may not be used to endorse or promote
** products derived from this software without specific prior written
** permission.
** 4. The source code is the creative property of the authors.
** Extensions and development under the terms of the Gnu Public License
** are limited to the Unix platform. Any distribution or compilation of
** the source code against libraries licensed other than gpl requires
** the written permission of the authors.
**
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
**
**
** CrossVC License for Unix platforms:
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, version 2 of the License.
** This program is distributed in
** the hope that it will be useful, but WITHOUT ANY WARRANTY; without
** even the implied warranty of MERCHANTABILITY or FITNESS FOR A
** PARTICULAR PURPOSE.
**
** See the GNU General Public License version 2 for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*****************************************************************************/
#include "config.h"
#include <stdlib.h>
#include <qtextcodec.h>
#include <qstring.h>
#include <qfont.h>
#include <qstringlist.h>
#include <qpushbutton.h>
#include <qmessagebox.h>
#include <qlayout.h>
#include <qcolordialog.h>
#include <qregexp.h>
#include <qapplication.h>
#include <qinputdialog.h>
#include <qmultilineedit.h>
#include <qwhatsthis.h>
#include <qcheckbox.h>
#include <qsizegrip.h>
#include <assert.h>
#ifndef Q_WS_WIN
#include <unistd.h>
#endif
#include "DiffDialogImpl.h"
#include "AnnotateDialogImpl.h"
#include "LogDialogImpl.h"
#include "globals.h"
#include "pixmapcache.h"
#include "colortab.h"
#include "VerifyDialog.h"
bool LogDialogImpl::s_keepSettings = false;
bool LogDialogImpl::s_showTags = false;
bool LogDialogImpl::s_showBranches = false;
LogDialogImpl::LogDialogImpl(CvsDirListView * workBench,
GuardedDir workDir,
const QIconSet &whatsThisIconSet,
QWidget* parent,
const char* name, WFlags fl )
: LogDialog( LookAndFeel::g_b0AsParent ? 0 : parent, name, fl ),
m_workBench(workBench),
m_workDir(workDir),
m_treeA(0), m_treeB(0), m_parent(parent)
{
m_pWhatsThis->setIconSet(whatsThisIconSet);
#ifdef Q_WS_MAC
m_pWhatsThis->setMaximumWidth(m_pWhatsThis->height() * 2);
#else
m_pWhatsThis->setMaximumWidth(m_pWhatsThis->height());
#endif
buttonLayout->addWidget(new QSizeGrip(this),0,Qt::AlignRight|Qt::AlignBottom);
connect(this,SIGNAL(checkInProgress(bool)),parent,SLOT(checkInProgress(bool)));
connect(this,SIGNAL(showWarning(const QString &,const QString &)),parent,SLOT(showWarning(const QString &,const QString &)));
init();
}
void LogDialogImpl::init()
{
installEventFilter(this);
if (bUseSmallIcons) setIcon( findEmbeddedPixmap( "LogTree16x16" ) );
else setIcon( findEmbeddedPixmap( "LogTree32x32" ) );
assert(m_workDir);
m_baseDir= "";
m_topModule = m_workDir->topControlledDir()->relativeName();
tags.setAutoDelete(true);
connect(m_treeZoomInButton,SIGNAL(clicked()),tree,SLOT(zoomIn()));
connect(m_treeZoomOutButton,SIGNAL(clicked()),tree,SLOT(zoomOut()));
connect(tree,SIGNAL(revisionClicked(LogTreeView::LogTreeItem *,bool)),this,SLOT(revisionSelected(LogTreeView::LogTreeItem *,bool)));
connect(tree,SIGNAL(revisionDblClicked(LogTreeView::LogTreeItem *)),this,SLOT(displayFileRevision(LogTreeView::LogTreeItem *)));
connect(list,SIGNAL(revisionClicked(LogListView::LogListItem *,bool)),this,SLOT(revisionSelected(LogListView::LogListItem *,bool)));
connect(list,SIGNAL(revisionDblClicked(LogListView::LogListItem *)),this,SLOT(displayFileRevision(LogListView::LogListItem *)));
for (int i=0; i<2; i++) {
tree->setSelectionColor (i, SELECTION_COLOR_OF_LOGDLG[i]);
list->setSelectionColor (i, SELECTION_COLOR_OF_LOGDLG[i]);
}
m_showMergeInfo = true;
CheckBoxKeepSettings->setChecked(s_keepSettings);
if (s_keepSettings) {
CheckBoxRegularTags->setChecked(s_showTags);
CheckBoxBranchTags->setChecked(s_showBranches);
}
}
/*
* Destroys the object and frees any allocated resources
*/
LogDialogImpl::~LogDialogImpl()
{
}
bool LogDialogImpl::eventFilter( QObject *o, QEvent *e ) {
if ( e->type() == QEvent::ContextMenu ) {
return TRUE; // eat event
} else {
// standard event processing
return QWidget::eventFilter( o, e );
}
}
void LogDialogImpl::parseCvsLog (QString BaseDir, QString name, QString revision, CvsBuffer *pCvsBuffer) {
// qDebug("startParsing: "+QDateTime::currentDateTime().toString("hh:mm:ss"));
m_fileName = name;
QStringList strlist;
QStringList vTags;
LogTreeView::ItemList itemList;
QString file, tag, rev, authorLocked, author, state, lines, kopt, commitid, mergepoint, filename, comment;
QDateTime date;
enum { Begin, StartFile, Tags, Admin, Revision,
Author, Branches, Comment, Finished } ParserState;
m_fileRevision = revision;
m_pCvsBuffer = pCvsBuffer;
setCaption ("CVS Log - " + name + " " + revision);
m_baseDir = BaseDir;
int files = 0;
ParserState = Begin;
QString line;
unsigned int len = (*m_pCvsBuffer).numLines();
for ( unsigned int i = outputLineOffset;i<len;i++) {
line = (*m_pCvsBuffer).textLine(i);
switch (ParserState) {
case Begin:
if (line.startsWith("Working file: ")) {
file = line.mid(14);
++files;
ParserState = StartFile;
}
break;
case StartFile:
if (line == "symbolic names:")
ParserState = Tags;
/* We'll drop through here because the log output
* doesn't always have a symbolic names section.
* This is particularly true if we have a .cvsrc file
* with the following line: "log -N"
*/
case Admin:
if (line == "----------------------------") {
ParserState = Revision;
}
break;
case Tags:
if (line[0] == '\t') {
strlist = QStringList::split (':', line);
QString rev = strlist[1].simplifyWhiteSpace();
QString tag = strlist[0].simplifyWhiteSpace();
QString branchpoint = "";
if (rev.contains (".0.")) {
/* For a revision number such as 2.10.0.6, we want:
* branchpoint = "2.10"
* rev = "2.10.6"
*/
branchpoint = QString(rev).replace (QRegExp ("\\.0\\.[0-9]+$"), "");
rev.replace (QRegExp ("\\.0\\."), ".");
} else if (rev.contains('.') == 2) {
//vendor tag
vTags.append(rev);
}
TagInfo *taginfo = new TagInfo;
taginfo->rev = rev;
taginfo->tag = tag;
taginfo->branch = rev;
taginfo->branchpoint = branchpoint;
tags.append(taginfo);
}
else ParserState = Admin;
break;
case Revision:
strlist = QStringList::split (' ', line);
rev = strlist[1];
int pos;
if ((pos=rev.findRev("\t"))>-1) {//lock info
rev.truncate(pos);
}
if ((pos=line.find("locked by: "))>-1) {
authorLocked = line.mid(pos+11,line.length()-pos-12);
} else {
authorLocked = "";
}
ParserState = Author;
break;
case Author: {
/* Extract the date, author and state subcomponents of a
* line that looks something like this:
* date: 2001/05/16 22:04:07; author: joseh; state: Exp; lines: +11 -11
*/
strlist = QStringList::split (';', line);
QString tmpVal = (QStringList::split (": ", strlist[0]))[1];
date = QDateTime::fromString(tmpVal.replace(10,1,(const char*)"T"),Qt::ISODate );
author = (QStringList::split (": ", strlist[1]))[1];
state = (QStringList::split (": ", strlist[2]))[1];
lines="";kopt="";commitid="";mergepoint="";filename="";
if (strlist.count() > 3) {
QStringList::Iterator it = strlist.at(3);
while (it != strlist.end()) {
QString tmpType = (QStringList::split (": ", *it))[0].stripWhiteSpace();
tmpVal = (QStringList::split (": ", *it))[1];
if (tmpType.find("lines") == 0) lines = tmpVal;
else if (tmpType.find("kopt") == 0) kopt = tmpVal;
else if (tmpType.find("commitid") == 0) commitid = tmpVal;
else if (tmpType.find("mergepoint") == 0) mergepoint = tmpVal;
else if (tmpType.find("filename") == 0) filename = tmpVal;
++it;
}
}
comment = "";
ParserState = Branches;
break;
}
case Branches:
if (qstrncmp(line, "branches:", 9) != 0) {
comment = line;
ParserState = Comment;
}
break;
case Comment:
if (line == "----------------------------") {
ParserState = Revision;
} else if (line == "=============================================================================") {
ParserState = Begin;
}
if (ParserState == Comment) {// still in message
comment += QString("\n") + QString(line);
} else {
// Create tagcomment
QString tagcomment, BranchTagList, RegularTagList, branch, branchName, releaseTag;
branch = QString(rev).replace (QRegExp ("\\.[0-9]+$"), "");
//check for vendor branch
bool found = FALSE;
QPtrListIterator<TagInfo> rtagIt(tags);
--rtagIt;// set to invalid position
QStringList::Iterator it0;
for ( it0 = vTags.begin(); it0 != vTags.end(); ++it0 ) {
if (branch == *it0) {
rtagIt.toLast();
while (rtagIt.current()) {
if (rtagIt.current()->rev == rev) {
found = TRUE;
break;
}
--rtagIt;
}
}
if (found) break;
}
// Build tagcomment and taglist:
// tagcomment contains Tags, Branchpoints and 'On Branch's
// taglist contains tags (without prefix) and Branchpoints
QPtrListIterator<TagInfo> it(tags);
for (; it.current(); ++it) {
if (rev == it.current()->rev) {
if (it != rtagIt) {// regular tag
tagcomment += "\nTag: " + it.current()->tag;
RegularTagList += "\nTag: " + it.current()->tag;
} else {// release tag
tagcomment += "\nRelease-Tag: " + it.current()->tag;
RegularTagList += "\nRelease-Tag: " + it.current()->tag;
}
}
if (branch == it.current()->branch) {
branchName = it.current()->tag;
}
if (rev == it.current()->branchpoint) {
// branch origin tag
tagcomment += "\nBranch-Point: " + it.current()->tag;
BranchTagList += "\nBranch-Point: " + it.current()->tag;
} else if (branch == it.current()->rev) {
if (rtagIt.current()) {
// vendor tag
// Note that cvs reports the vendor tag at the end of the tag list
tagcomment += "\nVendor-Tag: " + it.current()->tag;
BranchTagList += "\nVendor-Tag: " + it.current()->tag;
} else {
// branch tag
tagcomment += "\nBranch-Tip: " + it.current()->tag;
BranchTagList += "\nBranch-Tip: " + it.current()->tag;
}
// Since branch tags are floating tags, will associate
// the tag with the revision at the tip of the branch.
// Note that cvs always reports the latest revision first.
it.current()->rev = rev;
}
}
// remove leading '\n'
if (!tagcomment.isEmpty())
tagcomment.remove(0, 1);
if (!BranchTagList.isEmpty())
BranchTagList.remove(0, 1);
if (!RegularTagList.isEmpty())
RegularTagList.remove(0, 1);
if (branchName.isEmpty()) branchName = "MAIN";
list->addRevision(file, rev, branchName, author, comment, date);
itemList.append(new LogTreeView::LogTreeItem(file, rev, authorLocked,
date.toString(LookAndFeel::g_dateTimeFormat),
author, state, lines, kopt, commitid, mergepoint,
filename, comment, branchName, tagcomment,
BranchTagList, RegularTagList)
);
}
if (ParserState == Begin) {
tree->addRevisionList(itemList);
tree->nextFile();
list->nextFile();
tags.clear();
vTags.clear();
itemList.clear();
}
default :
break;
}
}
tree->recomputeCellSizes();
layout()->activate();
if (files > 1) tree->scrollDown();
// qDebug("finishParsing: "+QDateTime::currentDateTime().toString("hh:mm:ss"));
};
/*
* protected slot
*/
void LogDialogImpl::annotateClicked() {
QString cvsRoot = "annotate -r " + m_selectionA;
QString fileA = m_fileA;
QString file = masqWs(fileA.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS));
callInteractive( m_topModule, m_baseDir, cvsRoot,
file, CVS_ANNOTATE_CMD,
ExtApps::g_cvsRsh.path, //additional options of cvsRsh not supported yet
true);
}
void LogDialogImpl::keepSettingsToggled(bool state) {
s_keepSettings = state;
}
void LogDialogImpl::showTagsToggled(bool state) {
s_showTags = state;
}
void LogDialogImpl::showBranchesToggled(bool state) {
s_showBranches = state;
}
void LogDialogImpl::displayFileRevision (LogTreeView::LogTreeItem * item) {
runDisplayFileRevision(item->rev,item->file);
}
void LogDialogImpl::displayFileRevision (LogListView::LogListItem * item) {
runDisplayFileRevision(item->rev,item->file);
}
void LogDialogImpl::runDisplayFileRevision( QString &rev, QString &fileName) {
m_tmpDiffFileNameA = createTempFile("-" + rev + "-" + fileName);
if (!m_tmpDiffFileNameA.isEmpty()) {
QString tmpFile = fileName;
QString cvsRoot = "-Q update -p -r " + rev + " " + masqWs(tmpFile.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS)) + " > " + m_tmpDiffFileNameA;
QString file = "";
callInteractive( m_topModule, m_baseDir, cvsRoot,
file, CVS_EDIT_REVISION_CMD,
ExtApps::g_cvsRsh.path, //additional options of cvsRsh not supported yet
true);
}
}
/*
* protected slot
*/
void LogDialogImpl::diffClicked() {
m_captionA = m_selectionA;
m_captionB = m_selectionB;
diff(m_selectionA,m_selectionB,m_fileA,m_fileB);
}
void LogDialogImpl::diff(QString revA, QString revB, QString fileA, QString fileB) {
m_sandbox = QString::null;
m_fileName = fileA;
if (bUSEEXTERNALDIFFFORSIDEBYSIDE) {
QString cvsRoot = CvsOptions::cmprStr() + " -Q update ";
m_tmpDiffFileNameB = createTempFile("-" + revB + "-" + fileB);
if (!m_tmpDiffFileNameB.isEmpty()) {
if (!revA.isEmpty()) {
m_tmpDiffFileNameA = createTempFile("-" + revA + "-" + fileA);
if (!m_tmpDiffFileNameA.isEmpty()) {
if (bKeywordSuppression) cvsRoot += "-kk ";
cvsRoot += "-p -r " + revA + " " + masqWs(fileA.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS)) + " > " + m_tmpDiffFileNameA
+ " && cvs " + CvsOptions::cmprStr() + " -Q update ";
if (bKeywordSuppression) cvsRoot += "-kk ";
m_sandbox = m_baseDir + "/" + fileA;
} else return;
} else m_tmpDiffFileNameA = m_baseDir + "/" + fileA;
// and now, the names of used files are stored in *NameA and *NameB unless we make a
// diff between two revisions or between sandbox and one revision
// but we use m_sandbox for 3way diff...
cvsRoot += "-p -r " + revB + " " + masqWs(fileB.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS)) + " > " + m_tmpDiffFileNameB;
if (revA.isEmpty()) {//diff against local rep, exchange diff file order
QString tmp = m_tmpDiffFileNameA;
m_tmpDiffFileNameA = m_tmpDiffFileNameB;
m_tmpDiffFileNameB = tmp;
}
QString es = "";
callInteractive( m_topModule, m_baseDir, cvsRoot,
es, CVS_DIFF_EXT_CMD,
ExtApps::g_cvsRsh.path, //additional options of cvsRsh not supported yet
true);
}
}
else {
QString hlp;
QString cvsRoot = CvsOptions::cmprStr() + " -Q diff -N ";
if (bDiffIgnoreWhiteSpace) cvsRoot += "-b -B ";
if (!revA.isEmpty()) if (bKeywordSuppression) cvsRoot += "-kk ";
cvsRoot += "--side-by-side -t -W "+hlp.setNum(SIDEWIDTH);
if (!revA.isEmpty()) cvsRoot += " -r " + revA;
cvsRoot += " -r " + revB;
QString file = masqWs(fileA.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS));
callInteractive( m_topModule, m_baseDir, cvsRoot,
file, CVS_DIFF_SBS_CMD,
ExtApps::g_cvsRsh.path, //additional options of cvsRsh not supported yet
true);
}
}
void LogDialogImpl::diffAClicked() {
m_captionA = m_selectionA;
if (!m_fileRevision.isEmpty()) m_captionB = m_fileRevision + " " + tr("(working copy)");
else m_captionB = tr("of working copy");
diff(QString::null,m_selectionA,m_fileA,m_fileA);
}
void LogDialogImpl::diffBClicked() {
m_captionA = m_selectionB;
if (!m_fileRevision.isEmpty()) m_captionB = m_fileRevision + " " + tr("(working copy)");
else m_captionB = tr("of working copy");
diff(QString::null,m_selectionB,m_fileB,m_fileB);
}
void LogDialogImpl::diffConsoleClicked() {
QString cvsRoot = CvsOptions::cmprStr() + " -f -Q diff -N ";
if (bDiffIgnoreWhiteSpace) cvsRoot += "-b -B ";
if (bKeywordSuppression) cvsRoot += "-kk ";
if (!m_selectionA.isEmpty()) cvsRoot += " -r " + m_selectionA;
if (!m_selectionB.isEmpty()) cvsRoot += " -r " + m_selectionB;
QString fileA = m_fileA;
QString file = masqWs(fileA.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS));
callInteractive( m_topModule, m_baseDir, cvsRoot,
file, CVS_DIFF_CMD,
ExtApps::g_cvsRsh.path, //additional options of cvsRsh not supported yet
true);
}
void LogDialogImpl::diffConsoleAClicked() {
if (m_selectionA.isEmpty()) return;
diffConsoleSandBox(m_selectionA, m_fileA);
}
void LogDialogImpl::diffConsoleBClicked() {
if (m_selectionB.isEmpty()) return;
diffConsoleSandBox(m_selectionB, m_fileB);
}
void LogDialogImpl::diffConsoleSandBox(const QString &rev, const QString &f) {
QString cvsRoot = CvsOptions::cmprStr() + " -f -Q diff -N ";
if (bDiffIgnoreWhiteSpace) cvsRoot += "-b -B ";
if (bKeywordSuppression) cvsRoot += "-kk ";
cvsRoot += " -r " + rev;
QString tmpFile = f;
QString file = masqWs(tmpFile.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS));
callInteractive( m_topModule, m_baseDir, cvsRoot,
file, CVS_DIFF_CMD,
ExtApps::g_cvsRsh.path, //additional options of cvsRsh not supported yet
true);
}
void LogDialogImpl::createPatchClicked() {
bool ok;
QString dir = m_baseDir + "/" + m_fileA + "-diff-" + m_selectionA + "-" + m_selectionB;
QString patchFile = QInputDialog::getText(tr("Enter file name (default:") + " " + dir + ")",
"Enter a file name for the patch file", QLineEdit::Normal,
dir, &ok, this, "Patch file dialog");
if (!ok) return;
QFile f(patchFile);
if (f.exists()) {
if (QMessageBox::warning (this, tr("Warning"),
tr("The filename: ") + patchFile + tr(" already exists.\nOverwrite it?"),
QMessageBox::Yes , QMessageBox::No) != QMessageBox::Yes) return;
f.remove();
}
QString hlp;
QString cvsRoot = CvsOptions::cmprStr() + " -Q diff -N ";
if (bDiffIgnoreWhiteSpace) cvsRoot += "-b -B ";
if (bKeywordSuppression) cvsRoot += "-kk ";
if (CvsOptions::g_bUnifiedDiffOutput) cvsRoot += "-u ";
if (!m_selectionA.isEmpty()) cvsRoot += " -r " + m_selectionA;
if (!m_selectionB.isEmpty()) cvsRoot += " -r " + m_selectionB;
QString fileA = m_fileA;
cvsRoot += " " + masqWs(fileA.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS)) + " > " + patchFile;
QString file = "";
callInteractive( m_topModule, m_baseDir, cvsRoot,
file, CVS_NOT_INTERACTIVE_CMD,
ExtApps::g_cvsRsh.path, //additional options of cvsRsh not supported yet
true);
}
void LogDialogImpl::mergeClicked() {
QString tmp;
if( (! m_selectionA.isEmpty()) && (! m_selectionB.isEmpty()) ) {
if( m_showMergeInfo) {
//create dialog
VerifyDialog *dlg = new VerifyDialog(this);
dlg->setCaption(tr("Information"));
dlg->TextLabel->setText(tr("You are about to merge differences between revisions:\r\n "+
m_selectionA + " and "+m_selectionB+
"\ninto:\r\n "+
m_fileA + " " + m_fileRevision));
dlg->adjustSize();
if(!dlg->exec()) {
delete dlg;
return;
}
m_showMergeInfo = dlg->VerifyCheckBox->isChecked();
delete dlg;
}
QString command = "";
if (!bRWPermission) command += "-r ";
command += CvsOptions::cmprStr() + " update ";
if (bKeywordSuppression) command += "-kk ";
command += "-j " + m_selectionA;
command += " -j " + m_selectionB;
QString fileA = m_fileA;
QString file = masqWs(fileA.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS));
callInteractive( m_topModule, m_baseDir, command,
file, CVS_MERGE_REV_INTO_CMD,
ExtApps::g_cvsRsh.path, //additional options of cvsRsh not supported yet
true);
}
}
/*
* protected slot
*/
void LogDialogImpl::revisionSelected(LogTreeView::LogTreeItem * item,bool rmb) {
if (rmb) {
m_treeB = item->tree;
m_fileB = item->file;
FileBBox->setText(item->file);
RevBBox->setText (m_selectionB = item->rev);
BranchBBox->setText(item->branch);
AuthorDateBBox->setText(item->author+" "+item->date);
CommentBBox->setText(item->comment);
} else {
m_treeA = item->tree;
m_fileA = item->file;
FileABox->setText(item->file);
RevABox->setText (m_selectionA = item->rev);
BranchABox->setText(item->branch);
AuthorDateABox->setText(item->author+" "+item->date);
CommentABox->setText(item->comment);
}
setButtonsAndSelectedPair( m_treeA, m_treeB );
}
/*
* protected slot
*/
void LogDialogImpl::revisionSelected(LogListView::LogListItem * item,bool rmb) {
if (rmb) {
m_treeB = item->tree;
m_fileB = item->file;
FileBBox->setText(item->file);
RevBBox->setText (m_selectionB = item->rev);
BranchBBox->setText(item->branch);
AuthorDateBBox->setText(item->author+" "+item->date.toString(LookAndFeel::g_dateTimeFormat));
CommentBBox->setText(item->comment);
} else {
m_treeA = item->tree;
m_fileA = item->file;
FileABox->setText(item->file);
RevABox->setText (m_selectionA = item->rev);
BranchABox->setText(item->branch);
AuthorDateABox->setText(item->author+" "+item->date.toString(LookAndFeel::g_dateTimeFormat));
CommentABox->setText(item->comment);
}
setButtonsAndSelectedPair( m_treeA, m_treeB );
}
void LogDialogImpl::setButtonsAndSelectedPair(int treeA, int treeB) {
/* Enable or disable the view diffs button depending
* on whether there are two different revisions
* currently selected.
*/
bool sameTree = (treeA == treeB);
bool sameRev = (m_selectionA == m_selectionB);
bool bothRevsSet = (!m_selectionA.isNull() && !m_selectionB.isNull());
buttonDiffs->setEnabled( bool ( bothRevsSet &&
((sameTree && !sameRev) ||
(!sameTree && bUSEEXTERNALDIFFFORSIDEBYSIDE)) ));
m_ButtonDiffConsole->setEnabled( bool (sameTree &&
!m_selectionA.isNull() &&
!m_selectionB.isNull() &&
m_selectionA != m_selectionB));
m_ButtonPatch->setEnabled( bool (sameTree &&
!m_selectionA.isNull() &&
!m_selectionB.isNull() &&
m_selectionA != m_selectionB));
/* Enable or disable the annotation button depending
* on whether there is a revision currently selected.
*/
buttonAnnotate->setEnabled (bool (!m_selectionA.isNull()));
/* Enable or disable the merge button depending
* on whether there are two revisions currently selected.
*/
buttonMerge->setEnabled (bool (sameTree &&
!m_selectionA.isNull() &&
!m_selectionB.isNull() &&
m_selectionA != m_selectionB));
/* Enable or disable the rev->sandbox buttons depending
* on whether there is a revision currently selected.
*/
m_buttonDiffA->setEnabled(bool (!m_selectionA.isNull()) );
m_buttonDiffB->setEnabled(bool (!m_selectionB.isNull()) );
m_pDiffConsoleA->setEnabled(bool (!m_selectionA.isNull()) );
m_pDiffConsoleB->setEnabled(bool (!m_selectionB.isNull()) );
CommentABox->setEnabled(bool (!m_selectionA.isNull()) );
CommentBBox->setEnabled(bool (!m_selectionB.isNull()) );
tree->setSelectedPair(treeA, treeB, m_selectionA, m_selectionB);
list->setSelectedPair(treeA, treeB, m_selectionA, m_selectionB);
}
void LogDialogImpl::setEnabled(bool state) {
static bool diff = true;
static bool diffConsole = true;
static bool annotate = true;
static bool merge = true;
static bool patch = true;
LogTabWidget->setEnabled(state);
RevFrame->setEnabled(state);
m_pWhatsThis->setEnabled(state);
buttonDone->setEnabled(state);
if (!state) {//preserve state
diff = buttonDiffs->isEnabled();
diffConsole = m_ButtonDiffConsole->isEnabled();
annotate = buttonAnnotate->isEnabled();
merge = buttonMerge->isEnabled();
patch = m_ButtonPatch->isEnabled();
} else {
buttonDiffs->setEnabled(diff);
m_ButtonDiffConsole->setEnabled(diffConsole);
buttonAnnotate->setEnabled(annotate);
buttonMerge->setEnabled(merge);
m_ButtonPatch->setEnabled(patch);
}
}
void LogDialogImpl::cvsCallStarted() {
setEnabled(FALSE);
QApplication::setOverrideCursor(Qt::waitCursor);
}
void LogDialogImpl::cvsCallFinished() {
QApplication::restoreOverrideCursor();
setEnabled(TRUE);
}
void LogDialogImpl::afterCall( int cmd, CvsBuffer * buf, bool failed) {
cvsCallFinished();
if (failed) return;
switch( cmd) {
case CVS_DIFF_CMD: {
break;
}
case CVS_DIFF_SBS_CMD: {
DiffDialogImpl *l = new DiffDialogImpl( *(m_pWhatsThis->iconSet()),
m_parent, "DiffDlg", LookAndFeel::g_nonModalF | WDestructiveClose);
l->parseCvsDiff(m_pCvsBuffer, m_fileName, m_captionA, m_captionB);
l->show();
break;
}
case CVS_DIFF_EXT_CMD: {
QString diffPrg = "\"" + ExtApps::g_diffProg.path + "\" ";
QStringList nameList;
QString tmp = m_tmpDiffFileNameA;
nameList.append(tmp.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS));
tmp = m_tmpDiffFileNameB;
nameList.append(tmp.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS));
if (m_sandbox.isEmpty()) nameList.append("");
else {
tmp = m_sandbox;
nameList.append(tmp.replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS));
}
QString options = ExtApps::g_diffProg.options;
if (masqedFilenamesForPlaceholders(options, nameList)) diffPrg += options;
else {// no options, we add filenames assuming the user want it so ;-)
diffPrg += masqWs(m_tmpDiffFileNameA.latin1()) + " ";
diffPrg += masqWs(m_tmpDiffFileNameB.latin1()) + " ";
if (!m_sandbox.isEmpty()) {
diffPrg += masqWs(m_sandbox.latin1());
}
}
runExternal(diffPrg);
break;
}
case CVS_ANNOTATE_CMD: {
AnnotateDialogImpl *pAnnotateDialogImpl = new AnnotateDialogImpl( *(m_pWhatsThis->iconSet()),
m_parent, "AnnotateDlg",
LookAndFeel::g_nonModalF | WDestructiveClose);
pAnnotateDialogImpl->parseCvsAnnotate (m_fileA, m_pCvsBuffer, m_selectionA);
pAnnotateDialogImpl->show();
break;
}
case CVS_EDIT_REVISION_CMD: {
QFile tmpFile(m_tmpDiffFileNameA);
setPermission(tmpFile, READABLE);//don't think you could change the file
emit editFile(m_tmpDiffFileNameA);
break;
}
case CVS_MERGE_REV_INTO_CMD: {
if (m_workBench->validate(m_workDir)) {
m_workDir->parseCallResult( buf, cmd);
emit checkInProgress(true);
m_workDir->activateItem(false);
emit checkInProgress(false);
}
break;
}
}
}
void LogDialogImpl::enterWhatsThisMode()
{
QWhatsThis::enterWhatsThisMode();
}
syntax highlighted by Code2HTML, v. 0.9.1