You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/vcs/perforce/perforcepart.cpp

365 lines
12 KiB

/***************************************************************************
* Copyright (C) 1999-2001 by Bernd Gehrmann *
* bernd@kdevelop.org *
* Extended 2002 by Harald Fernengel <harry@kdevelop.org> *
* *
* 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; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "perforcepart.h"
#include <tqfileinfo.h>
#include <tqpopupmenu.h>
#include <tqregexp.h>
#include <kpopupmenu.h>
#include <kdebug.h>
#include <kdevgenericfactory.h>
#include <kprocess.h>
#include <kmessagebox.h>
#include <kapplication.h>
#include <kaction.h>
#include <kurl.h>
#include <kparts/part.h>
#include "kdevpartcontroller.h"
#include "kdevcore.h"
#include "kdevmakefrontend.h"
#include "kdevdifffrontend.h"
#include "kdevplugininfo.h"
#include "commitdlg.h"
#include "execcommand.h"
static const KDevPluginInfo data("kdevperforce");
typedef KDevGenericFactory<PerforcePart> PerforceFactory;
K_EXPORT_COMPONENT_FACTORY( libkdevperforce, PerforceFactory( data ) )
PerforcePart::PerforcePart( TQObject *parent, const char *name, const TQStringList & )
: KDevVersionControl( &data, parent, name ? name : "PerforcePart" )
{
setInstance(PerforceFactory::instance());
setupActions();
connect( core(), TQT_SIGNAL(contextMenu(TQPopupMenu *, const Context *)),
this, TQT_SLOT(contextMenu(TQPopupMenu *, const Context *)) );
}
PerforcePart::~PerforcePart()
{}
void PerforcePart::setupActions()
{
actionEdit = new KAction( i18n("Edit"), 0, this, TQT_SLOT(slotActionEdit()),
actionCollection(), "perforce_edit" );
actionEdit->setToolTip(i18n("Edit"));
actionEdit->setWhatsThis(i18n("<b>Edit</b><p>Opens file(s) in a client workspace for edit."));
actionRevert = new KAction( i18n("Revert"), 0, this, TQT_SLOT(slotActionRevert()),
actionCollection(), "perforce_revert" );
actionRevert->setToolTip(i18n("Revert"));
actionRevert->setWhatsThis(i18n("<b>Revert</b><p>Discards changes made to open files."));
actionSubmit = new KAction( i18n("Submit"), 0, this, TQT_SLOT(slotActionCommit()),
actionCollection(), "perforce_submit" );
actionSubmit->setToolTip(i18n("Submit"));
actionSubmit->setWhatsThis(i18n("<b>Submit</b><p>Sends changes made to open files to the depot."));
actionSync = new KAction( i18n("Sync"), 0, this, TQT_SLOT(slotActionUpdate()),
actionCollection(), "perforce_sync" );
actionSync->setToolTip(i18n("Sync"));
actionSync->setWhatsThis(i18n("<b>Sync</b><p>Copies files from the depot into the workspace."));
actionDiff = new KAction( i18n("Diff Against Repository"), 0, this, TQT_SLOT(slotActionDiff()),
actionCollection(), "perforce_diff" );
actionDiff->setToolTip(i18n("Diff against repository"));
actionDiff->setWhatsThis(i18n("<b>Diff against repository</b><p>Compares a client workspace file to a revision in the depot."));
actionAdd = new KAction( i18n("Add to Repository"), 0, this, TQT_SLOT(slotActionAdd()),
actionCollection(), "perforce_add" );
actionAdd->setToolTip(i18n("Add to repository"));
actionAdd->setWhatsThis(i18n("<b>Add to repository</b><p>Open file(s) in a client workspace for addition to the depot."));
actionRemove = new KAction( i18n("Remove From Repository"), 0, this, TQT_SLOT(slotActionRemove()),
actionCollection(), "perforce_remove" );
actionRemove->setToolTip(i18n("Remove from repository"));
actionRemove->setWhatsThis(i18n("<b>Remove from repository</b><p>Open file(s) in a client workspace for deletion from the depot."));
}
void PerforcePart::contextMenu(TQPopupMenu *popup, const Context *context)
{
if (context->hasType( Context::FileContext )) {
const FileContext *fcontext = static_cast<const FileContext*>(context);
popupfile = fcontext->urls().first().path();
TQFileInfo fi( popupfile );
popup->insertSeparator();
KPopupMenu *sub = new KPopupMenu(popup);
TQString name = fi.fileName();
sub->insertTitle( i18n("Actions for %1").arg(name) );
int id = sub->insertItem( i18n("Edit"),
this, TQT_SLOT(slotEdit()) );
sub->setWhatsThis(id, i18n("<b>Edit</b><p>Opens file(s) in a client workspace for edit."));
id = sub->insertItem( i18n("Revert"),
this, TQT_SLOT(slotRevert()) );
sub->setWhatsThis(id, i18n("<b>Revert</b><p>Discards changes made to open files."));
id = sub->insertItem( i18n("Submit"),
this, TQT_SLOT(slotCommit()) );
sub->setWhatsThis(id, i18n("<b>Submit</b><p>Sends changes made to open files to the depot."));
id = sub->insertItem( i18n("Sync"),
this, TQT_SLOT(slotUpdate()) );
sub->setWhatsThis(id, i18n("<b>Sync</b><p>Copies files from the depot into the workspace."));
sub->insertSeparator();
id = sub->insertItem( i18n("Diff Against Repository"),
this, TQT_SLOT(slotDiff()) );
sub->setWhatsThis(id, i18n("<b>Diff against repository</b><p>Compares a client workspace file to a revision in the depot."));
id = sub->insertItem( i18n("Add to Repository"),
this, TQT_SLOT(slotAdd()) );
sub->setWhatsThis(id, i18n("<b>Add to repository</b><p>Open file(s) in a client workspace for addition to the depot."));
id = sub->insertItem( i18n("Remove From Repository"),
this, TQT_SLOT(slotRemove()) );
sub->setWhatsThis(id, i18n("<b>Remove from repository</b><p>Open file(s) in a client workspace for deletion from the depot."));
id = popup->insertItem(i18n("Perforce"), sub);
}
}
void PerforcePart::execCommand( const TQString& cmd, const TQString& filename )
{
if ( filename.isEmpty() )
return;
TQFileInfo fi( filename );
if (fi.isDir()) {
KMessageBox::error( 0, i18n("Cannot handle directories, please select single files") );
return;
}
TQString dir = fi.dirPath();
TQString name = fi.fileName();
TQString command("cd ");
command += KProcess::quote(dir);
command += " && p4 " + cmd + " ";
command += name;
if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
makeFrontend->queueCommand(dir, command);
}
void PerforcePart::edit( const TQString& filename )
{
execCommand( "edit", filename );
}
void PerforcePart::revert( const TQString& filename )
{
if ( KMessageBox::questionYesNo( 0,
i18n("Do you really want to revert "
"the file %1 and lose all your changes?").arg( filename ), TQString::null, i18n("Revert"), i18n("Do Not Revert") ) == KMessageBox::Yes ) {
execCommand( "revert", filename );
}
}
void PerforcePart::commit( const TQString& filename )
{
if ( filename.isEmpty() )
return;
TQFileInfo fi( filename );
if ( fi.isDir() ) {
KMessageBox::error( 0, i18n("Submitting of subdirectories is not supported") );
return;
}
CommitDialog d;
TQStringList lst;
lst << filename;
d.setFiles( lst );
if (d.exec() == TQDialog::Rejected)
return;
TQString message = d.changeList();
if (!message.isEmpty())
message = KShellProcess::quote(message);
TQString command("echo " + message);
command += " | p4 submit -i";
if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
makeFrontend->queueCommand("", command);
}
void PerforcePart::update( const TQString& filename )
{
if ( filename.isEmpty() )
return;
TQString dir, name;
TQFileInfo fi( filename );
if (fi.isDir()) {
dir = fi.absFilePath();
name = "..."; // three dots means "recoursive"
} else {
dir = fi.dirPath();
name = fi.fileName();
}
TQString command("cd ");
command += KProcess::quote(dir);
command += " && p4 sync ";
command += name;
if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
makeFrontend->queueCommand(dir, command);
}
void PerforcePart::add( const TQString& filename )
{
execCommand( "add", filename );
}
void PerforcePart::remove( const TQString& filename )
{
execCommand( "delete", filename );
}
void PerforcePart::diff( const TQString& filename )
{
if ( filename.isEmpty() )
return;
TQString name;
TQFileInfo fi( filename );
if ( fi.isDir() ) {
name = fi.absFilePath() + "...";
} else {
name = filename;
}
TQStringList args;
args << "diff";
args << "-du";
args << name;
ExecCommand* cmv = new ExecCommand( "p4", args, TQString::null, TQStringList(), this );
connect( cmv, TQT_SIGNAL(finished( const TQString&, const TQString& )),
this, TQT_SLOT(slotDiffFinished( const TQString&, const TQString& )) );
}
void PerforcePart::slotDiffFinished( const TQString& diff, const TQString& err )
{
if ( diff.isNull() && err.isNull() ) {
kdDebug(9000) << "p4 diff cancelled" << endl;
return; // user pressed cancel or an error occured
}
if ( diff.isEmpty() && !err.isEmpty() ) {
KMessageBox::detailedError( 0, i18n("P4 output errors during diff."), err, i18n("Errors During Diff") );
return;
}
if ( !err.isEmpty() ) {
int s = KMessageBox::warningContinueCancelList( 0, i18n("P4 output errors during diff. Do you still want to continue?"),
TQStringList::split( "\n", err, false ), i18n("Errors During Diff") );
if ( s != KMessageBox::Continue )
return;
}
if ( diff.isEmpty() ) {
KMessageBox::information( 0, i18n("There is no difference to the repository."), i18n("No Differences Found") );
return;
}
// strip the ==== headers
static TQRegExp rx( "(^|\\n)==== ([^ ]+) -.*====\\n" );
rx.setMinimal( true );
TQString strippedDiff = diff;
strippedDiff.replace( rx, "--- \\2\n+++ \\2\n" );
if (KDevDiffFrontend *diffFrontend = extension<KDevDiffFrontend>("KDevelop/DiffFrontend"))
diffFrontend->showDiff( strippedDiff );
}
TQString PerforcePart::currentFile()
{
KParts::ReadOnlyPart *part = dynamic_cast<KParts::ReadOnlyPart*>( partController()->activePart() );
if ( part ) {
KURL url = part->url();
if ( url.isLocalFile() )
return url.path();
}
return TQString::null;
}
void PerforcePart::slotActionCommit()
{
commit( currentFile() );
}
void PerforcePart::slotActionUpdate()
{
update( currentFile() );
}
void PerforcePart::slotActionAdd()
{
add( currentFile() );
}
void PerforcePart::slotActionRemove()
{
remove( currentFile() );
}
void PerforcePart::slotActionEdit()
{
edit( currentFile() );
}
void PerforcePart::slotActionRevert()
{
revert( currentFile() );
}
void PerforcePart::slotActionDiff()
{
diff( currentFile() );
}
void PerforcePart::slotCommit()
{
commit( popupfile );
}
void PerforcePart::slotUpdate()
{
update( popupfile );
}
void PerforcePart::slotAdd()
{
add( popupfile );
}
void PerforcePart::slotRemove()
{
remove( popupfile );
}
void PerforcePart::slotEdit()
{
edit( popupfile );
}
void PerforcePart::slotRevert()
{
revert( popupfile );
}
void PerforcePart::slotDiff()
{
diff( popupfile );
}
#include "perforcepart.moc"