00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
#include "perforcepart.h"
00014
00015
#include <qfileinfo.h>
00016
#include <qpopupmenu.h>
00017
#include <qregexp.h>
00018
#include <kpopupmenu.h>
00019
#include <kdebug.h>
00020
#include <kdevgenericfactory.h>
00021
#include <klocale.h>
00022
#include <kprocess.h>
00023
#include <kmessagebox.h>
00024
#include <kapplication.h>
00025
#include <kaction.h>
00026
#include <kurl.h>
00027
#include <kparts/part.h>
00028
00029
#include "kdevpartcontroller.h"
00030
#include "kdevcore.h"
00031
#include "kdevmakefrontend.h"
00032
#include "kdevdifffrontend.h"
00033
#include "commitdlg.h"
00034
#include "execcommand.h"
00035
00036
static const KAboutData data(
"kdevperforce",
I18N_NOOP(
"Perforce"),
"1.0");
00037
00038 typedef KDevGenericFactory<PerforcePart> PerforceFactory;
00039 K_EXPORT_COMPONENT_FACTORY( libkdevperforce,
PerforceFactory( &data ) )
00040
00041
PerforcePart::
PerforcePart(
QObject *parent, const
char *name, const
QStringList & )
00042 :
KDevPlugin( "Perforce", "perforce", parent, name ? name : "
PerforcePart" )
00043 {
00044 setInstance(PerforceFactory::instance());
00045 setXMLFile(
"kdevperforcepart.rc" );
00046
00047 setupActions();
00048
00049 connect( core(), SIGNAL(contextMenu(
QPopupMenu *,
const Context *)),
00050
this, SLOT(contextMenu(
QPopupMenu *,
const Context *)) );
00051 }
00052
00053
00054 PerforcePart::~PerforcePart()
00055 {}
00056
00057 void PerforcePart::setupActions()
00058 {
00059
actionEdit =
new KAction( i18n(
"Edit"), 0,
this, SLOT(
slotActionEdit()),
00060
actionCollection(),
"perforce_edit" );
00061
actionEdit->
setToolTip(i18n(
"Edit"));
00062
actionEdit->
setWhatsThis(i18n(
"<b>Edit</b><p>Opens file(s) in a client workspace for edit."));
00063
actionRevert =
new KAction( i18n(
"Revert"), 0,
this, SLOT(
slotActionRevert()),
00064
actionCollection(),
"perforce_revert" );
00065
actionRevert->
setToolTip(i18n(
"Revert"));
00066
actionRevert->
setWhatsThis(i18n(
"<b>Revert</b><p>Discards changes made to open files."));
00067
actionSubmit =
new KAction( i18n(
"Submit"), 0,
this, SLOT(
slotActionCommit()),
00068
actionCollection(),
"perforce_submit" );
00069
actionSubmit->
setToolTip(i18n(
"Submit"));
00070
actionSubmit->
setWhatsThis(i18n(
"<b>Submit</b><p>Sends changes made to open files to the depot."));
00071
actionSync =
new KAction( i18n(
"Sync"), 0,
this, SLOT(
slotActionUpdate()),
00072
actionCollection(),
"perforce_sync" );
00073
actionSync->
setToolTip(i18n(
"Sync"));
00074
actionSync->
setWhatsThis(i18n(
"<b>Sync</b><p>Copies files from the depot into the workspace."));
00075
actionDiff =
new KAction( i18n(
"Diff Against Repository"), 0,
this, SLOT(
slotActionDiff()),
00076
actionCollection(),
"perforce_diff" );
00077
actionDiff->
setToolTip(i18n(
"Diff against repository"));
00078
actionDiff->
setWhatsThis(i18n(
"<b>Diff against repository</b><p>Compares a client workspace file to a revision in the depot."));
00079
actionAdd =
new KAction( i18n(
"Add to Repository"), 0,
this, SLOT(
slotActionAdd()),
00080
actionCollection(),
"perforce_add" );
00081
actionAdd->
setToolTip(i18n(
"Add to repository"));
00082
actionAdd->
setWhatsThis(i18n(
"<b>Add to repository</b><p>Open file(s) in a client workspace for addition to the depot."));
00083
actionRemove =
new KAction( i18n(
"Remove From Repository"), 0,
this, SLOT(
slotActionRemove()),
00084
actionCollection(),
"perforce_remove" );
00085
actionRemove->
setToolTip(i18n(
"Remove from repository"));
00086
actionRemove->
setWhatsThis(i18n(
"<b>Remove from repository</b><p>Open file(s) in a client workspace for deletion from the depot."));
00087 }
00088
00089 void PerforcePart::contextMenu(
QPopupMenu *popup,
const Context *context)
00090 {
00091
if (context->
hasType( Context::FileContext )) {
00092
const FileContext *fcontext = static_cast<const FileContext*>(context);
00093
popupfile = fcontext->
fileName();
00094
QFileInfo fi(
popupfile );
00095 popup->insertSeparator();
00096
00097
KPopupMenu *sub =
new KPopupMenu(popup);
00098
QString name = fi.fileName();
00099 sub->
insertTitle( i18n(
"Actions for %1").arg(name) );
00100
00101
int id = sub->insertItem( i18n(
"Edit"),
00102
this, SLOT(
slotEdit()) );
00103 sub->setWhatsThis(
id, i18n(
"<b>Edit</b><p>Opens file(s) in a client workspace for edit."));
00104
id = sub->insertItem( i18n(
"Revert"),
00105
this, SLOT(
slotRevert()) );
00106 sub->setWhatsThis(
id, i18n(
"<b>Revert</b><p>Discards changes made to open files."));
00107
id = sub->insertItem( i18n(
"Submit"),
00108
this, SLOT(
slotCommit()) );
00109 sub->setWhatsThis(
id, i18n(
"<b>Submit</b><p>Sends changes made to open files to the depot."));
00110
id = sub->insertItem( i18n(
"Sync"),
00111
this, SLOT(
slotUpdate()) );
00112 sub->setWhatsThis(
id, i18n(
"<b>Sync</b><p>Copies files from the depot into the workspace."));
00113 sub->insertSeparator();
00114
id = sub->insertItem( i18n(
"Diff Against Repository"),
00115
this, SLOT(
slotDiff()) );
00116 sub->setWhatsThis(
id, i18n(
"<b>Diff against repository</b><p>Compares a client workspace file to a revision in the depot."));
00117
id = sub->insertItem( i18n(
"Add to Repository"),
00118
this, SLOT(
slotAdd()) );
00119 sub->setWhatsThis(
id, i18n(
"<b>Add to repository</b><p>Open file(s) in a client workspace for addition to the depot."));
00120
id = sub->insertItem( i18n(
"Remove From Repository"),
00121
this, SLOT(
slotRemove()) );
00122 sub->setWhatsThis(
id, i18n(
"<b>Remove from repository</b><p>Open file(s) in a client workspace for deletion from the depot."));
00123
id = popup->insertItem(i18n(
"Perforce"), sub);
00124 }
00125 }
00126
00127 void PerforcePart::execCommand(
const QString& cmd,
const QString& filename )
00128 {
00129
if ( filename.isEmpty() )
00130
return;
00131
00132
QFileInfo fi( filename );
00133
if (fi.isDir()) {
00134 KMessageBox::error( 0, i18n(
"Cannot handle directories, please select single files") );
00135
return;
00136 }
00137
QString dir = fi.dirPath();
00138
QString name = fi.fileName();
00139
00140
QString command(
"cd ");
00141 command += dir;
00142 command +=
" && p4 " + cmd +
" ";
00143 command += name;
00144
00145
makeFrontend()->
queueCommand(dir, command);
00146 }
00147
00148 void PerforcePart::edit(
const QString& filename )
00149 {
00150
execCommand(
"edit", filename );
00151 }
00152
00153 void PerforcePart::revert(
const QString& filename )
00154 {
00155
if ( KMessageBox::questionYesNo( 0,
00156 i18n(
"Do you really want to revert "
00157
"the file %1 and lose all your changes?").arg( filename ) ) == KMessageBox::Yes ) {
00158
execCommand(
"revert", filename );
00159 }
00160 }
00161
00162 void PerforcePart::commit(
const QString& filename )
00163 {
00164
if ( filename.isEmpty() )
00165
return;
00166
00167
QFileInfo fi( filename );
00168
if ( fi.isDir() ) {
00169 KMessageBox::error( 0, i18n(
"Submitting of subdirectories is not supported") );
00170
return;
00171 }
00172
00173
CommitDialog d;
00174
QStringList lst;
00175 lst << filename;
00176 d.
setFiles( lst );
00177
if (d.exec() == QDialog::Rejected)
00178
return;
00179
00180
QString message = d.
changeList();
00181
if (!
message.isEmpty())
00182
message = KShellProcess::quote(
message);
00183
00184
QString command(
"echo " +
message);
00185 command +=
" | p4 submit -i";
00186
00187
makeFrontend()->
queueCommand(
"", command);
00188 }
00189
00190
00191 void PerforcePart::update(
const QString& filename )
00192 {
00193
if ( filename.isEmpty() )
00194
return;
00195
00196
QString dir, name;
00197
QFileInfo fi( filename );
00198
if (fi.isDir()) {
00199 dir = fi.absFilePath();
00200 name =
"...";
00201 }
else {
00202 dir = fi.dirPath();
00203 name = fi.fileName();
00204 }
00205
00206
QString command(
"cd ");
00207 command += dir;
00208 command +=
" && p4 sync ";
00209 command += name;
00210
00211
makeFrontend()->
queueCommand(dir, command);
00212 }
00213
00214
00215 void PerforcePart::add(
const QString& filename )
00216 {
00217
execCommand(
"add", filename );
00218 }
00219
00220
00221 void PerforcePart::remove(
const QString& filename )
00222 {
00223
execCommand(
"delete", filename );
00224 }
00225
00226 void PerforcePart::diff(
const QString& filename )
00227 {
00228
if ( filename.isEmpty() )
00229
return;
00230
00231
QString name;
00232
QFileInfo fi( filename );
00233
00234
if ( fi.isDir() ) {
00235 name = fi.absFilePath() +
"...";
00236 }
else {
00237 name = filename;
00238 }
00239
QStringList args;
00240
00241 args <<
"diff";
00242 args << name;
00243
ExecCommand* cmv =
new ExecCommand(
"p4", args, QString::null,
QStringList(),
this );
00244 connect( cmv, SIGNAL(finished(
const QString&,
const QString& )),
00245
this, SLOT(
slotDiffFinished(
const QString&,
const QString& )) );
00246 }
00247
00248 void PerforcePart::slotDiffFinished(
const QString& diff,
const QString& err )
00249 {
00250
if ( diff.isNull() && err.isNull() ) {
00251
kdDebug(9000) <<
"p4 diff cancelled" <<
endl;
00252
return;
00253 }
00254
00255
if ( diff.isEmpty() && !err.isEmpty() ) {
00256 KMessageBox::detailedError( 0, i18n(
"P4 outputted errors during diff."), err, i18n(
"Errors During Diff") );
00257
return;
00258 }
00259
00260
if ( !err.isEmpty() ) {
00261
int s = KMessageBox::warningContinueCancelList( 0, i18n(
"P4 outputted errors during diff. Do you still want to continue?"),
00262 QStringList::split(
"\n", err,
false ), i18n(
"Errors During Diff") );
00263
if ( s != KMessageBox::Continue )
00264
return;
00265 }
00266
00267
if ( diff.isEmpty() ) {
00268 KMessageBox::information( 0, i18n(
"There is no difference to the repository."), i18n(
"No Differences Found") );
00269
return;
00270 }
00271
00272
00273
static QRegExp rx(
"(^|\\n)====.*====\\n" );
00274 rx.setMinimal(
true );
00275
QString strippedDiff = diff;
00276 strippedDiff.replace( rx, QString::null );
00277
00278 Q_ASSERT(
diffFrontend() );
00279
diffFrontend()->
showDiff( strippedDiff );
00280 }
00281
00282 QString PerforcePart::currentFile()
00283 {
00284
KParts::ReadOnlyPart *part = dynamic_cast<KParts::ReadOnlyPart*>(
partController()->
activePart() );
00285
if ( part ) {
00286
KURL url = part->
url();
00287
if ( url.
isLocalFile() )
00288
return url.
path();
00289 }
00290
return QString::null;
00291 }
00292
00293 void PerforcePart::slotActionCommit()
00294 {
00295
commit(
currentFile() );
00296 }
00297
00298 void PerforcePart::slotActionUpdate()
00299 {
00300
update(
currentFile() );
00301 }
00302 void PerforcePart::slotActionAdd()
00303 {
00304
add(
currentFile() );
00305 }
00306
00307 void PerforcePart::slotActionRemove()
00308 {
00309
remove(
currentFile() );
00310 }
00311
00312 void PerforcePart::slotActionEdit()
00313 {
00314
edit(
currentFile() );
00315 }
00316
00317 void PerforcePart::slotActionRevert()
00318 {
00319
revert(
currentFile() );
00320 }
00321
00322 void PerforcePart::slotActionDiff()
00323 {
00324
diff(
currentFile() );
00325 }
00326
00327 void PerforcePart::slotCommit()
00328 {
00329
commit(
popupfile );
00330 }
00331
00332 void PerforcePart::slotUpdate()
00333 {
00334
update(
popupfile );
00335 }
00336
00337 void PerforcePart::slotAdd()
00338 {
00339
add(
popupfile );
00340 }
00341
00342 void PerforcePart::slotRemove()
00343 {
00344
remove(
popupfile );
00345 }
00346
00347 void PerforcePart::slotEdit()
00348 {
00349
edit(
popupfile );
00350 }
00351
00352 void PerforcePart::slotRevert()
00353 {
00354
revert(
popupfile );
00355 }
00356
00357 void PerforcePart::slotDiff()
00358 {
00359
diff(
popupfile );
00360 }
00361
00362
#include "perforcepart.moc"