summaryrefslogtreecommitdiff
path: root/utils/vp4
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/vp4
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/vp4')
-rw-r--r--utils/vp4/main.cpp147
-rw-r--r--utils/vp4/stdafx.cpp7
-rw-r--r--utils/vp4/stdafx.h29
-rw-r--r--utils/vp4/vp4.vpc65
-rw-r--r--utils/vp4/vp4dialog.cpp498
-rw-r--r--utils/vp4/vp4dialog.h57
6 files changed, 803 insertions, 0 deletions
diff --git a/utils/vp4/main.cpp b/utils/vp4/main.cpp
new file mode 100644
index 0000000..d497573
--- /dev/null
+++ b/utils/vp4/main.cpp
@@ -0,0 +1,147 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#define NOWINRES
+#define NOSERVICE
+#define NOMCX
+#define NOIME
+#include <windows.h>
+
+#undef MessageBox
+#undef PostMessage
+
+#include "stdafx.h"
+#include "appframework/tier3app.h"
+#include "tier2/tier2.h"
+#include "inputsystem/iinputsystem.h"
+#include "vgui_controls/controls.h"
+
+// root panel
+vgui::Panel *g_pMainPanel = NULL;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds in any search paths
+//-----------------------------------------------------------------------------
+void AddFileSystemSearchPaths(const char *pszExeName)
+{
+ // search locally first
+ char pExeName[MAX_PATH];
+ if ( ::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), pExeName, sizeof(pExeName) ) )
+ {
+ char pPlatform[MAX_PATH];
+ Q_StripFilename( pExeName );
+ Q_snprintf( pPlatform, sizeof(pPlatform), "%s\\..\\platform", pExeName );
+ g_pFullFileSystem->AddSearchPath( pExeName, "EXECUTABLE_PATH");
+ g_pFullFileSystem->AddSearchPath( pPlatform, "PLATFORM");
+ g_pFullFileSystem->AddSearchPath( pPlatform, "SKIN");
+ }
+ else
+ {
+ g_pFullFileSystem->AddSearchPath(".", "EXECUTABLE_PATH");
+ g_pFullFileSystem->AddSearchPath("../platform/", "PLATFORM");
+ g_pFullFileSystem->AddSearchPath("../platform/", "SKIN");
+ }
+
+ // add self as a pack file
+// g_pFullFileSystem->AddPackFile(pszExeName, "PLATFORM");
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets up the main vgui
+//-----------------------------------------------------------------------------
+bool InitializeVGui( )
+{
+ // add in the search paths
+ AddFileSystemSearchPaths(NULL);
+
+ // Init the surface
+ g_pMainPanel = new vgui::Panel(NULL, NULL);
+ vgui::surface()->SetEmbeddedPanel( g_pMainPanel->GetVPanel() );
+
+ // load the scheme
+ g_pMainPanel->SetScheme( vgui::scheme()->LoadSchemeFromFile( "//PLATFORM/Resource/sourcescheme.res", "PLATFORM" ) );
+
+ // localization
+ g_pVGuiLocalize->AddFile( "Resource/platform_%language%.txt");
+ g_pVGuiLocalize->AddFile( "Resource/vgui_%language%.txt");
+
+ // configuration settings
+ vgui::system()->SetUserConfigFile( "vp4config.txt", "EXECUTABLE_PATH" );
+
+ // Start vgui
+ vgui::ivgui()->Start();
+
+ // finish setting up main panel
+ vgui::SETUP_PANEL( g_pMainPanel );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// The application object
+//-----------------------------------------------------------------------------
+class CVP4App : public CVguiSteamApp
+{
+public:
+ // Methods of IApplication
+ virtual bool Create();
+ virtual int Main();
+ virtual void Destroy() {}
+};
+
+DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT( CVP4App );
+
+
+//-----------------------------------------------------------------------------
+// The application object
+//-----------------------------------------------------------------------------
+bool CVP4App::Create()
+{
+ AppSystemInfo_t appSystems[] =
+ {
+ { "inputsystem.dll", INPUTSYSTEM_INTERFACE_VERSION },
+ { "vgui2.dll", VGUI_IVGUI_INTERFACE_VERSION },
+ { "p4lib.dll", P4_INTERFACE_VERSION },
+ { "", "" } // Required to terminate the list
+ };
+
+ return AddSystems( appSystems );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: program entrypoint
+//-----------------------------------------------------------------------------
+int CVP4App::Main()
+{
+ if ( !InitializeVGui( ) )
+ {
+ ::MessageBoxA( NULL, "Fatal Error: Could not initialize vgui.", "Steam - Fatal Error", MB_OK | MB_ICONERROR );
+ return 0;
+ }
+
+ // open the wizard
+ CVP4Dialog *dlg = SETUP_PANEL(new CVP4Dialog());
+ dlg->SetParent(g_pMainPanel);
+ dlg->Activate();
+
+ // run vgui
+ while (vgui::ivgui()->IsRunning())
+ {
+ vgui::ivgui()->RunFrame();
+ }
+
+ // save configuration
+ vgui::system()->SaveUserConfigFile();
+
+ // delete all the panels
+ delete g_pMainPanel;
+
+ return 0;
+}
diff --git a/utils/vp4/stdafx.cpp b/utils/vp4/stdafx.cpp
new file mode 100644
index 0000000..fedf041
--- /dev/null
+++ b/utils/vp4/stdafx.cpp
@@ -0,0 +1,7 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/utils/vp4/stdafx.h b/utils/vp4/stdafx.h
new file mode 100644
index 0000000..bec2aeb
--- /dev/null
+++ b/utils/vp4/stdafx.h
@@ -0,0 +1,29 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef STDAFX_H
+#define STDAFX_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "filesystem.h"
+#include "vgui/ILocalize.h"
+#include "vgui/IScheme.h"
+#include "vgui/ISurface.h"
+#include "vgui/ISystem.h"
+#include "vgui/IVGui.h"
+#include "vgui/Cursor.h"
+#include "vgui_controls/Controls.h"
+#include "vgui_controls/Panel.h"
+
+#include "p4lib/ip4.h"
+
+#include "vp4dialog.h"
+
+using namespace vgui;
+
+#endif // STDAFX_H
diff --git a/utils/vp4/vp4.vpc b/utils/vp4/vp4.vpc
new file mode 100644
index 0000000..a79fcb5
--- /dev/null
+++ b/utils/vp4/vp4.vpc
@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------------
+// VP4.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+
+$Include "$SRCDIR\vpc_scripts\source_exe_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $Create/UsePrecompiledHeader "Use Precompiled Header (/Yu)"
+ $PrecompiledHeaderFile "Debug/vp4.pch"
+ }
+}
+
+$Project "Vp4"
+{
+ $Folder "Source Files"
+ {
+ $File "vp4dialog.cpp"
+
+ $File "main.cpp" \
+ "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $Create/UsePrecompiledHeader "Not Using Precompiled Headers"
+ }
+ }
+ }
+
+ $File "stdafx.cpp"
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $Create/UsePrecompiledHeader "Create Precompiled Header (/Yc)"
+ }
+ }
+ }
+ }
+
+ $Folder "Header Files"
+ {
+ $File "stdafx.h"
+ $File "vp4dialog.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib appframework
+ $Lib tier3
+ $Lib tier2
+ $Lib vgui_controls
+ $Lib mathlib
+ }
+}
diff --git a/utils/vp4/vp4dialog.cpp b/utils/vp4/vp4dialog.cpp
new file mode 100644
index 0000000..38d66b1
--- /dev/null
+++ b/utils/vp4/vp4dialog.cpp
@@ -0,0 +1,498 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "stdafx.h"
+
+#include "vgui_controls/TreeView.h"
+#include "vgui_controls/ListPanel.h"
+#include "vgui_controls/SectionedListPanel.h"
+#include "vgui_controls/ComboBox.h"
+#include "vgui_controls/PropertySheet.h"
+#include "vgui_controls/PropertyPage.h"
+
+#include <ctype.h>
+
+using namespace vgui;
+extern IP4* p4;
+
+// list of all tree view icons
+enum
+{
+ IMAGE_FOLDER = 1,
+ IMAGE_OPENFOLDER,
+ IMAGE_FILE,
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles file view
+//-----------------------------------------------------------------------------
+class CFileTreeView : public TreeView
+{
+ DECLARE_CLASS_SIMPLE( CFileTreeView, TreeView );
+public:
+ CFileTreeView(Panel *parent, const char *name) : BaseClass(parent, name)
+ {
+ }
+
+ // override to incremental request and show p4 directories
+ virtual void GenerateChildrenOfNode(int itemIndex)
+ {
+ KeyValues *pkv = GetItemData(itemIndex);
+ if (!pkv->GetInt("dir"))
+ return;
+
+ const char *pFilePath = pkv->GetString("path", "");
+ if (!pFilePath[0])
+ return;
+
+ surface()->SetCursor(dc_waitarrow);
+ // get the list of files
+ CUtlVector<P4File_t> &files = p4->GetFileList(pFilePath);
+
+ // generate children
+ // add all the items
+ for (int i = 0; i < files.Count(); i++)
+ {
+ if (files[i].m_bDeleted)
+ continue;
+
+ KeyValues *kv = new KeyValues("node", "text", p4->String( files[i].m_sName ) );
+
+ if (files[i].m_bDir)
+ {
+ kv->SetInt("expand", 1);
+ kv->SetInt("dir", 1);
+ kv->SetInt("image", IMAGE_FOLDER);
+ }
+ else
+ {
+ kv->SetInt("image", IMAGE_FILE);
+ }
+
+ // get the files path
+ char szPath[MAX_PATH];
+ if (files[i].m_bDir)
+ {
+ Q_snprintf(szPath, sizeof(szPath), "%s/%s/%%%%1", p4->String( files[i].m_sPath ), p4->String( files[i].m_sName ) );
+ }
+ else
+ {
+ Q_snprintf(szPath, sizeof(szPath), "%s/%s", p4->String( files[i].m_sPath ), p4->String( files[i].m_sName ));
+ }
+
+ // translate the files path from a depot path into a local path
+ char szLocalPath[MAX_PATH];
+ p4->GetLocalFilePath(szLocalPath, szPath, sizeof(szLocalPath));
+ kv->SetString("path", szLocalPath);
+
+ // now change the items text to match the local paths file name...
+ char *pLocalName = Q_strrchr(szLocalPath, '\\');
+ if (pLocalName)
+ {
+ *pLocalName = 0;
+ ++pLocalName;
+ }
+ kv->SetString("text", pLocalName);
+
+ int itemID = AddItem(kv, itemIndex);
+
+ // mark out of date files in red
+ if (files[i].m_iHaveRevision < files[i].m_iHeadRevision)
+ {
+ SetItemFgColor(itemID, Color(255, 0, 0, 255));
+ }
+ }
+ }
+
+ // setup a context menu whenever a directory is clicked on
+ virtual void GenerateContextMenu( int itemIndex, int x, int y )
+ {
+ KeyValues *pkv = GetItemData(itemIndex);
+ const char *pFilePath = pkv->GetString("path", "");
+ if (!pFilePath[0])
+ return;
+
+ Menu *pContext = new Menu(this, "FileContext");
+
+ if (pkv->GetInt("dir"))
+ {
+ pContext->AddMenuItem("Cloak folder", new KeyValues("CloakFolder", "item", itemIndex), GetParent(), NULL);
+ }
+ else
+ {
+ pContext->AddMenuItem("Open for edit", new KeyValues("EditFile", "item", itemIndex), GetParent(), NULL);
+ pContext->AddMenuItem("Open for delete", new KeyValues("DeleteFile", "item", itemIndex), GetParent(), NULL);
+ }
+
+ // show the context menu
+ pContext->SetPos(x, y);
+ pContext->SetVisible(true);
+ }
+
+
+
+ // setup a smaller font
+ virtual void ApplySchemeSettings(IScheme *pScheme)
+ {
+ BaseClass::ApplySchemeSettings(pScheme);
+ SetFont( pScheme->GetFont("DefaultSmall") );
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Revision list
+//-----------------------------------------------------------------------------
+class CSmallTextListPanel : public ListPanel
+{
+ DECLARE_CLASS_SIMPLE( CSmallTextListPanel, ListPanel );
+public:
+ CSmallTextListPanel(Panel *parent, const char *name) : BaseClass(parent, name)
+ {
+ }
+
+ virtual void ApplySchemeSettings(IScheme *pScheme)
+ {
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ SetFont( pScheme->GetFont("DefaultSmall") );
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CVP4Dialog::CVP4Dialog() : BaseClass(NULL, "vp4dialog"), m_Images(false)
+{
+ SetSize(1024, 768);
+ SetTitle("VP4", true);
+
+ // clientspec selection
+ m_pClientCombo = new ComboBox(this, "ClientCombo", 16, false);
+
+ // file browser tree controls
+ m_pFileTree = new CFileTreeView(this, "FileTree");
+ // build our list of images
+ m_Images.AddImage(scheme()->GetImage("resource/icon_folder", false));
+ m_Images.AddImage(scheme()->GetImage("resource/icon_folder_selected", false));
+ m_Images.AddImage(scheme()->GetImage("resource/icon_file", false));
+ m_pFileTree->SetImageList(&m_Images, false);
+
+ // property sheet - revisions, changes, etc.
+ m_pViewsSheet = new PropertySheet(this, "ViewsSheet");
+
+ // changes
+ m_pChangesPage = new PropertyPage(m_pViewsSheet, "ChangesPage");
+ m_pViewsSheet->AddPage(m_pChangesPage, "Changes");
+ m_pChangesList = new SectionedListPanel(m_pChangesPage, "ChangesList");
+
+ // layout changes
+ int x, y, wide, tall;
+ m_pChangesPage->GetBounds(x, y, wide, tall);
+ m_pChangesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 6, 6, -12, -12 );
+
+ // revisions
+ m_pRevisionsPage = new PropertyPage(m_pViewsSheet, "RevisionsPage");
+ m_pViewsSheet->AddPage(m_pRevisionsPage, "History");
+ m_pRevisionList = new CSmallTextListPanel(m_pRevisionsPage, "RevisionList");
+ m_pRevisionList->SetEmptyListText("No file or directory currently selected.");
+ m_pRevisionList->AddColumnHeader(0, "change", "change", 52, ListPanel::COLUMN_HIDDEN);
+ m_pRevisionList->AddColumnHeader(1, "date", "date", 52, 0);
+ m_pRevisionList->AddColumnHeader(2, "time", "time", 52, ListPanel::COLUMN_HIDDEN);
+ m_pRevisionList->AddColumnHeader(3, "user", "user", 64, 0);
+ m_pRevisionList->AddColumnHeader(4, "description", "description", 32, ListPanel::COLUMN_RESIZEWITHWINDOW);
+ m_pRevisionList->SetAllowUserModificationOfColumns(true);
+
+ // layout revisions
+ m_pRevisionsPage->GetBounds(x, y, wide, tall);
+ m_pRevisionList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 6, 6, -12, -12 );
+
+ LoadControlSettingsAndUserConfig("//PLATFORM/resource/vp4dialog.res");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CVP4Dialog::~CVP4Dialog()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: stops app on close
+//-----------------------------------------------------------------------------
+void CVP4Dialog::OnClose()
+{
+ BaseClass::OnClose();
+ ivgui()->Stop();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called to open
+//-----------------------------------------------------------------------------
+void CVP4Dialog::Activate()
+{
+ BaseClass::Activate();
+
+ char szTitle[256];
+ Q_snprintf(szTitle, sizeof(szTitle), "VP4 - %s", p4->String( p4->GetActiveClient().m_sUser ));
+
+ SetTitle(szTitle, true);
+
+ RefreshFileList();
+ RefreshClientList();
+ RefreshChangesList();
+
+ p4->GetClientList();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Refreshes the active file list
+//-----------------------------------------------------------------------------
+void CVP4Dialog::RefreshFileList()
+{
+ m_pFileTree->RemoveAll();
+ m_pFileTree->SetFgColor(Color(216, 222, 211, 255));
+
+ // add the base node
+ KeyValues *pkv = new KeyValues("root");
+ pkv->SetString("text", p4->String( p4->GetActiveClient().m_sLocalRoot ));
+ pkv->SetString("path", p4->String( p4->GetActiveClient().m_sLocalRoot ));
+ pkv->SetInt("dir", 1);
+ int iRoot = m_pFileTree->AddItem(pkv, m_pFileTree->GetRootItemIndex());
+ m_pFileTree->ExpandItem(iRoot, true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: utility function used in qsort
+//-----------------------------------------------------------------------------
+int __cdecl IntSortFunc(const void *elem1, const void *elem2)
+{
+ if ( *((int *)elem1) < *((int *)elem2) )
+ return -1;
+ else if ( *((int *)elem1) > *((int *)elem2) )
+ return 1;
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: rebuilds the list of changes
+//-----------------------------------------------------------------------------
+void CVP4Dialog::RefreshChangesList()
+{
+ m_pChangesList->RemoveAll();
+ m_pChangesList->RemoveAllSections();
+
+ CUtlVector<P4File_t> files;
+ p4->GetOpenedFileList( files );
+ CUtlVector<int> sections;
+
+ // find out all the changelists
+ for (int i = 0; i < files.Count(); i++)
+ {
+ if (!sections.IsValidIndex(sections.Find(files[i].m_iChangelist)))
+ {
+ // add a new section
+ sections.AddToTail(files[i].m_iChangelist);
+ }
+ }
+
+ // sort the changelists
+ qsort(sections.Base(), sections.Count(), sizeof(int), &IntSortFunc);
+
+ // add the changeslists
+ {for (int i = 0; i < sections.Count(); i++)
+ {
+ m_pChangesList->AddSection(sections[i], "");
+
+ char szChangelistName[256];
+ if (sections[i] > 0)
+ {
+ Q_snprintf(szChangelistName, sizeof(szChangelistName), "CHANGE: %d", sections[i]);
+ }
+ else
+ {
+ Q_snprintf(szChangelistName, sizeof(szChangelistName), "CHANGE: DEFAULT");
+ }
+
+ m_pChangesList->AddColumnToSection(sections[i], "file", szChangelistName, SectionedListPanel::COLUMN_BRIGHT, 512);
+ }}
+
+ // add the files to the changelists
+ {for (int i = 0; i < files.Count(); i++)
+ {
+ char szFile[_MAX_PATH];
+ Q_snprintf(szFile, sizeof(szFile), "%s/%s", p4->String( files[i].m_sPath ) + p4->GetDepotRootLength(), p4->String( files[i].m_sName ));
+ KeyValues *pkv = new KeyValues("node", "file", szFile);
+ m_pChangesList->AddItem(files[i].m_iChangelist, pkv);
+ }}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Refreshes the client selection combo
+//-----------------------------------------------------------------------------
+void CVP4Dialog::RefreshClientList()
+{
+ m_pClientCombo->RemoveAll();
+
+ CUtlVector<P4Client_t> &clients = p4->GetClientList();
+ P4Client_t &activeClient = p4->GetActiveClient();
+
+ // go through all clients
+ for (int i = 0; i < clients.Count(); i++)
+ {
+ // only add clients that are defined for this machine (host)
+ if (clients[i].m_sHost != activeClient.m_sHost)
+ continue;
+
+ // add in the new item
+ char szText[256];
+ Q_snprintf(szText, sizeof(szText), "%s %s", p4->String( clients[i].m_sName ), p4->String( clients[i].m_sLocalRoot ));
+ m_pClientCombo->AddItem(szText, new KeyValues("client", "client", p4->String( clients[i].m_sName )));
+ }
+
+ m_pClientCombo->SetText( p4->String( activeClient.m_sName ));
+
+ if (m_pClientCombo->GetItemCount() > 1)
+ {
+ m_pClientCombo->SetEnabled(true);
+ }
+ else
+ {
+ m_pClientCombo->SetEnabled(false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: refreshes dialog on text changing
+//-----------------------------------------------------------------------------
+void CVP4Dialog::OnTextChanged()
+{
+ KeyValues *pkv = m_pClientCombo->GetActiveItemUserData();
+ if (!pkv)
+ return;
+
+ // set the new client
+ p4->SetActiveClient(pkv->GetString("client"));
+
+ // refresh the UI
+ Activate();
+ m_pRevisionList->RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Cloaks a folder
+//-----------------------------------------------------------------------------
+void CVP4Dialog::CloakFolder(int iItem)
+{
+ KeyValues *pkv = m_pFileTree->GetItemData(iItem);
+ if (!pkv)
+ return;
+
+ // change the clientspec to remove the folder
+ p4->RemovePathFromActiveClientspec(pkv->GetString("path"));
+
+ // remove the folder from the tree view
+ m_pFileTree->RemoveItem(0-iItem, false);
+ m_pFileTree->InvalidateLayout();
+ m_pFileTree->Repaint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: open for edit
+//-----------------------------------------------------------------------------
+void CVP4Dialog::OpenFileForEdit(int iItem)
+{
+ KeyValues *pkv = m_pFileTree->GetItemData(iItem);
+ if (!pkv)
+ return;
+
+ p4->OpenFileForEdit(pkv->GetString("path"));
+
+ RefreshChangesList();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: open for delete
+//-----------------------------------------------------------------------------
+void CVP4Dialog::OpenFileForDelete(int iItem)
+{
+ KeyValues *pkv = m_pFileTree->GetItemData(iItem);
+ if (!pkv)
+ return;
+
+ p4->OpenFileForDelete(pkv->GetString("path"));
+
+ RefreshChangesList();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: updates revision view on a file being selected
+//-----------------------------------------------------------------------------
+void CVP4Dialog::OnFileSelected()
+{
+ m_pRevisionList->RemoveAll();
+
+ // only update if reviews page is visible
+ if (!m_pRevisionsPage->IsVisible())
+ return;
+
+ // update list
+ int iItem = m_pFileTree->GetFirstSelectedItem();
+ if (iItem < 0)
+ {
+ m_pRevisionList->SetEmptyListText("No file or directory currently selected.");
+ return;
+ }
+
+ surface()->SetCursor(dc_waitarrow);
+
+ m_pRevisionList->SetEmptyListText("There is no revision history for the selected file.");
+
+ KeyValues *pkv = m_pFileTree->GetItemData(iItem);
+
+ CUtlVector<P4Revision_t> &revisions = p4->GetRevisionList(pkv->GetString("path"), pkv->GetInt("dir"));
+
+ // add all the revisions
+ for (int i = 0; i < revisions.Count(); i++)
+ {
+ KeyValues *pkv = new KeyValues("node");
+ pkv->SetString("user", p4->String( revisions[i].m_sUser ));
+ pkv->SetInt("change", revisions[i].m_iChange);
+
+ char szDate[256];
+ Q_snprintf(szDate, sizeof(szDate), "%d/%d/%d", revisions[i].m_nYear, revisions[i].m_nMonth, revisions[i].m_nDay);
+ pkv->SetString("date", szDate);
+
+ char szTime[256];
+ Q_snprintf(szTime, sizeof(szTime), "%d:%d:%d", revisions[i].m_nHour, revisions[i].m_nMinute, revisions[i].m_nSecond);
+ pkv->SetString("time", szTime);
+
+ // take just the first line of the description
+ char *pDesc = revisions[i].m_Description.GetForModify();
+ // move to the first non-whitespace
+ while (*pDesc && (isspace(*pDesc) || iscntrl(*pDesc)))
+ {
+ ++pDesc;
+ }
+
+ char szShortDescription[256];
+ Q_strncpy(szShortDescription, pDesc, sizeof(szShortDescription));
+
+ // truncate to last terminator
+ char *pTerm = szShortDescription;
+ while (*pTerm && !iscntrl(*pTerm))
+ {
+ ++pTerm;
+ }
+ *pTerm = 0;
+
+ pkv->SetString("description", szShortDescription);
+
+ m_pRevisionList->AddItem(pkv, 0, false, false);
+ }
+}
diff --git a/utils/vp4/vp4dialog.h b/utils/vp4/vp4dialog.h
new file mode 100644
index 0000000..9006acb
--- /dev/null
+++ b/utils/vp4/vp4dialog.h
@@ -0,0 +1,57 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef VP4DIALOG_H
+#define VP4DIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+#include "vgui_controls/ImageList.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Main app window
+//-----------------------------------------------------------------------------
+class CVP4Dialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CVP4Dialog, vgui::Frame );
+public:
+ CVP4Dialog();
+ ~CVP4Dialog();
+
+ // overridden frame functions
+ virtual void Activate();
+ virtual void OnClose();
+
+private:
+ void RefreshFileList();
+ void RefreshClientList();
+ void RefreshChangesList();
+
+ MESSAGE_FUNC( OnFileSelected, "TreeViewItemSelected" );
+ MESSAGE_FUNC( OnTextChanged, "TextChanged" );
+
+ // changes
+ MESSAGE_FUNC_INT( CloakFolder, "CloakFolder", item );
+ MESSAGE_FUNC_INT( OpenFileForEdit, "EditFile", item );
+ MESSAGE_FUNC_INT( OpenFileForDelete, "DeleteFile", item );
+
+ vgui::ComboBox *m_pClientCombo;
+ vgui::TreeView *m_pFileTree;
+ vgui::ImageList m_Images;
+
+ vgui::PropertySheet *m_pViewsSheet;
+ vgui::PropertyPage *m_pRevisionsPage;
+ vgui::PropertyPage *m_pChangesPage;
+
+ vgui::ListPanel *m_pRevisionList;
+ vgui::SectionedListPanel *m_pChangesList;
+
+};
+
+
+#endif // VP4DIALOG_H