/* Copyright (C) Sven Erik Knop, Perforce Software, 2009 * */ #include <windows.h> #include <time.h> #include <clientapi.h> #include <i18napi.h> #include <strtable.h> #include <enviro.h> #include "PerforceClient.h" #include "PluginInterface.h" extern NppData nppData; PerforceClient::PerforceClient( ) { TCHAR path[MAX_PATH]; ::SendMessage(nppData._nppHandle, NPPM_GETCURRENTDIRECTORY, 0, (LPARAM) path); // Since this is a Unicode wchar, I need to convert it to ANSI first for Perforce char cwd[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, path, -1, cwd, MAX_PATH, NULL, NULL); enviro = new Enviro; enviro->Config( StrRef(cwd) ); const char *lc; if( ( lc = enviro->Get( "P4CHARSET" )) ) { CharSetApi::CharSet cs = CharSetApi::NOCONV; cs = CharSetApi::Lookup( lc ); if( cs >= 0 ) { client.SetTrans( cs, cs, cs, cs ); } } client.SetCwd( cwd ); Error e; client.Init( &e ); if ( e.Test() ) { except( "Connection failed.", &e ); } } PerforceClient::~PerforceClient() { Error e; client.Final( &e ); delete enviro; } void PerforceClient::except(const char *msg, Error *e) { StrBuf error; e->Fmt( &error ); StrBuf message; message << msg << "\n" << error; int length = MultiByteToWideChar(CP_ACP, 0, message.Text(), -1, NULL , 0); LPWSTR wmessage = new WCHAR[length]; (void) MultiByteToWideChar(CP_ACP, 0, message.Text(), -1, wmessage , length); ::MessageBox(nppData._nppHandle, wmessage, TEXT("Perforce error"), MB_OK); delete[] wmessage; } class OutputClient : public ClientUser { public: OutputClient() : error(false) { } virtual void OutputInfo( char level, const char *data ) { buf << data << "\n"; } virtual void OutputError( const char *errBuf ) { error = true; err << errBuf << "\n"; } virtual void OutputStat( StrDict *varList ) { StrRef var, val; for( int i = 0; varList->GetVar( i, var, val ); i++ ) { if( var == "func" || var == P4Tag::v_specFormatted ) continue; buf << var << " ... " << val << "\n"; dict.VSetVar(var, val); } } bool errorExists() const { return error; } const StrBuf& getError() const { return err; } const StrBuf& getBuf() const { return buf; } StrDict& getDict() { return dict; } private: bool error; StrBuf err; StrBuf buf; StrBufDict dict; }; void PerforceClient::showInfo() { OutputClient cu; client.Run("info", &cu); displayMessage(TEXT("Perforce connection info"), cu.getBuf()); } void PerforceClient::callP4V(const char * cmd) { TCHAR path[MAX_PATH]; ::SendMessage(nppData._nppHandle, NPPM_GETFULLCURRENTPATH, 0, (LPARAM)path); char file[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, path, -1, file, MAX_PATH, NULL, NULL); StrBuf cmdLine("p4v.exe"); cmdLine << " -p " << client.GetPort(); cmdLine << " -c " << client.GetClient(); cmdLine << " -u " << client.GetUser(); if( client.GetCharset().Length() ) { cmdLine << " -C " << client.GetCharset(); } if ( client.GetPassword().Length() ) { cmdLine << " -P " << client.GetPassword(); } cmdLine << " -cmd \"" << cmd; cmdLine << " " << file << "\""; // OK, here we actually are going to call P4V. PROCESS_INFORMATION procInfo; STARTUPINFO startInfo; GetStartupInfo( &startInfo ); startInfo.lpReserved = startInfo.lpDesktop = NULL; startInfo.dwFlags |= STARTF_USESHOWWINDOW; startInfo.wShowWindow = SW_SHOWNORMAL; int length = MultiByteToWideChar(CP_ACP, 0, cmdLine.Text(), -1, NULL , 0); LPWSTR cmdString = new WCHAR[length]; (void) MultiByteToWideChar(CP_ACP, 0, cmdLine.Text(), -1, cmdString , length); CreateProcess( NULL, cmdString, //da command NULL, NULL, //evil windows "security" stuff FALSE, NORMAL_PRIORITY_CLASS,//inheritance & creation flags NULL, NULL, //default env and current dir &startInfo, &procInfo ); CloseHandle( procInfo.hThread ); } void PerforceClient::showFileInfo() { TCHAR path[MAX_PATH]; ::SendMessage(nppData._nppHandle, NPPM_GETFULLCURRENTPATH, 0, (LPARAM)path); char file[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, path, -1, file, MAX_PATH, NULL, NULL); int argc = 2; char * argv[] = { "-l", file }; client.SetArgv( argc, argv ); OutputClient ui; // client.SetVar( P4Tag::v_tag ); client.Run("fstat", &ui); if( ui.errorExists() ) { displayMessage(TEXT("Perforce error"), ui.getError()); return; } StrBuf buf; StrDict &dict = ui.getDict(); if( dict.GetVar("depotFile") ) { buf << "Depot File :\t" << dict.GetVar("depotFile") << "\n"; buf << "Client File :\t" << dict.GetVar("clientFile") << "\n"; if( dict.GetVar("haveRev") && dict.GetVar("headRev") ) { buf << "Revision : \t\t#" << dict.GetVar("haveRev") << " of " << dict.GetVar("headRev") << "\n"; } else { buf << "Revision : \t\t#0/0\n"; } buf << "Change : \t\t" << dict.GetVar("headChange") << "\n"; const size_t MAX_DATE = 128; char dateBuffer[MAX_DATE]; time_t rawtime = dict.GetVar("headTime")->Atoi(); struct tm * timeinfo = localtime( &rawtime ); strftime(dateBuffer, MAX_DATE, "%#c", timeinfo); buf << "Last changed : \t" << dateBuffer << "\n"; buf << "Type : \t\t" << dict.GetVar("headType") << "\n"; if( dict.GetVar("fileSize") ) { buf << "File size : \t\t" << dict.GetVar("fileSize") << "\n"; } StrBuf openBy("Opened by "); if( dict.GetVar("action") ) { buf << "\nOpen for " << dict.GetVar("action") << " - change " << dict.GetVar("change") << " (" << dict.GetVar("type") << ")\n"; openBy = "\tAlso opened by "; } if( dict.GetVar("otherOpen") ) { int otherOpen = atoi(dict.GetVar("otherOpen")->Text()); buf << "\n"; for( int i = 0; i < otherOpen; i++) { StrBuf name("otherOpen"); StrBuf action("otherAction"); name << i; action << i; buf << openBy << dict.GetVar(name) << " for " << dict.GetVar(action) << "\n"; } } } else { buf << "Not stored in Perforce"; } displayMessage(TEXT("Perforce file info"), buf /*ui.getBuf() */); } void PerforceClient::processFile(const char *cmd) { TCHAR path[MAX_PATH]; ::SendMessage(nppData._nppHandle, NPPM_GETFULLCURRENTPATH, 0, (LPARAM)path); char file[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, path, -1, file, MAX_PATH, NULL, NULL); int argc = 1; char * argv[] = { file }; client.SetArgv( argc, argv ); OutputClient ui; client.Run( cmd, &ui ); if( ui.errorExists() ) { displayMessage(TEXT("Perforce error"), ui.getError()); } //if( !strcmp(cmd, "sync") ) { // int currentBufferId = ::SendMessage(nppData._nppHandle, NPPM_GETCURRENTBUFFERID, 0, 0); // (void) ::SendMessage(nppData._nppHandle, NPPM_RELOADBUFFERID, currentBufferId, 0); //} //else { // refresh Notepad++ - currently a hack ::SendMessage(nppData._nppHandle, NPPMSG + 53, TRUE, 0); //} } bool PerforceClient::displayMessage(LPWSTR title, const StrRef &buf, bool allowCancel) { UINT type = allowCancel ? MB_OKCANCEL : MB_OK; int length = MultiByteToWideChar(CP_ACP, 0, buf.Text(), -1, NULL , 0); LPWSTR wmessage = new WCHAR[length]; (void) MultiByteToWideChar(CP_ACP, 0, buf.Text(), -1, wmessage , length); int result = ::MessageBox(nppData._nppHandle, wmessage, title, type); delete[] wmessage; return (result == IDOK); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#13 | 11396 | Sven Erik Knop |
Fixed login issue from file command (endless loop). Bumped version to 1.0.7 Final version in this iteration (I hope). |
||
#12 | 11391 | Sven Erik Knop | Added login status to connection info output. | ||
#11 | 11384 | Sven Erik Knop | Added logout menu item (more for testing than practical use) | ||
#10 | 11381 | Sven Erik Knop |
Added login dialog (after many years of waiting) Currently needs to log on in a separate step, next change should prompt for password if ticket expired in any case. Also fixed a bug with showing file information for freshly added files. |
||
#9 | 10986 | Sven Erik Knop |
Updated for new-style P4V. Now using P4VC (there is no more P4V -cmd). Currently only Revgraph, Timelapse View and Submit are supported. |
||
#8 | 7822 | Sven Erik Knop |
Preparations for log-in dialog. The dialog is written, but not hooked up yet, but all the parts compile and link. Error dialog now displays a different error text if the ticket has expired, in preparation for the next step. |
||
#7 | 7821 | Sven Erik Knop |
Small change to Notepad++ plugin: improved error handling, in that errors are actually printed out as errors. Especially important if the user's session has expired and the user needs to log on again. Next up: Login dialog. |
||
#6 | 7482 | Sven Erik Knop |
Added P4V support to the plugin. If p4v.exe is in the path, additional menu items become available. |
||
#5 | 7469 | Sven Erik Knop | Solved a problem with Unicode enabled servers. | ||
#4 | 7468 | Sven Erik Knop | Show the otherAction as well. | ||
#3 | 7467 | Sven Erik Knop |
Updated the file info one more time. Now it shows the last change date, the last change number and the fact that files are open in other workspaces even if they are not open in the local workspace. |
||
#2 | 7465 | Sven Erik Knop |
Updated the fstat output for the plugin. Now the file type of the head revision is shown as well. |
||
#1 | 7440 | Sven Erik Knop |
Notepad++ Perforce Plugin. The provided DLL will only work for the Unicode version of Notepad++. The code currently contains no provision for ASCII builds. The plugin can : Add Edit Delete Revert Sync (to head) --- Show file info Show connection info |