/****************************************************************************
**
** Copyright (C) 2003-2006 Frank Hemer <frank@hemer.org>,
** Tilo Riemer <riemer@crossvc.com>
**
**
**----------------------------------------------------------------------------
**
**----------------------------------------------------------------------------
**
** 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 <qapplication.h>
#include <qtextcodec.h>
#include <qinputdialog.h>
#include <qfile.h>
#include <qcheckbox.h>
#include <qtextstream.h>
#include <qfiledialog.h>
#include <qlabel.h>
#include <qstringlist.h>
#include <qregexp.h>
#include <qprocess.h>
#include <assert.h>
#ifndef Q_WS_WIN
#include <unistd.h>
#else
#include <io.h>
#endif
#include "directory.h"
#include "cvscontrol.h"
#include "PixmapTimer.h"
#include "colortab.h"
#include "cvslistview.h"
#include "noncvslistview.h"
#include "cvsignorelistview.h"
#include "cvsconfig.h"
#include "cvsconfig_old.h"
#include "login.h"
#include "LinCVSLog.h"
#include "TextEncoder.h"
//----------------------------------------------------------------------------
const bool CvsControl::OVERRIDE = TRUE;
//----------------------------------------------------------------------------
CvsControl::CvsControl( QString startUpDir)
: CMainWindow(0, "CrossVC main window", WType_TopLevel | WDestructiveClose)
{
conf = 0;
KILLED = false;
createTmpDir();
sshAgentIsRunning = false;
sshAgentStarted = false;
m_pInteractiveCmdThread = NULL;
m_pCvsBuffer = new CvsBuffer();
readSettings();
Debug::g_pLog = new CLinCVSLog();
if (Debug::g_pLog) {
QString msg = "\n";
msg += LC_APPNAME;
msg += " version: " + getVersion() + "\n";
#ifdef Q_WS_WIN
msg += "for Windows\n";
#else
#ifdef Q_WS_MAC
msg += "for Mac OS X\n";
#else
msg += "for Unix\n";
#endif
#endif
msg += "Compile Time: "+getCompileTime()+"\n";
msg += "LogLevel: "+QString::number(Debug::g_logLevel)+"\n";
Debug::g_pLog->log(Debug::LL_INFO, msg);
}
//we have set the application icon --> now we try to load icons from disk
loadPixmapsFromDisk(iconDir);
globalListViewsEnabled = true;
m_pFetchTagDir = NULL;
m_pLastCvsCallDir = NULL;
globalStopAction = false;
m_chainedCommand = false;
m_interactiveCmdThreadIsRunning = false;
/* initialize CommandInterface */
initCommandInterface(this);
if (bStartedInDir) {
m_tmpStartUpDir = startUpDir;
}
/* initialize Monitoring */
initMonitoring();
if (DirWatch::b_isActive) {
//No better way here since globals can't handle qt messages
connect (getDirConnector(), SIGNAL(eventReceived()),this,SLOT(dirConnectorDataNotify()));
}
}
//----------------------------------------------------------------------------
CvsControl::~CvsControl()
{
releaseMonitoring();
//remove all tmp files from external diff
QDir d(tmpDir);
d.setFilter( QDir::Files | QDir::NoSymLinks );
const QStringList list = d.entryList();
unsigned int i;
for (i = 0; i < list.count(); i++) {
if ( (WINVERSION && (list[i].find("fn") >= 0) ) || ( (!WINVERSION) && (list[i].find("tmp.") == 0)) ) {
QFile tmpFile(tmpDir + "/" + list[i]);
setPermission(tmpFile,READABLE | WRITEABLE);
tmpFile.remove();
}
}
killSshAgent();
delete Debug::g_pLog;
Debug::g_pLog = 0; //prevents logging after deleting log object
}
//----------------------------------------------------------------------------
void CvsControl::readSettings() {
delete conf;
conf = 0; //paranoia
QString tmpCvsRsh = getenv("CVS_RSH");
QString tmpCvsPassPath = getenv("CVS_PASSFILE");
QString tmpCvsWrappers = getenv("CVSWRAPPERS");
if (tmpCvsPassPath.isEmpty()) tmpCvsPassPath = QDir::homeDirPath() + "/.cvspass";
conf = new CvsConfig;
// check for old lincvs config
if (Misc::g_bVeryFirstStart) {
// try to load old config --> creation of object reads old config
CvsConfigOld oldConf;
}
Misc::g_bVeryFirstStart = false;
expurgateProjectSettings();
if (ExtApps::g_cvsRsh.path.isEmpty() && (!tmpCvsRsh.isEmpty())) {
ExtApps::g_cvsRsh.path = tmpCvsRsh; //use CVS_RSH
}
if (CVSPASSPATH.isEmpty() && (!tmpCvsPassPath.isEmpty())) {
CVSPASSPATH = tmpCvsPassPath;
}
if (BINARYFILESPECLIST.isEmpty() && (!tmpCvsWrappers.isEmpty())) {
//probably read file pointed to by CVSWRAPPERS, no docu available
// BINARYFILESPECLIST = tmpCvsWrappers;
}
}
//----------------------------------------------------------------------------
void CvsControl::writeSettings() {
expurgateProjectSettings();
writeSetup();
writeCfg();
delete conf;
conf = 0;
}
//----------------------------------------------------------------------------
void CvsControl::expurgateProjectSettings() {
unsigned int i;
unsigned int j;
QString workdir;
QStringList projectNameList;
QStringList topLevelProjectNameList;
//remove unreferenced project settings
projectSettings->getTopLevelProjects(topLevelProjectNameList);
projectSettings->getProjects(projectNameList);
QStringList tmpProjectNameList = projectNameList;
QString joined;
for (i=0; i<topLevelProjectNameList.count(); ++i) {//remove unreferenced entries from subProject list
QStringList subProjects;
if (projectSettings->getSubProjects(topLevelProjectNameList[i],subProjects)) {
for (j=0; j<subProjects.count(); ++j) {
QStringList::Iterator it = projectNameList.find(subProjects[j]);
if (it == projectNameList.end()) {
projectSettings->removeSubProject(topLevelProjectNameList[i],subProjects[j]);
if (Debug::g_pLog) {
Debug::g_pLog->log(Debug::LL_INFO,"removing unreferenced sub-project from sub-project list: "+subProjects[j]);
}
} else {
joined += "^e"+subProjects[j].replace(QRegExp("\\^"),"^0");
}
}
}
tmpProjectNameList.remove(tmpProjectNameList.find(topLevelProjectNameList[i]));
}
QStringList allSubProjectsList = QStringList::split("^e",joined);
QStringList::Iterator it;
for (it = allSubProjectsList.begin(); it != allSubProjectsList.end(); ++it) {
(*it).replace(QRegExp("\\^0"),"^");
}
for (i=0; i<tmpProjectNameList.count(); ++i) {//remove unreferenced subProjects
QStringList::Iterator it = allSubProjectsList.find(tmpProjectNameList[i]);
if (it == allSubProjectsList.end()) {
projectSettings->removeProject(tmpProjectNameList[i]);
if (Debug::g_pLog) Debug::g_pLog->log(Debug::LL_INFO,"removing unreferenced sub-project: "+tmpProjectNameList[i]);
}
}
}
//----------------------------------------------------------------------------
void CvsControl::setSettings() {
if (!DirWatch::b_useDirWatch) releaseMonitoring();
Debug::g_pLog->log(Debug::LL_THE_OLD_MAN_AND_THE_SEA, "LogLevel set to: "+QString::number(Debug::g_logLevel));
}
//----------------------------------------------------------------------------
void CvsControl::startInSingleDir() {//startup option, only called by lincvs.cpp
addProject(m_tmpStartUpDir,true);
}
//----------------------------------------------------------------------------
void CvsControl::initialDirScanning()//startup option, only called by lincvs.cpp
{
QStringList projectNameList;
projectSettings->getTopLevelProjects(projectNameList);
QStringList removeList;
unsigned int i;
for(i = 0; i < projectNameList.count(); i++) {
QString fullName;
projectSettings->get(projectNameList[i],WORKDIR,fullName);
if (addProject(fullName)) {
applyProjectSettings(projectNameList[i]);
} else {//globalStopAction!
setStatusText( tr("Scanning aborted") );
if (showYesNoQuestion( tr("Interrupted"),
tr("Remove project from workbench:")+"\n"+
fullName+"?" ) ) {
removeList.append(projectNameList[i]);
}
}
}
if (!removeList.isEmpty()) {
for(i = 0; i < removeList.count(); ++i) {
QString fullName;
projectSettings->get(removeList[i],WORKDIR,fullName);
DirBase * dir = m_pWorkBenchTree->find(fullName);
if (dir) delete dir;
projectSettings->removeProject(removeList[i]);
}
}
globalStopAction = false;
initDone();
}
//----------------------------------------------------------------------------
bool CvsControl::addNewProject(const QString fileName, bool expand) {
QStringList projectNameList;
projectSettings->getProjects(projectNameList);
unsigned int i;
for(i=0; i < projectNameList.count(); i++) {
QString fullName;
projectSettings->get(projectNameList[i],WORKDIR,fullName);
if ( fileName.mid(fileName.findRev("/")+1) == projectNameList[i]) {
showWarning(tr("Warning")+", "+tr("adding aborted"),
tr("This project is already in the workbench:\n")
+projectNameList[i]
+"\nat: "+fullName);
setStatusText( tr("Adding aborted"), 4000 );
return FALSE;
}
}
setStatusText("");
Directory * item = Directory::createInstance (fileName);
projectSettings->set(item->shortName(),WORKDIR,item->fullName());
if(expand) {
item->setOpen(true);
}
if (globalStopAction) {
setStatusText(tr("Adding aborted"));
globalStopAction = false;
return FALSE;
} else {
m_pWorkBenchTree->setSelected(item,TRUE);
slot_checkStatusOfTree(item);
return TRUE;
}
}
//----------------------------------------------------------------------------
bool CvsControl::addProject(const char * fileName, bool expand)
{
bool addNewProject = false;
QString fn = fileName;
if(fn.isEmpty()){//popup dialog
addNewProject = true;
expand = true;
/* Using the Qt standard file dialog preserves the look and feel
* of the application across platforms.
*/
QString defaultDir = QString::null;
DirBase * dir;
if ( (dir = getSelectedDir(false)) ) {
defaultDir = dir->fullName();
defaultDir = defaultDir.left(defaultDir.findRev("/"));
}
blockGUI(false);
fn = QFileDialog::getExistingDirectory (defaultDir, this, NULL,
tr("Add directory to workbench"), true);
blockGUI(true);
// Remove trailing "/" from the path.
fn.replace (QRegExp ("/+$"), "");
#ifdef Q_WS_WIN
fn.replace (QRegExp ("\\\\"), "/");
#endif
}
if ( !fn.isEmpty() ) {
if (addNewProject) {
QStringList projectNameList;
projectSettings->getProjects(projectNameList);
unsigned int i;
for(i=0; i < projectNameList.count(); i++) {
QString fullName;
projectSettings->get(projectNameList[i],WORKDIR,fullName);
if ( fn.mid(fn.findRev("/")+1) == projectNameList[i]) {
showWarning(tr("Warning")+", "+tr("adding aborted"),
tr("This project is already in workbench:\n")
+projectNameList[i]
+"\nat: "+fullName);
setStatusText( tr("Adding aborted"), 4000 );
return FALSE;
}
}
}
setStatusText("");
Directory * item = Directory::createInstance (fn);
if(addNewProject){
projectSettings->set(item->shortName(),WORKDIR,item->fullName());
}
if(expand) {
item->setOpen(true);
}
if (globalStopAction) {
setStatusText(tr("Adding aborted"));
globalStopAction = false;
return FALSE;
} else {
if (!item->isDisabled()) {
m_pWorkBenchTree->setSelected(item,TRUE);
slot_checkStatusOfTree(item);
}
return TRUE;
}
}
else setStatusText(tr("Adding aborted"));
return FALSE;
}
//----------------------------------------------------------------------------
void CvsControl::slot_addCheckedOutProject(QString path,QString name,int sshAccess) {
Directory * myChild = (Directory*)(m_pWorkBenchTree->firstChild());
while( myChild) {
if (myChild->shortName() == name) {
showWarning( tr("Warning")+", "+tr("can't add to workbench"),
tr("A project with equal name is already in workbench:")+"\n"+
myChild->shortName());
return;
}
myChild = (Directory*)(myChild->nextSibling());
}
bool res = showYesNoQuestion( tr("Checkout Info"),
tr("Add this project to workbench:")+"\n"+
name+"?" );
if (res) {
Directory * item = Directory::createInstance (path+"/"+name);
assert(item);
item->setAllToUpToDate();
//write project settings
QString topProjectDir = item->shortName();
projectSettings->set(item->shortName(),WORKDIR,item->fullName());
projectSettings->set(topProjectDir,SSHACCESS,sshAccess);
//select the dir
m_pWorkBenchTree->setSelected(item,TRUE);
//open the dir
item->setOpen(true);
if (globalStopAction) globalStopAction = FALSE;
}
}
//----------------------------------------------------------------------------
void CvsControl::slot_requestDirectorySuicide(const QVariant &name) {
QString dirName = name.toString();
m_DirsToKill.append(dirName);
CExtTimer::singleShot(0,this,SLOT(slot_execDirectorySuicide()) );
}
//----------------------------------------------------------------------------
void CvsControl::slot_execDirectorySuicide() {
if (!m_DirsToKill.isEmpty()) {
QString name = m_DirsToKill.first();
m_DirsToKill.pop_front();
Directory * dir = static_cast<Directory *>(m_pWorkBenchTree->find(name));
if (dir) {
Directory * parentDir = dir->parent();
if (parentDir) parentDir->removeChild(dir);
}
}
}
//----------------------------------------------------------------------------
void CvsControl::slot_removeProjectSlot(DirBase * dir)
{
if (!dir) {
dir = m_pWorkBenchTree->selectedItem();
}
if (!dir) {
showWarning(tr("Warning"), tr("There is no directory selected") );
return;
}
if (dir != dir->topDir()) {
showInfo( tr("Information"),
tr("This Directory is not a top level dir.") );
return;
}
QString topModule = dir->shortName();
projectSettings->removeProject(topModule);
delete dir;
Directory * nextDir = static_cast <Directory *> (m_pWorkBenchTree->selectCurrentItem ());
if (nextDir) {
nextDir->activateItem(FALSE);
}
}
/*---------------------------------------------------------------------------*/
/*!
\fn void CvsControl::disableProjectSlot(void)
\brief Disable a dir at top level form workbench.
Dir is still listed but not further updated and scanned until enabled
again. Entry is inserted in file list in cfg file section DISABLED.
<BR><HR>*/
/*---------------------------------------------------------------------------*/
void CvsControl::disableProjectSlot(void) //only called from lincvs.cpp
{
Directory * dir;
if (!(dir = getSelectedDir())) {
return;
}
bool blocked = isGuiBlocked();
if (!blocked) blockGUI(true);
QString topCvsModule = dir->topControlledDir()->relativeName();
QString dirname = dir->fullName();
QStringList disabled;
projectSettings->get(topCvsModule,DISABLED,disabled);
disabled.append(dirname);
projectSettings->set(topCvsModule,DISABLED,disabled);
static_cast<Directory *>(dir->topControlledDir())->updateDisabledList(disabled);
Directory *hlp = dir->parent();
if (hlp) {
hlp->reloadChild(dirname);
dir = static_cast<Directory *>(m_pWorkBenchTree->find( dirname));
m_pWorkBenchTree->setSelected( dir, TRUE );
slot_checkStatusOfTree(dir);
}
else {
delete dir;
addProject(dirname.latin1());
applyProjectSettings(topCvsModule);
dir = static_cast<Directory *>(m_pWorkBenchTree->find( dirname));
m_pWorkBenchTree->setSelected( dir, TRUE );
}
if (!blocked) blockGUI(false);
}
/*---------------------------------------------------------------------------*/
/*!
\fn void CvsControl::enableProjectSlot()
\brief Reread project after reenable.
<BR><HR>*/
/*---------------------------------------------------------------------------*/
void CvsControl::enableProjectSlot() //only called from lincvs.cpp
{
Directory * dir;
if (!(dir = getSelectedDir())) {
return;
}
bool blocked = isGuiBlocked();
if (!blocked) blockGUI(true); // takes some time on huge dirs
QString topCvsModule = dir->topControlledDir()->relativeName();
QString dirname = dir->fullName();
QStringList disabled;
projectSettings->get(topCvsModule,DISABLED,disabled);
disabled.remove(dirname);
projectSettings->set(topCvsModule,DISABLED,disabled);
static_cast<Directory *>(dir->topControlledDir())->updateDisabledList(disabled);
Directory * hlp = dir->parent();
if (hlp) {
dir = static_cast<Directory *>(hlp->reloadChild(dirname));
if (dir == dir->topControlledDir()) applyProjectSettings(topCvsModule);
if (!dir->isDisabled()) {
slot_checkStatusOfTree(dir);
}
}
else {
delete dir;
addProject(dirname.latin1());// calls slot_checkStatusOfTree()
dir = static_cast<Directory *>(m_pWorkBenchTree->find( dirname));
applyProjectSettings(topCvsModule);
}
m_pWorkBenchTree->setSelected(dir,TRUE);
dir->activateItem(FALSE);
if (!blocked) blockGUI(false);
}
/*---------------------------------------------------------------------------*/
void CvsControl::disableOthers()
{
Directory * dir;
if (!(dir = getSelectedDir())) {
return;
}
bool blocked = isGuiBlocked();
if (!blocked) blockGUI(true);
QStringList disabled;
QStringList projectList;
Directory * tmpDir = dir;
Directory * parent = NULL;
while ( (parent = tmpDir->parent() ) ) {
Directory * child = parent->firstChild();
while (child) {
if (child != tmpDir) {
disabled.append(child->fullName());
}
child = child->nextSibling();
}
if (parent == parent->topControlledDir()) {
QString topCvsModule = parent->relativeName();
projectList.append(topCvsModule);
projectSettings->set(topCvsModule,DISABLED,disabled);
disabled.clear();
}
tmpDir = parent;
}
QString openDir = dir->fullName();
QString moduleName = dir->topDir()->shortName();
QString topDirName = dir->topDir()->fullName();
delete dir->topDir();
performRereadProject(moduleName,topDirName);
QStringList::Iterator iter;
for (iter = projectList.begin(); iter != projectList.end(); iter++) {
applyProjectSettings(*iter);
}
openTreeAndActivate(topDirName,openDir);
if (!blocked) blockGUI(false);
}
/*---------------------------------------------------------------------------*/
void CvsControl::enableTree() {
Directory * dir;
if (!(dir = getSelectedDir())) {
return;
}
bool blocked = isGuiBlocked();
if (!blocked) blockGUI(true);
QString dirName = dir->fullName();
QString projectName = dir->topDir()->shortName();
//remove from toplevel project
QStringList disabledList;
projectSettings->get(projectName,DISABLED,disabledList);
QStringList::Iterator it = disabledList.begin();
while (it != disabledList.end()) {
if ((*it).startsWith(dirName)) {
it = disabledList.remove(it);
} else {
++it;
}
}
projectSettings->set(projectName,DISABLED,disabledList);
//remove from subprojects
QStringList emptyList;
QStringList subProjectNameList;
projectSettings->getSubProjects(projectName,subProjectNameList);
unsigned int i;
for(i=0; i < subProjectNameList.count(); i++) {
QString fullName;
projectSettings->get(subProjectNameList[i],WORKDIR,fullName);
if ( fullName.startsWith(dirName)) {
projectSettings->set(subProjectNameList[i],DISABLED,emptyList);
} else if (dirName.startsWith(fullName)) {
projectSettings->get(subProjectNameList[i],DISABLED,disabledList);
QStringList::Iterator it = disabledList.begin();
while (it != disabledList.end()) {
if ((*it).startsWith(dirName)) {
it = disabledList.remove(it);
} else {
++it;
}
}
projectSettings->set(subProjectNameList[i],DISABLED,disabledList);
}
}
//make sure disabled list is set
QString topCvsModule = dir->topControlledDir()->relativeName();
projectSettings->get(topCvsModule,DISABLED,disabledList);
static_cast<Directory *>(dir->topControlledDir())->updateDisabledList(disabledList);
//reread tree
rereadProjectOfDir(dir);
if (!blocked) blockGUI(false);
}
/*---------------------------------------------------------------------------*/
void CvsControl::performRereadProject( QString moduleName, QString fullName) {
setStatusText( "");
addProject(fullName);
projectSettings->set(moduleName,WORKDIR,fullName);
setStatusText( tr("Ready"));
}
//----------------------------------------------------------------------------
void CvsControl::slot_rereadProject(DirBase * dir) {
if (!dir) {
if (!(dir = getSelectedDir())) {
return;
}
}
bool blocked = isGuiBlocked();
if (!blocked) blockGUI(true);
Directory * tDir = static_cast<Directory *>(dir);
assert(tDir);
rereadProjectOfDir(tDir);
if (!blocked) blockGUI(false);
}
//----------------------------------------------------------------------------
// reopen tree, returns deepest opened dir in hierarchy or null, if not found in workbench
// it returns also null if dirToOpen is removed behind the back
Directory * CvsControl::openTreeAt(const QString &topDirName,const QString &dirToOpen) {
DirBase * dir = NULL;
if (ONTHEFLYSCANNING && (topDirName != dirToOpen)) {//can't find dir since it's not scanned jet!
int from = topDirName.length();
while (from >= 0) {
dir = m_pWorkBenchTree->find(dirToOpen.left( (unsigned int)from));
if (dir) {
dir->setOpen(TRUE);//This will scan!
}
from = dirToOpen.find('/',from+1);
}
}
dir = m_pWorkBenchTree->find( dirToOpen );
if (dir) {
QString curDir = dir->fullName();
QString removed;
if (ONTHEFLYSCANNING) dir->setOpen(TRUE, removed);//This will scan!
else dir->setAllOpen();
if (removed == curDir) dir = 0;
}
slot_checkStatusOfTree(static_cast<Directory *>(m_pWorkBenchTree->find(topDirName)));
return static_cast<Directory *>(dir);
}
//----------------------------------------------------------------------------
void CvsControl::slot_openTreeAndActivate(DirBase * dirToOpen,const QString name) {
DirBase * dir;
if ( !(dir = openTreeAndActivate(dirToOpen->topDir()->fullName(),name)) ) {
dir = m_pWorkBenchTree->findBestMatch(name);
if (dir) {
m_pWorkBenchTree->setSelected(dir,true);
dir->activateItem(false);
}
}
}
//----------------------------------------------------------------------------
Directory * CvsControl::openTreeAndActivate( const QString &topDirName, QString dirToOpenAfterRescan) {
// reopen tree
int pos = dirToOpenAfterRescan.findRev("/");
if (pos > (int)topDirName.length()) {
openTreeAt(topDirName,dirToOpenAfterRescan.left(pos) );
}
//activate dir
Directory * dir = NULL;
dir = static_cast<Directory *>(m_pWorkBenchTree->find( dirToOpenAfterRescan ));
if( dir ) {
m_pWorkBenchTree->setSelected( dir, TRUE );
dir->activateItem(FALSE);
return dir;
}
return NULL;
}
//----------------------------------------------------------------------------
//warning: param 'dir' will be deleted/invalidated by this method!!!
void CvsControl::slot_selectSubDir(DirBase ** pdir, QString subDir) {
*pdir = rereadProjectOfDir( static_cast<Directory *>(*pdir));//selects the given dir and opens from top to parent if available
if(*pdir) {
// make directory active and open so that content of directory is shown
(*pdir)->setOpen(TRUE);
DirBase * prevDir = *pdir;
*pdir = (*pdir)->searchDirOfPath( subDir );
if (*pdir) {
m_pWorkBenchTree->setSelected( *pdir, TRUE );
(*pdir)->activateItem(FALSE);
} else {//adding of dir failed
*pdir = prevDir;
(*pdir)->activateItem(FALSE);
QString caption = tr("CrossVC - Error");
QString msg = tr("Adding of directory %1 failed!\nMaybe permission denied.");
showWarning( caption, msg.arg(subDir) );
}
}
}
//----------------------------------------------------------------------------
void CvsControl::applyProjectSettings(QString projectName) {
if (projectName.isEmpty()) {//apply settings of all existing projects
QStringList projectNameList;
projectSettings->getTopLevelProjects(projectNameList);
unsigned int i;
for(i = 0; i < projectNameList.count(); ++i) {
projectName = projectNameList[i];
QStringList subProjectNameList;
projectSettings->getSubProjects(projectName,subProjectNameList);
Directory * dir;
QString workdir;
int autoupdate;
bool autoUpdateInSubProject = FALSE;
unsigned int j;
for (j = 0; j < subProjectNameList.count(); ++j) {
autoupdate = AutoUpdate::OFF;
projectSettings->get(subProjectNameList[j],WORKDIR,workdir);
projectSettings->get(subProjectNameList[j],PAUTOUPDATE,autoupdate);
dir = (Directory *)m_pWorkBenchTree->find(workdir);
if (dir) {
bool state = AUTOUPDATE && (autoupdate != AutoUpdate::OFF);
autoUpdateInSubProject |= state;
dir->setAutoUpdate(state);
}
}
autoupdate = AutoUpdate::OFF;
projectSettings->get(projectName,PAUTOUPDATE,autoupdate);
projectSettings->get(projectName,WORKDIR,workdir);
dir = (Directory *)m_pWorkBenchTree->find(workdir);
if (dir) {
dir->setAutoUpdate(AUTOUPDATE && ( (autoUpdateInSubProject) || (autoupdate != AutoUpdate::OFF) ) );
}
}
} else {//apply only settings of 'projectName'
QStringList subProjectNameList;
projectSettings->getSubProjects(projectName,subProjectNameList);
Directory * dir;
QString workdir;
int autoupdate;
bool autoUpdateInSubProject = FALSE;
unsigned int j;
for (j = 0; j < subProjectNameList.count(); ++j) {
autoupdate = AutoUpdate::OFF;
projectSettings->get(subProjectNameList[j],WORKDIR,workdir);
projectSettings->get(subProjectNameList[j],PAUTOUPDATE,autoupdate);
dir = (Directory *)m_pWorkBenchTree->find(workdir);
if (dir) {
bool state = AUTOUPDATE && (autoupdate != AutoUpdate::OFF);
autoUpdateInSubProject |= state;
dir->setAutoUpdate(state);
}
}
autoupdate = AutoUpdate::OFF;
projectSettings->get(projectName,PAUTOUPDATE,autoupdate);
projectSettings->get(projectName,WORKDIR,workdir);
dir = (Directory *)m_pWorkBenchTree->find(workdir);
if (dir) {
dir->setAutoUpdate(AUTOUPDATE && ( (autoUpdateInSubProject) || (autoupdate != AutoUpdate::OFF) ) );
}
}
}
//----------------------------------------------------------------------------
void CvsControl::stopTimers(int type /* = TALL */) {
if (type == TALL || type == TSTATUS) {
m_timer.stop();
}
if (type == TALL || type == TUPDATE) {
m_updateTimer.stop();
}
}
//----------------------------------------------------------------------------
void CvsControl::startTimers(int type /* = TALL */) {
if (type == TALL || type == TSTATUS) {
if (Polling::checkStatusLevel>Polling::NONE && (!DirWatch::b_isActive) ) {
if (!m_timer.isActive()) {
m_timer.start(CHECKSTATUSINTERVALL);
}
}
}
if (type == TALL || type == TUPDATE) {
if (!m_updateTimer.isActive() && AUTOUPDATE) {
m_updateTimer.start(AUTOUPDATEINTERVALL*1000*60);
}
}
}
//----------------------------------------------------------------------------
/**
* Use this Method to check project state and to start the state timer
* It will stop and restart the timer
* appropriate according to the Settings
*/
void CvsControl::slot_checkStatus(bool forceRefresh /*=false*/) {
checkInProgress(TRUE);
stopTimers(TSTATUS);
bool doBlock = !isGuiBlocked();
if (doBlock) blockGUI(true,BLOCKNOCONTROLS | BLOCKNOCURSOR);
DirBase * dir = m_pWorkBenchTree->selectedItem();
if ( dir && dir->isSelected() ) {
if ( dir->isModified() || forceRefresh) {
dir->activateItem(TRUE);
} else {
CFileListView * lv = static_cast<CvsListView*>(m_pFileViews->page(0));
QListViewItem *myChild = lv->firstChild();
while(myChild) {
if(lv->itemRect(myChild).isValid()) {
dir->checkAndShowStatus(static_cast<FileListViewItem*>(myChild));
}
myChild = myChild->nextSibling();
}
}
if ( (Polling::checkStatusLevel >= Polling::ALLDIRS) || forceRefresh ) {
dir = dir->topDir();
dir->recCheckForModifications( (Polling::checkStatusLevel >= Polling::ALLFILES) || forceRefresh );
}
}
if (Polling::checkStatusLevel >= Polling::ALLPROJECTS) {
QListViewItem * myChild = m_pWorkBenchTree->firstChild();
while (myChild) {
if (myChild != dir) {
static_cast<Directory *>(myChild)->recCheckForModifications(Polling::checkStatusLevel >= Polling::ALLFILES);
if (globalStopAction) break;
}
myChild = myChild->nextSibling();
}
}
globalStopAction = false;
checkInProgress(FALSE);
startTimers(TSTATUS);
m_timer.pause();
if (doBlock) blockGUI(false,BLOCKNOCONTROLS | BLOCKNOCURSOR);
}
//----------------------------------------------------------------------------
void CvsControl::slot_checkStatusOfTree(DirBase * dir) {
checkInProgress(TRUE);
if ( dir && dir->isSelected() ) {
if ( dir->isModified() ) {
dir->activateItem(TRUE);
} else {
CFileListView *lv = static_cast<CvsListView*>(m_pFileViews->page(0));
QListViewItem *myChild = lv->firstChild();
while(myChild) {
if(lv->itemRect(myChild).isValid()) {
dir->checkAndShowStatus(static_cast<FileListViewItem*>(myChild));
}
myChild = myChild->nextSibling();
}
}
}
dir->recCheckForModifications(TRUE);
checkInProgress(FALSE);
}
//----------------------------------------------------------------------------
void CvsControl::dirConnectorDataNotify() {
DirBase * dir = m_pWorkBenchTree->selectedItem();
//if(!dir) return; <-- not needed because we want to check dirs even if we have no dirs selected
DirBase * tmpDir = NULL;
QString fileName;
bool deleted;
blockGUI(true,BLOCKNOCONTROLS | BLOCKNOCURSOR);
checkInProgress(TRUE);
while ( (tmpDir = checkMonitoredEvent(fileName,deleted))) {
// qDebug("Notify Dir: "+tmpDir->fullName()+", file: "+fileName+", deleted: "+QString(deleted ? "true" : "false"));
//tmpDir != NULL --> call only dir->activateItem if dir != NULL too
if (dir == tmpDir) {
dir->activateItem(true);
} else {
tmpDir->checkAndShowStatus(NULL,true,DirBase::Controled|DirBase::NonControled|DirBase::Ignored,true);
}
}
checkInProgress(FALSE);
blockGUI(false,BLOCKNOCONTROLS | BLOCKNOCURSOR);
}
//----------------------------------------------------------------------------
void CvsControl::test() { /* -->please keep test() method for testing,
slot is enabled if .lincvsrc has <DEBUG = true> entrie<-- */
recValidateCvsFilesStatus(false,true);
}
void CvsControl::slot_onlineHelp() {
openUrlWithRemoteBrowser(tr("http://cvsbook.red-bean.com/cvsbook.html"));
}
void CvsControl::slot_debug() {
QString debugLogFile;
QFileDialog* fd = new QFileDialog(QDir::currentDirPath(),
tr("Debug Log (*.log)"),
this, "file dialog", TRUE );
fd->setCaption(LC_APPNAME);
fd->setMode( QFileDialog::AnyFile );
fd->setSelection("debug.log");
if ( fd->exec() == QDialog::Accepted) {
debugLogFile = fd->selectedFile();
if ( debugLogFile.isEmpty()) return;
} else {
return;
}
QFile file(debugLogFile);
if (file.exists()) {
if (!showYesNoQuestion( tr("Warning"),
tr("The filename:") + " "
+ debugLogFile + " "
+ tr("already exists.")
+ "\n"
+ tr("Overwrite it?")) )
return;
file.remove();
}
if (file.open(IO_WriteOnly)) {
QTextStream s(&file); // serialize using f
s << "----------start debug log------------\n";
s << "Date: "+QDateTime::currentDateTime().toString(Qt::ISODate)+"\n";
s << "CrossVC version: "+getVersion()+"\n";
#ifdef Q_WS_WIN
s << "for Windows\n";
#else
#ifdef Q_WS_MAC
s << "for Mac OS X\n";
#else
s << "for Unix\n";
#endif
#endif
s << "Compile Time: "+getCompileTime()+"\n";
fillCmdDebugStream(s);
s << "----------end debug log------------";
file.close();
} else {
showWarning( tr("Error:"),
tr("No write access to: ") + debugLogFile);
}
}
//----------------------------------------------------------------------------
void CvsControl::fillCmdDebugStream(QTextStream &s) {
s << m_debugCvsCallString;
s << "outputLineOffset: "+QString::number(outputLineOffset)+"\n";
s << "CvsBuffer: ->"+m_pCvsBuffer->readAll()+"<-\n";
s << "==================================================================\n";
s << "CvsBuffer single line mode: \n";
unsigned int len = (*m_pCvsBuffer).numLines();
for ( unsigned int i = outputLineOffset;i<len;i++) {
s << "->"+(*m_pCvsBuffer).textLine(i)+"<-\n";
}
}
//----------------------------------------------------------------------------
// use this if visible cvs output doesn't match CVS/Repository i.e. merge with -j xxx -j xxx
void CvsControl::recValidateCvsFilesStatus(bool forceCacheReset /*= FALSE */, bool forceEntriesReset /*= FALSE */) {
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
// iter down all dirs, check state of folders and set entries
qApp->setOverrideCursor(waitCursor); // takes some time on huge dirs
dir->validateControlledFilesStatus(TRUE,forceCacheReset,forceEntriesReset);
qApp->restoreOverrideCursor();
}
//----------------------------------------------------------------------------
void CvsControl::updateProjectTagList() {
if (!(m_pFetchTagDir = getSelectedDir())) {
return;
}
DirBase * topDir = m_pFetchTagDir->topControlledDir();
QString dirName = topDir->fullName();
QString cvsRoot = "status -v";
QString files = "";
QString topModule = topDir->relativeName();
callInteractiveCmd( topModule, dirName, cvsRoot,
files, CVS_GET_TAG_INFO_PROJECT_CMD,
ExtApps::g_cvsRsh.path, //additional options of cvsRsh not supported yet
NOROOT, this);
}
//----------------------------------------------------------------------------
void CvsControl::readCurrentTagList() {
if (!(m_pFetchTagDir = getSelectedDir())) {
return;
}
m_currentTagList.clear();
QString cvsRoot = "status -v";
QString files;
QStringList fileList = m_pFetchTagDir->getSelectedFiles();
masqQuoteMarks(&fileList);
if (!fileList.isEmpty()) files = masqWs(fileList.join("\" \""));
else cvsRoot += " -l";
QString dirName = m_pFetchTagDir->fullName();
QString topModule = m_pFetchTagDir->topControlledDir()->relativeName();
callInteractiveCmd( topModule, dirName, cvsRoot,
files, CVS_GET_TAG_INFO_FILES_CMD,
ExtApps::g_cvsRsh.path, //additional options of cvsRsh not supported yet
NOROOT, this);
}
//----------------------------------------------------------------------------
void CvsControl::loginDir()
{
Directory * dir;
if (!(dir = getSelectedDir())) {
return;
}
m_pMessages->setText("");
m_pMessages->setCursorPosition(0, 0);
dir->loginOk(m_pMessages, true);
}
//----------------------------------------------------------------------------
void CvsControl::logoutDir()
{
Directory * dir;
if (!(dir = getSelectedDir())) {
return;
}
m_pMessages->setText("");
m_pMessages->setCursorPosition(0, 0);
dir->removeLogin(m_pMessages);
}
//----------------------------------------------------------------------------
void CvsControl::editFile( QString FN) {
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
QStringList nameList;
nameList.append(FN);
Mapping::FileAppItem item = getMatchForWildcard(nameList,Mapping::openFileAppList);
if (!item.params.isEmpty()) {
QStringList::Iterator it;
for (it=nameList.begin(); it != nameList.end(); it++) {
(*it).replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS);
(*it) = dir->fullName()+"/"+(*it);
}
QString cmd = masqWs(item.app);
QString params = " " + item.params;
if (masqedFilenamesForPlaceholders(params,nameList)) {
cmd += params;
runExternal(cmd);
} else {
showWarning(tr("Warning"), tr("There are no matching placeholders specified,")
+"\n"
+tr("Check and adjust 'Options/Open file mapping ...' to proceed."));
}
} else {
showWarning(tr("Warning"), tr("There is no application specified to open the selected file with,")
+"\n"
+tr("Check and adjust 'Options/Open file mapping ...' to proceed."));
}
}
//----------------------------------------------------------------------------
void CvsControl::viewFileWithPath( QString FN) {
int pos = FN.findRev("/");
QString path = FN.mid(0,pos);
FN = FN.mid(pos+1);
QStringList nameList;
nameList.append(FN);
Mapping::FileAppItem item = getMatchForWildcard(nameList,Mapping::viewFileAppList);
if (!item.params.isEmpty()) {
QStringList::Iterator it;
for (it=nameList.begin(); it != nameList.end(); it++) {
(*it).replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS);
(*it) = path+"/"+(*it);
}
QString cmd = masqWs(item.app);
QString params = " " + item.params;
if (masqedFilenamesForPlaceholders(params,nameList)) {
cmd += params;
runExternal(cmd);
} else {
showWarning(tr("Warning"), tr("There are no matching placeholders specified,")
+"\n"
+tr("Check and adjust 'Options/View file mapping ...' to proceed."));
}
} else {
showWarning(tr("Warning"), tr("There is no application specified to view the selected file with,")
+"\n"
+tr("Check and adjust 'Options/View file mapping ...' to proceed."));
}
}
//----------------------------------------------------------------------------
void CvsControl::browseDir()
{
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
QString cmd = "\"" + ExtApps::g_localBrowser.path + "\" ";
QStringList nameList;
nameList.append(dir->fullName());//the startup dir is not sufficiant -- some browsers need the startup dir specified
QString options = ExtApps::g_localBrowser.options;
options = validateOptions(options);
masqedFilenamesForPlaceholders(options, nameList);
cmd += options;
QDir * directory = new QDir(dir->fullName());
runExternal(cmd, directory);
}
//----------------------------------------------------------------------------
void CvsControl::openShellDir()
{
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
QString cmd = "\"" + ExtApps::g_localShell.path + "\" ";
QStringList nameList;
nameList.append(dir->fullName());//the startup dir is not sufficiant -- some consoles might need the startup dir specified
QString options = ExtApps::g_localShell.options;
//options = validateOptions(options); we cannot append an '%n' because the most shells don't like it!
masqedFilenamesForPlaceholders(options, nameList);
cmd += options;
QDir * directory = new QDir(dir->fullName());
runExternal(cmd, directory);
}
//----------------------------------------------------------------------------
void CvsControl::openFile()
{
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
QStringList nameList = dir->getSelectedFiles();
if (!nameList.empty()) {//dir is selected, no further check needed
Mapping::FileAppItem item = getMatchForWildcard(nameList,Mapping::openFileAppList);
if (!item.params.isEmpty()) {
QStringList::Iterator it;
for (it=nameList.begin(); it != nameList.end(); it++) {
(*it).replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS);
(*it) = dir->fullName()+"/"+(*it);
}
QString cmd = masqWs(item.app);
QString params = " " + item.params;
if (masqedFilenamesForPlaceholders(params,nameList)) {
cmd += params;
runExternal(cmd);
} else {
showWarning(tr("Warning"), tr("There are no matching placeholders specified,")
+"\n"
+tr("Check and adjust 'Options/Open file mapping ...' to proceed."));
}
} else {
showWarning(tr("Warning"), tr("There is no application specified to open the selected files with,")
+"\n"
+tr("Check and adjust 'Options/Open file mapping ...' to proceed."));
}
}
}
//----------------------------------------------------------------------------
void CvsControl::viewFile()
{
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
QStringList nameList = dir->getSelectedFiles();
if (!nameList.empty()) {//dir is selected, no further check needed
Mapping::FileAppItem item = getMatchForWildcard(nameList,Mapping::viewFileAppList);
if (!item.params.isEmpty()) {
QStringList::Iterator it;
for (it=nameList.begin(); it != nameList.end(); it++) {
(*it).replace("\"", PLACEHOLDER_FOR_QUOTATION_MARKS);
(*it) = dir->fullName()+"/"+(*it);
}
QString cmd = masqWs(item.app);
QString params = " " + item.params;
if (masqedFilenamesForPlaceholders(params,nameList)) {
cmd += params;
runExternal(cmd);
} else {
showWarning(tr("Warning"), tr("There are no matching placeholders specified,")
+"\n"
+tr("Check and adjust 'Options/View file mapping ...' to proceed."));
}
} else {
showWarning(tr("Warning"), tr("There is no application specified to view the selected files with,")
+"\n"
+tr("Check and adjust 'Options/View file mapping ...' to proceed."));
}
}
}
//----------------------------------------------------------------------------
void CvsControl::createNewFile() {
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
QString newFile = QInputDialog::getText("Create File", "Name: ",
QLineEdit::Normal ).stripWhiteSpace();
if (!newFile.isEmpty() && !newFile.contains("/")) {
QFile file(dir->fullName()+"/"+newFile);
if (file.exists()) {
showWarning( tr("Warning"), tr("This file already exists") );
} else if (file.open(IO_WriteOnly)) {
file.close();
dir->activateItem(false,( (dir->getEntryState(newFile)>0) ? DirBase::Controled : 0)|DirBase::NonControled|DirBase::Ignored);
} else {
showWarning( tr("Warning"), tr("The file could not be created") );
}
} else {
showWarning( tr("Warning"), tr("The filename is invalid") );
}
}
//----------------------------------------------------------------------------
void CvsControl::createNewDir() {
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
QString newDir = QInputDialog::getText("Create Dir", "Name: ",
QLineEdit::Normal ).stripWhiteSpace();
if (!newDir.isEmpty() && !newDir.contains("/")) {
QDir d(dir->fullName()+"/"+newDir);
if (d.exists()) {
showWarning( tr("Warning"), tr("This directory already exists") );
} else if (d.mkdir(dir->fullName()+"/"+newDir,true)) {
dir->activateItem(false,DirBase::NonControled|DirBase::Ignored);
} else {
showWarning( tr("Warning"), tr("The Dir could not be created") );
}
} else {
showWarning( tr("Warning"), tr("The dirname is invalid") );
}
}
//----------------------------------------------------------------------------
//returns the dir if successfully reopened, null otherwise
Directory * CvsControl::rereadProjectOfDir( Directory * dir ) {
// have added directory
QString dirToOpenAfterRescan = dir->fullName();
DirBase * topDir = dir->topDir();
// keep project identifiers
QString moduleName = topDir->shortName();
QString topDirName = topDir->fullName();
//keep open dirs
QStringList openDirs;
dir->recGetOpenDirsStringList(openDirs);
if (topDirName == dirToOpenAfterRescan) {
delete dir;
dir = NULL;
performRereadProject( moduleName,topDirName);//calls addProject()
} else {
Directory * parentDir = dir->parent();
parentDir->reloadChild(dirToOpenAfterRescan);
}
dir = (Directory *)m_pWorkBenchTree->find( dirToOpenAfterRescan );
if( dir ) {
QString curDir = dir->fullName();
QStringList::Iterator it;
for (it = openDirs.begin(); it != openDirs.end(); ++it) {
Directory *openedDir = openTreeAt( topDirName, (*it));
if (!openedDir && (curDir == (*it))) dir = 0;
}
if (dir) {
m_pWorkBenchTree->setSelected( dir, TRUE );
dir->activateItem(FALSE);
}
}
applyProjectSettings(moduleName);
return dir;
}
//----------------------------------------------------------------------------
void CvsControl::expandDir() {//only called from lincvs.cpp
Directory * dir;
if (!(dir = getSelectedDir())) {
return;
}
bool blocked = isGuiBlocked();
if (!blocked) blockGUI(true);
dir->expandAllDir();
slot_checkStatusOfTree(dir);
if (!blocked) blockGUI(false);
}
//----------------------------------------------------------------------------
void CvsControl::collapsDir() {//only called from lincvs.cpp
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
blockGUI(true,BLOCKNOCONTROLS);
dir->collapsAllDir();
QApplication::restoreOverrideCursor();
blockGUI(false,BLOCKNOCONTROLS);
}
//----------------------------------------------------------------------------
//works only on toplevel dirs!!!!!!!!!!!!!!!!!!!!
void CvsControl::renameDir(Directory * dir,QString newName) {
QStringList projectNameList;
projectSettings->getProjects(projectNameList);
unsigned int i;
for(i=0; i < projectNameList.count(); i++) {
QString fullName;
projectSettings->get(projectNameList[i],WORKDIR,fullName);
if ( newName.startsWith(fullName)) {
int pos = fullName.length()-projectNameList[i].length();
QString newModule = newName.mid(pos,newName.find('/',pos)-pos);
if (projectNameList[i] == newModule) {
showWarning(tr("Warning: rename aborted")
,tr("This project is already in workbench:")+" "
+projectNameList[i]
+"\nat: "+fullName);
setStatusText( tr("Rename aborted"), 4000 );
return;
}
}
}
QString oldTopName = dir->topDir()->fullName();
QString topModule = dir->topDir()->shortName();
QString newTopModule = newName.mid( newName.findRev("/")+1);
if (renameProject(topModule,newTopModule)) {
if (!rename(dir->fullName(),newName)) {
renameProject(newTopModule,topModule);
showWarning(tr("Warning: rename aborted")
,tr("Can't rename:\n")
+oldTopName
+",\n"+tr("check permissions"));
setStatusText( tr("Rename aborted"), 4000 );
return;
}
} else {
showWarning(tr("Warning: rename aborted")
,tr("Can't rename:\n")
+oldTopName
+",\n"+tr("the new name: ")+newTopModule+"\n"+tr("is already in use"));
setStatusText( tr("Rename aborted"), 4000 );
return;
}
QStringList openDirs;
QStringList::Iterator it;
dir->recGetOpenDirsStringList(openDirs);
for (it = openDirs.begin(); it != openDirs.end(); ++it) {
if ( (*it).startsWith(oldTopName)) {
(*it) = newName + (*it).mid(oldTopName.length());
}
}
delete dir;
dir = NULL;
addProject(newName,TRUE);
dir = static_cast<Directory *>(m_pWorkBenchTree->find(newName));
if (dir) {
QString curDir = dir->fullName();
for (it = openDirs.begin(); it != openDirs.end(); ++it) {
Directory *openedDir = openTreeAt( newName, (*it));
if (!openedDir && (curDir == (*it))) dir = 0;
}
if (dir) {
m_pWorkBenchTree->setSelected( dir, TRUE );
dir->activateItem(FALSE);
}
}
}
//----------------------------------------------------------------------------
bool CvsControl::moveProject(const QString& project, const QString& oldPath, const QString& newPath) {//FIXME unused ...
projectSettings->set(project,WORKDIR,newPath);
QStringList::Iterator it;
QStringList list;
projectSettings->get(project,DISABLED,list);
for (it = list.begin(); it != list.end(); ++it) {
if ( (*it).startsWith(oldPath)) {
(*it) = newPath + (*it).mid(oldPath.length());
}
}
projectSettings->set(project,DISABLED,list);
projectSettings->getSubProjects(project,list);
for (it = list.begin(); it != list.end(); ++it) {
QString path;
projectSettings->get(*it,WORKDIR,path);
if ( path.startsWith(oldPath)) {
path = newPath + path.mid(oldPath.length());
}
projectSettings->set(*it,WORKDIR,path);
}
return true;
}
//----------------------------------------------------------------------------
bool CvsControl::renameProject(const QString& oldProject, const QString& newProject) {
if (!projectSettings->renameProject(oldProject,newProject)) return false;
QString oldWorkdir;
projectSettings->get(newProject,WORKDIR,oldWorkdir);
QString newWorkdir = oldWorkdir.left(oldWorkdir.length()-oldProject.length()) + newProject;
projectSettings->set(newProject,WORKDIR,newWorkdir);
QStringList::Iterator it;
QStringList list;
projectSettings->get(newProject,DISABLED,list);
QStringList oldDisabledList = list;
for (it = list.begin(); it != list.end(); ++it) {
if ( (*it).startsWith(oldWorkdir)) {
(*it) = newWorkdir + (*it).mid(oldWorkdir.length());
}
}
projectSettings->set(newProject,DISABLED,list);
list.clear();
projectSettings->getSubProjects(newProject,list);
for (it = list.begin(); it != list.end(); ++it) {
QString newName = newProject + (*it).mid(oldProject.length());
if (renameProject(*it,newName)) {
*it = newName;
} else {//rollback
QStringList::Iterator rit = list.begin();
while( rit != it) {
QString oldName = oldProject + (*it).mid(newProject.length());
renameProject(*it,oldName);
++rit;
}
projectSettings->renameProject(newProject,oldProject);
projectSettings->set(oldProject,WORKDIR,oldWorkdir);
projectSettings->set(oldProject,DISABLED,oldDisabledList);
return false;
}
}
projectSettings->setSubProjects(newProject,list);
return true;
}
//----------------------------------------------------------------------------
void CvsControl::slot_removeFileFromDisk() {
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
QStringList files = dir->getSelectedFiles();
if (files.isEmpty()) return;
if (!showVerifyDialog(tr("Warning"),tr("This command will remove file(s) from disk!"))) {
return;
}
QString path = dir->fullName()+"/";
bool blocked = isGuiBlocked();
if (!blocked) blockGUI(true);
QStringList::Iterator it;
for( it = files.begin(); it != files.end(); ++ it ) {
QFile f(path+*it);
if (!QFileInfo(f.name()).isSymLink()) setPermission(f,READABLE | WRITEABLE);
if (f.remove()) {
dir->setEntryState(*it,ES_missing);
} else qDebug("couldn't remove: "+path+*it);
}
dir->postCallCheck(DirBase::Controled|DirBase::Force);
if (!blocked) blockGUI(false);
}
//----------------------------------------------------------------------------
void CvsControl::removeNonCvsFileFromDisk() {
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
if (!showVerifyDialog(tr("Warning"),tr("This command will remove file(s) from disk!"))) {
return;
}
QString CurDir = dir->fullName() + "/";
QListViewItem *myChild = static_cast<QListView*>(m_pFileViews->page(1))->firstChild();
while(myChild) {
if(myChild->isSelected()) {
QString fileName = myChild->text(0).stripWhiteSpace();
QFileInfo info( CurDir + fileName);
if (!info.isSymLink() && info.isDir()) {
if (removeDirTreeFromDisk(CurDir + fileName, FALSE)) {
if (!removeDirTreeFromDisk(CurDir + fileName, TRUE)) {
myChild = myChild->nextSibling();
continue;
}
}
} else {
QFile f( CurDir + fileName);
if (!QFileInfo(f.name()).isSymLink()) setPermission(f,READABLE | WRITEABLE);
f.remove();
}
QListViewItem *childToDelete;
childToDelete = myChild;
myChild = myChild->nextSibling();
delete childToDelete;
continue;
}
myChild = myChild->nextSibling();
}
dir->activateItem(TRUE);
}
//----------------------------------------------------------------------------
void CvsControl::removeCvsIgnoreFileFromDisk() {
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
if (!showVerifyDialog(tr("Warning"),tr("This command will remove file(s) from disk!"))) {
return;
}
QString CurDir = dir->fullName() + "/";
QListViewItem *myChild = static_cast<QListView*>(m_pFileViews->page(2))->firstChild();
while(myChild) {
if(myChild->isSelected()) {
QString fileName = myChild->text(0).stripWhiteSpace();
QFileInfo info( CurDir + fileName);
if (!info.isSymLink() && info.isDir()) {
if (removeDirTreeFromDisk(CurDir + fileName, FALSE)) {
if (!removeDirTreeFromDisk(CurDir + fileName, TRUE)) {
myChild = myChild->nextSibling();
continue;
}
}
} else {
QFile f( CurDir + fileName);
if (!info.isSymLink()) setPermission(f,READABLE | WRITEABLE);
f.remove();
}
QListViewItem *childToDelete;
childToDelete = myChild;
myChild = myChild->nextSibling();
delete childToDelete;
continue;
}
myChild = myChild->nextSibling();
}
dir->activateItem(TRUE);
}
//----------------------------------------------------------------------------
bool CvsControl::removeDirTreeFromDisk(QString dir,bool remove) {
QDir D( dir);
D.setFilter( QDir::Dirs); //should list all dirs
QStringList AllDirEntries = D.entryList();
AllDirEntries.remove( "." );
AllDirEntries.remove( ".." );
if (!remove && (AllDirEntries.find( "CVS") != AllDirEntries.end())) return FALSE;
QStringList::Iterator it;
for ( it = AllDirEntries.begin(); it != AllDirEntries.end(); it++ ) {
if (!removeDirTreeFromDisk( dir+"/"+(*it),remove)) return FALSE;
}
dir += "/";
D.setFilter( QDir::Files | QDir::Hidden); //should list everything
QStringList AllEntriesInDir = D.entryList();
for ( it = AllEntriesInDir.begin(); it != AllEntriesInDir.end(); it++ ) {
QString file = dir + (*it);
if (remove) {
QFile f( file);
if (!QFileInfo(file).isSymLink()) setPermission(f,READABLE | WRITEABLE);
if (!f.remove()) {
showWarning( tr("Warning"), tr("Cannot remove:\n")+file);
return FALSE;
}
}
}
QFileInfo info( D.path());
if (info.permission( QFileInfo::WriteUser)) {
if (remove) {
if (D.rmdir(D.path())) return TRUE;
else {
showWarning( tr("Warning"), tr("Cannot remove:") + "\n" + D.path() + "\n" + tr("no permission") );
return FALSE;
}
} else return TRUE;
} else {
showWarning( tr("Warning"), tr("Cannot remove:") + "\n" + D.path() + "\n" + tr("no permission") );
return FALSE;
}
}
//----------------------------------------------------------------------------
bool CvsControl::removeFilesInTreeFromDisk(QString dir,bool remove) {//unused
QDir D( dir);
D.setFilter( QDir::Dirs); //should list all dirs
QStringList AllDirEntries = D.entryList();
AllDirEntries.remove( "." );
AllDirEntries.remove( ".." );
if (!remove && (AllDirEntries.find( "CVS") != AllDirEntries.end())) return FALSE;
AllDirEntries.remove( "CVS");
QStringList::Iterator it;
for ( it = AllDirEntries.begin(); it != AllDirEntries.end(); it++ ) {
if (!removeFilesInTreeFromDisk( dir+"/"+(*it),remove)) return FALSE;
}
dir += "/";
D.setFilter( QDir::Files | QDir::Hidden); //should list everything
QStringList AllEntriesInDir = D.entryList();
for ( it = AllEntriesInDir.begin(); it != AllEntriesInDir.end(); it++ ) {
QString file = dir + (*it);
if (remove) {
QFile f( file);
if (!QFileInfo(file).isSymLink()) setPermission(f,READABLE | WRITEABLE);
if (!f.remove()) {
showWarning( tr("Warning"), tr("Cannot remove:") + "\n" + file);
return FALSE;
}
}
}
return TRUE;
}
//----------------------------------------------------------------------------
void CvsControl::stopCurAction()
{
globalStopAction = true;
if(m_interactiveCmdThreadIsRunning) {//nur fuer cvs thread
m_interactiveCmdThreadIsRunning = false; //"prellen" verhindern
CExtTimer::singleShot(100, this, SLOT(killInteractiveCmdThread()));
}
}
//----------------------------------------------------------------------------
void CvsControl::killInteractiveCmdThread()
{
//m_pInteractiveCmdThread can be 0 after cancelling cvs action by user
if (m_pInteractiveCmdThread) m_pInteractiveCmdThread->exit();
}
//----------------------------------------------------------------------------
//write config
void CvsControl::writeCfg()
{
conf->writeCfg();
}
//----------------------------------------------------------------------------
void CvsControl::removeDirIfNoCvsRegisteredFiles() {
Directory * dir = static_cast<Directory *>(m_pWorkBenchTree->selectedItem());
if(!dir) {
showWarning( tr("Warning"), tr("There is no directory selected") );
return;
}
if(!dir->loginOk(m_pMessages)) return;
if (!showVerifyDialog(tr("Warning"),tr("This command will recursively remove\nfile(s) from disk!"))) {
return;
}
bool blocked = isGuiBlocked();
if (!blocked) blockGUI(true);
bool isTopLevel = (dir == dir->topDir());
if ( !(removeDirTreeFromDisk(dir->fullName(), FALSE)) ) {
if ( !( showYesNoQuestion( tr("Warning"),
tr("The directory contains files under CVS control:") + "\n" +
dir->fullName() + "\n" + tr("Delete anyway?") )
&& removeDirTreeFromDisk(dir->fullName(), TRUE)) ) {
showWarning( tr("Error"),
tr("Failure during removal of:") + "\n" + dir->fullName() );
if (!blocked) blockGUI(false);
return;
}
}
if (!isTopLevel) rereadProjectOfDir( dir->parent() );
if (!blocked) blockGUI(false);
}
//----------------------------------------------------------------------------
/*
* This funktion should export the workdir the user klicked on to export.
* Since the cvs export funktion only exports cvs registered files from the
* repository, we need here the ability to only export the cvs registered
* files as well, but maybe in modified state, just as they are currently
* in the workdir. If a file for example is missing, we don't export it, and
* so on. So we have here a funktion that exports our working dir, but without
* ignored or not cvs registered files. We could build a tarbal without .o and
* whatever files, but wouldn't need to run make clean before (very anoying in
* big projects since it takes quite long to recompile).
*/
void CvsControl::exportFromModuleDir() {
DirBase * dir;
if (!(dir = getSelectedDir())) {
return;
}
QString exportDir = dir->shortName()+"_export";
QString parentDir = dir->fullName();
parentDir = parentDir.left(parentDir.findRev("/"));
QFileDialog* fd = new QFileDialog(parentDir, NULL,
this, "directory dialog", true );
fd->setCaption("Export project: "+dir->shortName());
fd->setMode( QFileDialog::DirectoryOnly );
fd->setSelection(exportDir);
if ( fd->exec() == QDialog::Accepted) {
exportDir = fd->selectedFile();
if ( exportDir.isEmpty()) return;
while ( (exportDir.length() > 1) && exportDir.endsWith("/") ) exportDir.truncate(exportDir.length()-1);
} else {
return;
}
QDir exdir(exportDir);
if (exdir.exists()) {
QStringList entries = exdir.entryList();
bool bEmpty = true;
for (QStringList::Iterator it = entries.begin(); it != entries.end(); it++ ) {
if ( (*it == ".") || (*it == "..") ) continue;
bEmpty = false;
break;
}
if (!bEmpty) {
if (!showYesNoQuestion(tr("Warning"),
tr("The directory:") + " "
+ exportDir
+ " " + tr("already exists.") + "\n" + tr("Overwrite it?"))) return;
}
}
QApplication::setOverrideCursor(waitCursor);
if (!dir->recCopyControlledFiles(exportDir,DirBase::Replace)) showWarning( (tr("Error")+", "+tr("export stopped")),
tr("Couldn't create directories"));
QApplication::restoreOverrideCursor();
}
//----------------------------------------------------------------------------
void CvsControl::initLocalRepository(QString cvsRoot) {
QString topModule = QString::null;
QString file = "init";
cvsRoot = masqWs(cvsRoot);
callInteractiveCmd( topModule, APPDIR, cvsRoot,
file, CVS_NOT_INTERACTIVE_CMD,
ExtApps::g_cvsRsh.path); //additional options of cvsRsh not supported yet
}
/*****************************************************************************
*
* Call InteractiveCmdThread!
* Params: topModule - the toplevel (dir-)name of the module
* dir - the dir to invoke the command in
* cvsRootOrCommand - the CVS/Root or command ==> noroot
* files - the files to invoke the command with
* icmd - Command that should be called (ie.CommandInterface.h)
* cvsRsh - the remote shell to use
* noroot - if noroot is true the command except 'cvs'
* has to be appended to cvsRootOrCommand, no -d option will be specified
* instance - the instance (for ex. a dialog implementing CommandInterface.h)
* if instance is given with 'this', afterCall(icmd) in 'this' instance
* will be called when cvs-call has finished
*
* to append additional interactive commands, InteractiveCmdThread.cpp and
* InteractiveCmdThread.h have to be edited and the additional rules
* must be put to the switch-clauses
*
* to call cvs from external classes, inherit CommandInterface, implement void afterCall(int cmd)
* and start cvscall: void callInteractive( dir, cvsRootOrCommand, files, icmd, cvsRsh, noroot);
* calling cvsCallFailed(icmd,instance) makes sure that afterCall gets called in error situation too.
*
****************************************************************************/
void CvsControl::callInteractiveCmd( QString& topModule,
QString& dir,
QString& cvsRootOrCommand,
QString& files,
int icmd,
QString& cvsRsh,
bool noroot /*=FALSE*/,
CommandInterface *instance /*=NULL*/) {
if (m_interactiveCmdThreadIsRunning) {//make sure no two commands run simultaneous
QString msg = "THREAD WARNING: InteractiveCmdThread is already running, call: "+QString::number(icmd)+" canceled";
if (Debug::g_pLog) Debug::g_pLog->log(Debug::LL_THE_OLD_MAN_AND_THE_SEA,msg);
cvsCallFailed(icmd,instance);//makes sure automatic recursive calls don't get mixed up
return;
}
QString command;
setStatusText("");
m_pLastCvsCallDir = static_cast<Directory *>(m_pWorkBenchTree->find(dir.stripWhiteSpace()));
QDir workDir(dir.stripWhiteSpace());
if (!workDir.exists()) {//would run in LinCVS's workdir otherwise
cvsCallFailed(icmd,instance);
return;
}
// check for required login
QString cvsRootLine;
QString method;
QString user;
QString passwd;
QString host;
int port;
QString rootDir;
if (noroot) { // We have to check the cvs connection method
QFile f;
f.setName(dir + "/CVS/Root");
if(f.open(IO_ReadOnly)) {
QTextStream textStream(&f);
cvsRootLine = textStream.readLine();
f.close();
}
} else {
int pos = cvsRootOrCommand.find("\"",1);//extract tmp files
if (pos > -1) cvsRootLine = cvsRootOrCommand.left(pos+1);
else cvsRootLine = cvsRootOrCommand;
cvsRootLine = umasqWs(cvsRootLine);//only umasq for local use, not for cmd call!!!
}
if (!extractCVSROOT( cvsRootLine, method, user, passwd, host, port, rootDir)) {
if (Debug::g_pLog) Debug::g_pLog->log(Debug::LL_THE_OLD_MAN_AND_THE_SEA,"ERROR in cvsRootLine: ->"+cvsRootLine+"<-");
cvsCallFailed(icmd,instance);
return;
}
globalStopAction = false;
unsigned int pwdPos = 0;
unsigned int pwdLen = 0;
if ((method == "pserver") || (method == "sspi")) { // password server OR sspi
Debug::g_pLog->log(Debug::LL_INFO, "access method: pserver OR sspi");
if (passwd.isNull() && !isInCvsPass(cvsRootLine))
{
bool ok = false;
bool blocked = isGuiBlocked();
if (blocked) blockGUI(false);
QWidget * parentWidget = qApp->activeWindow();
//if (!parentWidget) parentWidget = LookAndFeel::g_b0AsParent ? 0 : this;
if (!parentWidget) parentWidget = this;
QString pwd = QInputDialog::getText("Enter CVS password",
":" + method + ":" + user + "@" + host + ":" + QString::number(port) + rootDir, QLineEdit::Password,
QString::null, &ok, parentWidget, "Password Dialog");
if (blocked) blockGUI(true);
if (!ok) {
cvsCallFailed(icmd,instance);
return;
}
globalStopAction = false;
if (!blocked) blockGUI(true);
Login *l = new Login(m_pMessages, method, user, host, port, rootDir);
l->doLogin(pwd);
delete l;
if (!blocked) blockGUI(false);
if(!isInCvsPass(cvsRootLine)) {
if (!KILLED) {
showWarning(tr("Warning"), tr("Login failed.") );
}
cvsCallFailed(icmd,instance);
return;
}
}
//export proxy settings
QString proxyString = getProxy(user+"@"+host);
if (!proxyString.isEmpty()) {
if ( (icmd==CVS_RELEASE_D_CMD) || (icmd==CVS_RELEASE_CMD)) {//cvs bug prevents proxy usage
showWarning( tr("Warning"), tr("can't release through proxy tunnel.") );
cvsCallFailed(icmd,instance);
return;
}
command += "export PSERVER_PROXY=" + proxyString + " && ";
int pos = proxyString.find (':');
if (pos > 0) {
command += "export CVS_PROXY=" + proxyString.left (pos) + " && ";
command += "export CVS_PROXY_PORT=" + proxyString.mid (pos+1) + " && ";
}
}
} else if ( method == "ext") { // external connect method
#ifdef Q_WS_WIN
command += "export CVS_RSH=" + cvsRsh + " && ";
#else
QString rsh = APPDIR + "/" + LC_TOOLS_DIR + "/rshwrapper";
if (!QFileInfo(rsh).exists()) {
showWarning( tr("Warning"), tr("can't access rshwrapper: "+rsh+": file not found") );
cvsCallFailed(icmd,instance);
return;
}
command += "export CVS_RSH=" + rsh + " && export WRAPPER_RSH=" + cvsRsh + " && ";
#endif
//need project specific settings here:
QString cvsServerCmd;
if ( projectSettings->get(topModule,CVSSERVER,cvsServerCmd)) {
if (!cvsServerCmd.isEmpty()) {
command += "export CVS_SERVER=" + cvsServerCmd + " && ";
}
}
int sshAccess = NOSSH;
if ( projectSettings->get(topModule,SSHACCESS,sshAccess)) {
bUseSsh = false;
bUseSshAgent = false;
bUseSshAgentVars = false;
switch( sshAccess) {
case USESSH: {
bUseSsh = true;
break;
}
case USESSHAGENT: {
bUseSshAgent = true;
break;
}
case USESSHAGENTVARS: {
bUseSshAgentVars = true;
break;
}
}
}
if (bUseSsh) {//use modified ssh with graphical login
Debug::g_pLog->log(Debug::LL_INFO, "access method: ext/ssh");
if (WINVERSION) {
bool ok = false;
bool blocked = isGuiBlocked();
if (blocked) blockGUI(false);
QWidget * parentWidget = qApp->activeWindow();
//if (!parentWidget) parentWidget = LookAndFeel::g_b0AsParent ? 0 : this;
if (!parentWidget) parentWidget = this;
QString pwd = QInputDialog::getText("Enter CVS password",
":" + method + ":" + user + "@" + host + ":" + QString::number(port) + rootDir, QLineEdit::Password,
QString::null, &ok, parentWidget, "Password Dialog");
if (blocked) blockGUI(true);
if (!ok) {
cvsCallFailed(icmd,instance);
return;
}
command += "export SSH_LinCVS_PW=";
pwdPos = command.length();
pwdLen = pwd.length();
command += pwd;
command += " && ";
} else {
command += "export SSH_LinCVS=LinCVSMagic && ";
}
} else if ( !cvsRsh.isEmpty() && (bUseSshAgent || bUseSshAgentVars) ) { // special for ssh
Debug::g_pLog->log(Debug::LL_INFO, "access method: ext/ssh-agent");
sshAgentIsRunning = false;
if (!sshAgentStarted || bUseSshAgentVars) {
bool blocked = isGuiBlocked();
if (!blocked) blockGUI(true);
if (!bUseSshAgentVars) setStatusText(tr("Starting ssh-agent. Please wait ..."));
startSshAgent();//(check for ssh agent variables if bUseSshAgentVars or start ssh agent
if (!blocked) blockGUI(false);
if (bUseSshAgentVars) {
if (sshAgentIsRunning) {
setStatusText(tr("Using running ssh-agent. Please wait ..."));
} else if (sshAgentStarted) {
setStatusText(tr("Couldn't detect running ssh-agent. Own agent started, please wait ..."));
} else {
setStatusText(tr("Cannot detect running ssh-agent and couldn't start agent, call canceled."));
cvsCallFailed(icmd,instance);
return;
}
} else if (!sshAgentStarted) {
setStatusText(tr("Couldn't start ssh-agent"));
cvsCallFailed(icmd,instance);
return;
} else {
setStatusText(tr("Ssh-agent started. Please wait ..."));
}
}
if (!sshAgentIsRunning) checkSshAgent();//read agent env vars
if (!sshAgentIsRunning) {//cancel the command if ssh agent could not be started
setStatusText(tr("Cannot detect running ssh-agent, call canceled."));
cvsCallFailed(icmd,instance);
return;
}
if (WINVERSION) {//todo: setup for win ssh-agent
} else {
command += "export ";
command += envSSH_AGENT_PID;
command += " && ";
command += "export ";
command += envSSH_AUTH_SOCK;
command += " && ";
command += "export SSH_LinCVS=LinCVSMagic && ";
}
} else if (cvsRsh.isEmpty() || bUseSshAgent || bUseSshAgentVars) {
showWarning( tr("Warning"),
tr("Connect method is 'ext'")
+",\n"
+tr("but there is no ssh remote shell specified, aborting.") );
cvsCallFailed(icmd,instance);
return;
} else {// other connect method
Debug::g_pLog->log(Debug::LL_INFO, "access method: ext/unknown");
}
} else { // local connect method
Debug::g_pLog->log(Debug::LL_INFO, "access method: local");
}
//append cvsRoot (ev. including additional commands) to command
command += "cvs ";
if (!noroot) command +="-d ";
command += cvsRootOrCommand;
//complete the command
switch(icmd) {
case CVS_RELEASE_CMD: {
command += " release";
break;
}
case CVS_RELEASE_D_CMD: {
command += " release -d";
break;
}
case CVS_UNEDIT_CMD: {
command += " unedit";
break;
}
default: {
break;
}
}
//change to absolute cvs path if given
if (!CVSPATH.isEmpty()) {
command.replace( QRegExp("^cvs\\s"), masqWs(CVSPATH)+" ");
command.replace( QRegExp("&&\\scvs\\s"), "&& "+masqWs(CVSPATH)+" ");
}
if (!m_chainedCommand) {//don't clear output window on chained calls
m_pMessages->reset();
} else {
m_pMessages->insert("\n========================== "+tr("next command")+" ===========================\n\n");
}
m_pMessages->setMode(icmd);
m_pCvsBuffer->clear();
if (!isGuiBlocked()) blockGUI(true);
setStatusText(tr("Operation in progress. Please wait ..."));
suspendDirWatch();
m_pPixmapTimer->slotStart();
m_debugCvsCallString = command;
if (pwdLen > 0) {
m_debugCvsCallString.replace(pwdPos,pwdLen,"*****");
}
m_debugCvsCallString = "cvscall:\ndir: ->"+
workDir.absPath()+"<-\ncommand: ->"+
m_debugCvsCallString+"<-\nicmd: ->"+
QString::number(icmd)+"<-\nfiles: ->"+
files+"<-\n";
delete m_pInteractiveCmdThread;
m_pInteractiveCmdThread = new InteractiveCmdThread( this, m_pCvsBuffer, m_pMessages, workDir, command, icmd, files, instance);
connect(m_pInteractiveCmdThread,SIGNAL(requestReceived(MESSAGE)),this,SLOT(handleMessage(MESSAGE)));
connect(m_pInteractiveCmdThread,SIGNAL(cvsCommandFinished()),this,SLOT(cvsCommandFinished()));
if (m_chainedCommand) {//delay chained cvs call, to make CVS dir timestamp detectable as beeing changed
int from = QTime::currentTime().second();
while (from == QTime::currentTime().second()) {
qApp->processEvents(100);
wait(100);
}
m_chainedCommand = false;
}
if (m_pInteractiveCmdThread->start()) {
m_interactiveCmdThreadIsRunning = true;
}
}
//----------------------------------------------------------------------------
void CvsControl::cvsCallFailed(int cmd, CommandInterface* instance) {
if (Debug::g_pLog) Debug::g_pLog->log(Debug::LL_INFO, "cvs call failed");
m_pLastCvsCallDir = NULL;
setStatusText(tr("Cvs call failed"),2000);
if (instance) {
instance->afterCall( cmd, m_pCvsBuffer, true);
}
}
//----------------------------------------------------------------------------
void CvsControl::cvsCommandFinished() {
// qDebug("-->"+m_pCvsBuffer->readAll()+"<--");
if (!globalStopAction) {
finishInteractiveCmd();
} else {
m_pMessages->append("\n" + tr("Action interrupted by user!") + "\n");
finishInteractiveCmd();
}
}
//----------------------------------------------------------------------------
void CvsControl::handleMessage(MESSAGE m) {
m_pPixmapTimer->slotStop();
setStatusText(tr("waiting for your answer ..."));
switch( m.type) {
case CVS_Y_N: {
blockGUI(false);
if (showYesNoQuestion(tr("cvs asks:"), m.request + "\n\n") ) {
m.reply = "y\n\0";
m_pInteractiveCmdThread->sendReply( m);
} else {
m.reply = "n\n\0";
m_pInteractiveCmdThread->sendReply( m);
}
blockGUI(true);
break;
}
default: {
Debug::g_pLog->log(Debug::LL_THE_OLD_MAN_AND_THE_SEA,"unknown cvs message to handle: ->"+m.request+"<-");
break;
}
}
m_pPixmapTimer->slotStart();
setStatusText(tr("Operation in progress. Please wait ..."));
}
//----------------------------------------------------------------------------
void CvsControl::finishInteractiveCmd() {
CommandInterface *afterCallInstance = m_pInteractiveCmdThread->getInstance();
int cmd = m_pInteractiveCmdThread->getCommand();
bool callFailed = !m_interactiveCmdThreadIsRunning;
m_interactiveCmdThreadIsRunning = false;
if (m_pLastCvsCallDir) {
QDateTime t = QDateTime::currentDateTime();
m_pLastCvsCallDir->setCallTime(t);
m_pLastCvsCallDir = NULL;
}
if ( Debug::g_logLevel >= Debug::LL_INFO) {
QString str;
QTextStream stream(&str,IO_WriteOnly);
fillCmdDebugStream(stream);
Debug::g_pLog->log(Debug::LL_INFO, str);
}
if (afterCallInstance) {
m_chainedCommand = true;
afterCallInstance->afterCall(cmd,m_pCvsBuffer,callFailed);
afterCallInstance = NULL;
if (m_interactiveCmdThreadIsRunning) {// for loop commands, (i.e. commands calling another cvs command) don't continue
return;
} else {
m_chainedCommand = false;
}
} else {
Directory * dir = static_cast<Directory *>(m_pWorkBenchTree->selectedItem());
if (dir) {
slot_checkStatusOfTree(dir);
}
}
expurgateProjectSettings();
m_pPixmapTimer->slotStop();
globalStopAction = false;
blockGUI(false);
resumeDirWatch();
//set status info
DirBase * dir = m_pWorkBenchTree->selectedItem();
if (dir) {
setStatusText(dir->fullName());
}
setStatusText( tr("Ready"), 2000);
}
//----------------------------------------------------------------------------
void CvsControl::afterCall(int cmd,CvsBuffer*,bool failed) {
switch(cmd) {
case CVS_GET_TAG_INFO_PROJECT_CMD: {
if (failed) {
emit tagListFetched();
return;
}
QStringList projectTagList;
projectSettings->get(m_pFetchTagDir->topControlledDir()->relativeName(),PROJECTTAGLIST,projectTagList);
m_pFetchTagDir->parseCallResult( m_pCvsBuffer, cmd, &projectTagList);
projectTagList.sort();
projectSettings->set(m_pFetchTagDir->topControlledDir()->relativeName(),PROJECTTAGLIST,projectTagList);
emit tagListFetched();
m_pFetchTagDir = NULL;
break;
}
case CVS_GET_TAG_INFO_FILES_CMD: {
if (failed) {
emit tagListFetched();
return;
}
m_pFetchTagDir->parseCallResult( m_pCvsBuffer, cmd, &m_currentTagList);
m_currentTagList.sort();
//now add to projectTagList
if (!m_currentTagList.isEmpty()) {
QStringList projectTagList;
projectSettings->get(m_pFetchTagDir->topControlledDir()->relativeName(),PROJECTTAGLIST,projectTagList);
for (QStringList::Iterator it=m_currentTagList.begin(); it != m_currentTagList.end(); ++it) {
if (projectTagList.find(*it) == projectTagList.end()) {
projectTagList.append(*it);
}
}
projectTagList.sort();
projectSettings->set(m_pFetchTagDir->topControlledDir()->relativeName(),PROJECTTAGLIST,projectTagList);
}
emit tagListFetched();
m_pFetchTagDir = NULL;
break;
}
default: {
Debug::g_pLog->log(Debug::LL_THE_OLD_MAN_AND_THE_SEA,"there is no afterCall implemented for cmd id: "+QString::number(cmd));
}
}
}
//----------------------------------------------------------------------------
syntax highlighted by Code2HTML, v. 0.9.1