Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,45 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
if(NOT PAL_TRAIT_BUILD_HOST_TOOLS)
return()
endif()
include(${CMAKE_CURRENT_SOURCE_DIR}/Platform/${PAL_PLATFORM_NAME}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # For PAL_TRAIT_BUILD_P4PLUGIN_SUPPORTED
if(NOT PAL_TRAIT_BUILD_P4PLUGIN_SUPPORTED)
return()
endif()
ly_add_target(
NAME PerforcePlugin MODULE
NAMESPACE Legacy
OUTPUT_SUBDIRECTORY EditorPlugins
AUTOMOC
AUTOUIC
FILES_CMAKE
perforceplugin_files.cmake
COMPILE_DEFINITIONS
PRIVATE
PLUGIN_EXPORTS
INCLUDE_DIRECTORIES
PUBLIC
.
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
Legacy::CryCommon
Legacy::EditorLib
3rdParty::p4api
)
ly_add_dependencies(Editor PerforcePlugin)
set_property(GLOBAL APPEND PROPERTY LY_EDITOR_PLUGINS $<TARGET_FILE_NAME:Legacy::PerforcePlugin>)
@@ -0,0 +1,303 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "PerforcePlugin_precompiled.h"
#include "PerforcePlugin.h"
#include "PasswordDlg.h"
#include <ui_settings.h> // generated
#include <AzQtComponents/Components/Widgets/CheckBox.h>
#include <AzToolsFramework/UI/UICore/ProgressShield.hxx>
#include <QTimer>
#include <AzCore/std/bind/bind.h>
namespace PerforceConnection
{
const char* const PerforceUser = "P4USER";
const char* const PerforceServer = "P4PORT";
const char* const PerforceClient = "P4CLIENT";
const char* const PerforceCharset = "P4CHARSET";
using namespace AzToolsFramework;
PerforceConfigDialog::PerforceConfigDialog(QWidget* parent)
: QDialog(parent)
{
this->setWindowFlags(Qt::Dialog
| Qt::MSWindowsFixedSizeDialogHint
| Qt::WindowStaysOnTopHint);
m_ui = new Ui::P4SettingsDialog();
m_ui->setupUi(this);
{
SourceControlState state = SourceControlState::Disabled;
SourceControlConnectionRequestBus::BroadcastResult(state, &SourceControlConnectionRequestBus::Events::GetSourceControlState);
bool onlineMode = state == SourceControlState::Disabled ? false : true;
AzQtComponents::CheckBox::applyToggleSwitchStyle(m_ui->workOnlineCheckbox);
m_ui->workOnlineCheckbox->setChecked(onlineMode);
}
}
void PerforceConfigDialog::RetrieveSettings()
{
m_retrievedSettings.insert_key(PerforceClient);
m_retrievedSettings.insert_key(PerforceUser);
m_retrievedSettings.insert_key(PerforceServer);
m_retrievedSettings.insert_key(PerforceCharset);
setEnabled(false);
int numSettingsToGet = m_retrievedSettings.size();
auto applySettingResultFunction = [this, &numSettingsToGet](AZStd::string setting, const SourceControlSettingInfo& info) -> void
{
m_retrievedSettings[setting] = info;
--numSettingsToGet;
};
using SCRequestBus = AzToolsFramework::SourceControlConnectionRequestBus;
for (const auto& kvp : m_retrievedSettings)
{
auto boundLocal = AZStd::bind<void>(applySettingResultFunction, kvp.first.c_str(), AZStd::placeholders::_1);
SCRequestBus::Broadcast(&SCRequestBus::Events::GetConnectionSetting, kvp.first.c_str(), boundLocal);
}
auto waitForAllSettings = [&numSettingsToGet](int&, int&)
{
return numSettingsToGet == 0;
};
// Wait for completion
ProgressShield::LegacyShowAndWait(this, tr("Getting settings"), waitForAllSettings);
// wrinkle in the plan - charset might have (SERVER)charset applied to it. So ask for one more.
m_charsetKey = PerforceCharset;
if (m_retrievedSettings[PerforceServer].IsAvailable())
{
AZStd::string charsetNameWithServerAddress = AZStd::string::format("P4_%s_CHARSET", m_retrievedSettings[PerforceServer].m_value.c_str());
// ask for one more
numSettingsToGet = 1;
auto boundLocal = AZStd::bind<void>(applySettingResultFunction, charsetNameWithServerAddress.c_str(), AZStd::placeholders::_1);
SCRequestBus::Broadcast(&SCRequestBus::Events::GetConnectionSetting, charsetNameWithServerAddress.c_str(), boundLocal);
ProgressShield::LegacyShowAndWait(this, tr("Getting settings"), waitForAllSettings);
// did we get a value?
if (m_retrievedSettings[charsetNameWithServerAddress].IsAvailable())
{
m_charsetKey = charsetNameWithServerAddress;
}
}
// which CHARSET do we pick? we prefer (servername) charset, but will fall back to just P4CHARSET
for (const auto& value : m_retrievedSettings)
{
QLineEdit *targetControl = nullptr;
const AZStd::string& settingName = value.first;
const SourceControlSettingInfo& info = value.second;
ApplyValueToControl(GetControlForSetting(settingName), info);
}
setEnabled(true);
}
QLineEdit* PerforceConfigDialog::GetControlForSetting(const AZStd::string& settingName) const
{
if (settingName == PerforceClient)
{
return m_ui->workspaceEdit;
}
else if (settingName == PerforceUser)
{
return m_ui->userEdit;
}
else if (settingName == PerforceServer)
{
return m_ui->serverEdit;
}
else if (settingName == m_charsetKey)
{
return m_ui->charsetEdit;
}
return nullptr;
}
PerforceConfigDialog::~PerforceConfigDialog()
{
delete m_ui;
}
void PerforceConfigDialog::ApplyValueToControl(QLineEdit* targetControl, const SourceControlSettingInfo& value)
{
if (targetControl)
{
if (value.IsAvailable())
{
targetControl->setText(QString::fromUtf8(value.m_value.c_str()));
}
else
{
targetControl->setText(QString(""));
}
if (value.IsSettable())
{
targetControl->setReadOnly(false);
targetControl->setEnabled(true);
targetControl->setToolTip("");
}
else
{
targetControl->setReadOnly(true);
targetControl->setEnabled(false);
QString toolTip;
QString ttDescStart("Cannot change this value - it is currently being overridden by");
if (value.m_status == SourceControlSettingStatus::Config)
{
if (!value.m_context.empty())
{
toolTip = tr("%1 config file: %2.").arg(ttDescStart).arg(QString::fromUtf8(value.m_context.c_str()));
}
else
{
toolTip = tr("%1 a config file.").arg(ttDescStart);
}
}
else
{
toolTip = tr("%1 your system environment. Please check your environment variables in your system's control panel").arg(ttDescStart);
}
targetControl->setToolTip(toolTip);
}
}
}
void PerforceConfigDialog::on_workOnlineCheckbox_toggled(bool newState)
{
m_ui->workspaceEdit->setEnabled(false);
m_ui->userEdit->setEnabled(false);
m_ui->serverEdit->setEnabled(false);
m_ui->charsetEdit->setEnabled(false);
if (newState)
{
// we only fetch settings if we are working online.
QTimer::singleShot(0, this, &PerforceConfigDialog::RetrieveSettings);
}
else
{
m_ui->workspaceEdit->setText(tr("(offline)"));
m_ui->userEdit->setText(tr("(offline)"));
m_ui->serverEdit->setText(tr("(offline)"));
m_ui->charsetEdit->setText(tr("(offline)"));
}
}
void PerforceConfigDialog::Apply()
{
bool onlineMode = m_ui->workOnlineCheckbox->isChecked();
{
using SCRequestBus = AzToolsFramework::SourceControlConnectionRequestBus;
SCRequestBus::Broadcast(&SCRequestBus::Events::EnableSourceControl, onlineMode);
}
if (onlineMode)
{
// work online!
// apply all the settings.
// you may only apply some of the settings - the ones that are either 'set' or 'unset'
// only set values that are not already that value
// and charset is special in that you must set it as eitehr CHARSET or override the server.
ApplySetting(PerforceUser);
ApplySetting(PerforceServer);
ApplySetting(PerforceClient);
ApplySetting(m_charsetKey.c_str());
}
}
bool PerforceConfigDialog::ApplySetting(const char* key)
{
if (!m_retrievedSettings[key].IsSettable())
{
return false;
}
QLineEdit* source = GetControlForSetting(key);
if (!source)
{
return false;
}
AZStd::string newValue = source->text().toUtf8().data();
if (newValue.empty())
{
return false;
}
if (newValue == m_retrievedSettings[key].m_value)
{
return false;
}
// again, charset is special in that it can under certain circumstances take the form P4_SERVERNAME_CHARSET instead of just P4CHARSET
if (m_charsetKey == key)
{
// if its already P4CHARSET then we don't care.
if (m_charsetKey != PerforceCharset)
{
QLineEdit* hostSource = GetControlForSetting(PerforceServer);
if (!hostSource)
{
return false;
}
m_charsetKey = AZStd::string::format("P4_%s_CHARSET", hostSource->text().toUtf8().data());
key = m_charsetKey.c_str();
}
}
bool succeeded = false;
bool complete = false;
auto respCallback = [&succeeded, &complete, newValue](const SourceControlSettingInfo& info)
{
succeeded = (info.m_value == newValue);
complete = true;
};
auto waitForDone = [&complete](int&, int&)
{
return complete;
};
using SCRequestBus = AzToolsFramework::SourceControlConnectionRequestBus;
SCRequestBus::Broadcast(&SCRequestBus::Events::SetConnectionSetting, key, newValue.c_str(), respCallback);
ProgressShield::LegacyShowAndWait(this, tr("Applying settings"), waitForDone);
return succeeded;
}
bool OpenPasswordDlg()
{
PerforceConfigDialog dialog;
if (dialog.exec() == QDialog::Accepted)
{
dialog.Apply();
return true;
}
return false;
}
} // namespace PerforceConnection
#include <moc_PasswordDlg.cpp>
@@ -0,0 +1,60 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#if !defined(Q_MOC_RUN)
#include <QDialog>
#include <QString>
#include <AzToolsFramework/SourceControl/SourceControlAPI.h> // for SouceControlSettingInfo
#endif
class QLineEdit;
namespace Ui {
class P4SettingsDialog;
} // namespace Ui
namespace PerforceConnection
{
class PerforceConfigDialog
: public QDialog
{
Q_OBJECT
public:
PerforceConfigDialog(QWidget* pParent = nullptr);
virtual ~PerforceConfigDialog();
bool GetWorkOffline() const;
void SetWorkOffline(bool value);
public Q_SLOTS:
void RetrieveSettings();
// auto-bound slots
void on_workOnlineCheckbox_toggled(bool newState);
void Apply();
private:
Ui::P4SettingsDialog* m_ui;
AZStd::unordered_map<AZStd::string, AzToolsFramework::SourceControlSettingInfo> m_retrievedSettings;
AZStd::string m_charsetKey;
void ApplyValueToControl(QLineEdit* targetControl, const AzToolsFramework::SourceControlSettingInfo& value);
bool ApplySetting(const char* key);
QLineEdit* GetControlForSetting(const AZStd::string& settingName) const;
};
bool OpenPasswordDlg();
} // namespace PerforceConnection
@@ -0,0 +1,78 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "PerforcePlugin_precompiled.h"
#include "PerforcePlugin.h"
#include "PerforceSourceControl.h"
#include "Include/ISourceControl.h"
#include "Include/IEditorClassFactory.h"
extern CPerforceSourceControl* g_pPerforceControl;
namespace PluginInfo
{
const char* kName = "Perforce Client";
const char* kGUID = "{FD5F1023-8F02-4051-89FA-DF1F038863A2}";
const int kVersion = 1;
}
void CPerforcePlugin::Release()
{
GetIEditor()->GetClassFactory()->UnregisterClass(g_pPerforceControl->ClassName().toUtf8().data());
delete this;
}
void CPerforcePlugin::ShowAbout()
{
}
const char* CPerforcePlugin::GetPluginGUID()
{
return PluginInfo::kGUID;
}
DWORD CPerforcePlugin::GetPluginVersion()
{
return PluginInfo::kVersion;
}
const char* CPerforcePlugin::GetPluginName()
{
return PluginInfo::kName;
}
bool CPerforcePlugin::CanExitNow()
{
return true;
}
void CPerforcePlugin::Serialize([[maybe_unused]] FILE* hFile, [[maybe_unused]] bool bIsStoring)
{
}
void CPerforcePlugin::ResetContent()
{
}
bool CPerforcePlugin::CreateUIElements()
{
return true;
}
void CPerforcePlugin::OnEditorNotify(EEditorNotifyEvent aEventId)
{
if (eNotify_OnInit == aEventId)
{
g_pPerforceControl->Init();
}
}
@@ -0,0 +1,37 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_PERFORCEPLUGIN_PERFORCEPLUGIN_H
#define CRYINCLUDE_PERFORCEPLUGIN_PERFORCEPLUGIN_H
#pragma once
#include <Include/IPlugin.h>
class CPerforcePlugin
: public IPlugin
{
public:
void Release();
void ShowAbout();
const char* GetPluginGUID();
DWORD GetPluginVersion();
const char* GetPluginName();
bool CanExitNow();
void Serialize(FILE* hFile, bool bIsStoring);
void ResetContent();
bool CreateUIElements();
void OnEditorNotify(EEditorNotifyEvent aEventId);
};
#endif // CRYINCLUDE_PERFORCEPLUGIN_PERFORCEPLUGIN_H
@@ -0,0 +1,4 @@
<RCC>
<qresource prefix="/">
</qresource>
</RCC>
@@ -0,0 +1,71 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_P4 ICON "res\\p4.ico"
IDI_P4_ERROR ICON "res\\p4_error.ico"
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
@@ -0,0 +1,15 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "PerforcePlugin_precompiled.h"
@@ -0,0 +1,47 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <AzCore/PlatformDef.h>
#include "resource.h"
/////////////////////////////////////////////////////////////////////////////
// CRY Stuff ////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#include <platform.h>
/////////////////////////////////////////////////////////////////////////////
// STL
/////////////////////////////////////////////////////////////////////////////
#include <vector>
#include <list>
#include <map>
#include <set>
#include <algorithm>
/////////////////////////////////////////////////////////////////////////////
// CRY Stuff ////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#include <ISystem.h>
#include "Util/EditorUtils.h"
#include "IEditor.h"
/////////////////////////////////////////////////////////////////////////////
// P4 API ////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#include <p4/clientapi.h>
#include <p4/enviro.h>
#include <p4/errornum.h>
@@ -0,0 +1,427 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "PerforcePlugin_precompiled.h"
#include "CryFile.h"
#include "PerforceSourceControl.h"
#include "PasswordDlg.h"
#include <QSettings>
#include <QDir>
#include <QFile>
#include <QProcess>
#include <QApplication>
#include <QTimer>
#include <Util/PathUtil.h>
#include <AzCore/base.h>
namespace
{
CryCriticalSection g_cPerforceValues;
}
void CMyClientUser::Init()
{
m_e.Clear();
}
////////////////////////////////////////////////////////////
void CMyClientApi::Run(const char* func)
{
// The "enableStreams" var has to be set prior to any Run call in order to be able to support Perforce streams
ClientApi::SetVar("enableStreams");
ClientApi::Run(func);
}
void CMyClientApi::Run(const char* func, ClientUser* clientUserUI)
{
ClientApi::SetVar("enableStreams");
ClientApi::Run(func, clientUserUI);
}
////////////////////////////////////////////////////////////
CPerforceSourceControl::CPerforceSourceControl()
: m_ref(0)
{
m_bIsWorkOffline = true;
m_bIsWorkOfflineBecauseOfConnectionLoss = true;
m_bIsFailConnectionLogged = false;
m_configurationInvalid = false;
m_dwLastAccessTime = 0;
m_client = nullptr;
m_nextHandle = 0;
m_lastWorkOfflineResult = true;
m_lastWorkOfflineBecauseOfConnectionLossResult = true;
m_clientInitialized = false;
}
ULONG STDMETHODCALLTYPE CPerforceSourceControl::Release()
{
if ((--m_ref) == 0)
{
g_cPerforceValues.Lock();
FreeData();
delete this;
g_cPerforceValues.Unlock();
return 0;
}
else
{
return m_ref;
}
}
CPerforceSourceControl::~CPerforceSourceControl()
{
delete m_client;
}
bool CPerforceSourceControl::Connect()
{
// before we call Init we must set up the connection!
// the user may have overridden the connection on a per-project basis.
// check the config file.
AUTO_LOCK(g_cPerforceValues);
FreeData();
m_client = new CMyClientApi();
// Ensure P4PORT is set before calling ClientApi::Init
const bool p4PortIsSet = nullptr != m_client->GetEnviro()->Get("P4PORT");
if (p4PortIsSet)
{
m_client->Init(&m_e);
m_clientInitialized = true;
}
if (!p4PortIsSet || m_e.Test())
{
if (!m_bIsWorkOffline)
{
m_bIsWorkOfflineBecauseOfConnectionLoss = true;
}
m_bIsWorkOffline = true;
if (!m_bIsFailConnectionLogged)
{
GetIEditor()->GetSystem()->GetILog()->Log(p4PortIsSet ? "\nPerforce plugin: Failed to connect." : "\nPerforce plugin: P4PORT must be set to connect.");
m_bIsFailConnectionLogged = true;
}
if (GetIEditor()->IsSourceControlAvailable())
{
//Only Check Connection and than Notify Listeners if SourceControl is available at that instance
CheckConnectionAndNotifyListeners();
}
return false;
}
else
{
GetIEditor()->GetSystem()->GetILog()->Log("\nPerforce plugin: Connected.");
m_bIsFailConnectionLogged = false;
if (m_bIsWorkOfflineBecauseOfConnectionLoss)
{
m_bIsWorkOffline = false;
m_bIsWorkOfflineBecauseOfConnectionLoss = false;
}
}
return true;
}
bool CPerforceSourceControl::Reconnect()
{
AUTO_LOCK(g_cPerforceValues);
if ((m_client && m_client->Dropped()) || m_bIsWorkOfflineBecauseOfConnectionLoss)
{
if (!m_bIsFailConnectionLogged)
{
GetIEditor()->GetSystem()->GetILog()->Log("\nPerforce connection dropped: attempting reconnect");
}
FreeData();
if (!Connect())
{
if (!m_bIsWorkOffline)
{
m_bIsWorkOfflineBecauseOfConnectionLoss = true;
}
m_bIsWorkOffline = true;
return false;
}
else
{
CheckConnectionAndNotifyListeners();
}
}
return true;
}
void CPerforceSourceControl::FreeData()
{
AUTO_LOCK(g_cPerforceValues);
if (m_client)
{
if (m_clientInitialized)
{
m_client->Final(&m_e);
m_clientInitialized = false;
}
delete m_client;
m_client = nullptr;
}
m_e.Clear();
}
void CPerforceSourceControl::Init()
{
Connect();
{
AzToolsFramework::SourceControlState state = AzToolsFramework::SourceControlState::Disabled;
using SCRequestBus = AzToolsFramework::SourceControlConnectionRequestBus;
SCRequestBus::BroadcastResult(state, &SCRequestBus::Events::GetSourceControlState);
SetSourceControlState(state);
}
}
void CPerforceSourceControl::ShowSettings()
{
AUTO_LOCK(g_cPerforceValues);
bool workOffline = (m_bIsWorkOffline && !m_bIsWorkOfflineBecauseOfConnectionLoss);
if (PerforceConnection::OpenPasswordDlg())
{
m_bIsWorkOfflineBecauseOfConnectionLoss = false;
bool onlineMode = false;
{
using SCRequestBus = AzToolsFramework::SourceControlConnectionRequestBus;
SCRequestBus::BroadcastResult(onlineMode, &SCRequestBus::Events::IsActive);
}
m_bIsWorkOffline = !onlineMode;
// reset the connection!
if ((!m_bIsWorkOfflineBecauseOfConnectionLoss) && onlineMode)
{
Connect();
}
CheckConnectionAndNotifyListeners();
}
}
const char* CPerforceSourceControl::GetErrorByGenericCode(int nGeneric)
{
switch (nGeneric)
{
case EV_USAGE:
return "Request is not consistent with documentation or cannot support a server version";
case EV_UNKNOWN:
return "Using unknown entity";
case EV_CONTEXT:
return "Using entity in wrong context";
case EV_ILLEGAL:
return "Trying to do something you can't";
case EV_NOTYET:
return "Something must be corrected first";
case EV_PROTECT:
return "Operation was prevented by protection level";
// No fault at all
case EV_EMPTY:
return "Action returned empty results";
// not the fault of the user
case EV_FAULT:
return "Inexplicable program fault";
case EV_CLIENT:
return "Client side program errors";
case EV_ADMIN:
return "Server administrative action required";
case EV_CONFIG:
return "Client configuration is inadequate";
case EV_UPGRADE:
return "Client or server is too old to interact";
case EV_COMM:
return "Communication error";
case EV_TOOBIG:
return "File is too big";
}
return "Undefined";
}
bool CPerforceSourceControl::Run(const char* func, int nArgs, char* argv[], bool bOnlyFatal)
{
for (int x = 0; x < nArgs; ++x)
{
if (argv[x][0] == '\0')
{
return false;
}
}
if (!Reconnect())
{
return false;
}
bool bRet = false;
AUTO_LOCK(g_cPerforceValues);
m_ui.Init();
m_client->SetArgv(nArgs, argv);
m_client->Run(func, &m_ui);
m_client->WaitTag();
#if 0 // connection debug
for (int argid = 0; argid < nArgs; argid++)
{
g_pSystem->GetILog()->Log("\n arg %d : %s", argid, argv[argid]);
}
#endif // connection debug
if (bOnlyFatal)
{
if (!m_ui.m_e.IsFatal())
{
bRet = true;
}
}
else
{
if (!m_ui.m_e.Test())
{
bRet = true;
}
}
if (m_ui.m_e.GetSeverity() == E_FAILED || m_ui.m_e.GetSeverity() == E_FATAL)
{
static int nGenericPrev = 0;
const int nGeneric = m_ui.m_e.GetGeneric();
if (IsSomeTimePassed())
{
nGenericPrev = 0;
}
if (nGenericPrev != nGeneric)
{
if ((!bOnlyFatal) || (m_ui.m_e.GetSeverity() == E_FATAL))
{
GetIEditor()->GetSystem()->GetILog()->LogError("Perforce plugin: %s", GetErrorByGenericCode(nGeneric));
StrBuf m;
m_ui.m_e.Fmt(&m);
GetIEditor()->GetSystem()->GetILog()->LogError("Perforce plugin: %s", m.Text());
}
nGenericPrev = nGeneric;
}
}
m_ui.m_e.Clear();
return bRet;
}
void CPerforceSourceControl::SetSourceControlState(SourceControlState state)
{
AUTO_LOCK(g_cPerforceValues);
switch (state)
{
case SourceControlState::Disabled:
{
m_bIsWorkOffline = true;
m_bIsWorkOfflineBecauseOfConnectionLoss = true;
m_configurationInvalid = false;
break;
}
case SourceControlState::Active:
m_bIsWorkOffline = false;
m_bIsWorkOfflineBecauseOfConnectionLoss = false;
m_configurationInvalid = false;
CheckConnectionAndNotifyListeners();
break;
case SourceControlState::ConfigurationInvalid:
m_bIsWorkOffline = false;
m_bIsWorkOfflineBecauseOfConnectionLoss = false;
m_configurationInvalid = true;
break;
default:
break;
}
}
CPerforceSourceControl::ConnectivityState CPerforceSourceControl::GetConnectivityState()
{
ConnectivityState state = ConnectivityState::Disconnected;
if (!m_bIsWorkOffline)
{
state = ConnectivityState::Connected;
}
else if (m_configurationInvalid)
{
state = ConnectivityState::BadConfiguration;
}
return state;
}
bool CPerforceSourceControl::CheckConnectionAndNotifyListeners()
{
AUTO_LOCK(g_cPerforceValues);
bool bRet = false;
bool wasWorkOffline = m_bIsWorkOffline;
if (!m_bIsWorkOffline)
{
bRet = Run("info", 0, 0);
}
if (m_bIsWorkOffline || m_configurationInvalid)
{
if (!wasWorkOffline)
{
// only log once when transitioning offline.
GetIEditor()->GetSystem()->GetILog()->LogError("Perforce plugin: Perforce is offline");
}
return false;
}
return bRet;
}
bool CPerforceSourceControl::IsSomeTimePassed()
{
AUTO_LOCK(g_cPerforceValues);
const DWORD dwSomeTime = 10000; // 10 sec
static DWORD dwLastTime = 0;
DWORD dwCurTime = GetTickCount();
if (dwCurTime - dwLastTime > dwSomeTime)
{
dwLastTime = dwCurTime;
return true;
}
return false;
}
@@ -0,0 +1,118 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#define USERNAME_LENGTH 64
#include "IEditorClassFactory.h"
#include "Include/IEditorClassFactory.h"
#include "Include/ISourceControl.h"
class CMyClientUser
: public ClientUser
{
public:
CMyClientUser()
{
Init();
}
void Init();
Error m_e;
};
class CMyClientApi
: public ClientApi
{
public:
void Run(const char* func);
void Run(const char* func, ClientUser* ui);
};
class CPerforceSourceControl
: public ISourceControl
, public IClassDesc
{
public:
// constructor
CPerforceSourceControl();
virtual ~CPerforceSourceControl();
bool Connect();
bool Reconnect();
void FreeData();
void Init();
bool CheckConnectionAndNotifyListeners();
virtual void SetSourceControlState(SourceControlState state) override;
virtual ConnectivityState GetConnectivityState() override;
virtual void ShowSettings() override;
bool Run(const char* func, int nArgs, char* argv[], bool bOnlyFatal = false);
// from IClassDesc
virtual ESystemClassID SystemClassID() { return ESYSTEM_CLASS_SCM_PROVIDER; };
REFGUID ClassID()
{
// {3c209e66-0728-4d43-897d-168962d5c8b5}
static const GUID guid = {
0x3c209e66, 0x0728, 0x4d43, { 0x89, 0x7d, 0x16, 0x89, 0x62, 0xd5, 0xc8, 0xb5 }
};
return guid;
}
virtual QString ClassName() { return "Perforce source control"; };
virtual QString Category() { return "SourceControl"; };
virtual void ShowAbout() {};
// from IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(const IID& riid, void** ppvObj)
{
if (riid == __uuidof(ISourceControl) /* && m_pIntegrator*/)
{
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef() { return ++m_ref; };
ULONG STDMETHODCALLTYPE Release();
protected:
bool IsSomeTimePassed();
static const char* GetErrorByGenericCode(int nGeneric);
private:
CMyClientUser m_ui;
CMyClientApi* m_client;
Error m_e;
bool m_bIsWorkOffline;
bool m_bIsWorkOfflineBecauseOfConnectionLoss;
bool m_bIsFailConnectionLogged;
bool m_configurationInvalid;
DWORD m_dwLastAccessTime;
ULONG m_ref;
uint m_nextHandle;
bool m_lastWorkOfflineResult;
bool m_lastWorkOfflineBecauseOfConnectionLossResult;
bool m_clientInitialized;
};
@@ -0,0 +1,12 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_BUILD_P4PLUGIN_SUPPORTED FALSE)
@@ -0,0 +1,12 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_BUILD_P4PLUGIN_SUPPORTED TRUE)
@@ -0,0 +1,12 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_BUILD_P4PLUGIN_SUPPORTED TRUE)
@@ -0,0 +1,54 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "PerforcePlugin_precompiled.h"
#include "PerforcePlugin.h"
#include "Include/ISourceControl.h"
#include "Include/IEditorClassFactory.h"
#include "PerforceSourceControl.h"
#include <AzCore/PlatformDef.h>
CPerforceSourceControl* g_pPerforceControl = 0;
PLUGIN_API IPlugin* CreatePluginInstance(PLUGIN_INIT_PARAM* pInitParam)
{
if (pInitParam->pluginVersion != SANDBOX_PLUGIN_SYSTEM_VERSION)
{
pInitParam->outErrorCode = IPlugin::eError_VersionMismatch;
return 0;
}
ModuleInitISystem(GetIEditor()->GetSystem(), "PerforcePlugin");
g_pPerforceControl = new CPerforceSourceControl();
pInitParam->pIEditorInterface->GetClassFactory()->RegisterClass(g_pPerforceControl);
return new CPerforcePlugin();
}
#ifdef AZ_PLATFORM_WINDOWS
HINSTANCE g_hInstance = 0;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, ULONG fdwReason, [[maybe_unused]] LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
g_hInstance = hinstDLL;
//DisableThreadLibraryCalls(hInstance);
}
return(TRUE);
}
#endif
@@ -0,0 +1,25 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
settings.ui
main.cpp
PasswordDlg.cpp
PasswordDlg.h
PerforcePlugin.cpp
PerforcePlugin.h
PerforcePlugin.qrc
PerforceSourceControl.cpp
PerforceSourceControl.h
resource.h
PerforcePlugin_precompiled.cpp
PerforcePlugin_precompiled.h
)
@@ -0,0 +1,27 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#define IDI_P4 104
#define IDI_P4_ERROR 106
#define IDC_ERROR 1004
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 107
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1010
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
@@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>P4SettingsDialog</class>
<widget class="QDialog" name="P4SettingsDialog">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>358</width>
<height>160</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>358</width>
<height>160</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>358</width>
<height>160</height>
</size>
</property>
<property name="windowTitle">
<string>Perforce Settings</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout" rowstretch="1,1,1,1,1" columnstretch="1,2">
<item row="1" column="1">
<widget class="QLineEdit" name="userEdit"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Charset:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="serverEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Workspace:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="workspaceEdit"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Server:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>User:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="charsetEdit"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Work Online</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="workOnlineCheckbox">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>serverEdit</tabstop>
<tabstop>userEdit</tabstop>
<tabstop>workspaceEdit</tabstop>
<tabstop>charsetEdit</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>P4SettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>236</x>
<y>202</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>181</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>P4SettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>304</x>
<y>202</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>181</y>
</hint>
</hints>
</connection>
</connections>
</ui>