2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "TaskBrowserPrivatePCH.h"
# include "STaskBrowser.h"
# include "STaskColumn.h"
# include "STaskComplete.h"
# include "STaskSettings.h"
# include "../Public/TaskDatabase.h"
# include "../Public/TaskDataManager.h"
# if PLATFORM_WINDOWS
# include "AllowWindowsPlatformTypes.h"
# include <winsock2.h>
# include <iphlpapi.h>
# include <wincrypt.h>
# include "HideWindowsPlatformTypes.h"
// Link with the Wintrust.lib file.
# pragma comment( lib, "Crypt32.lib" )
# pragma comment( lib, "Iphlpapi.lib" )
# endif
# if PLATFORM_MAC
# include <CoreFoundation/CoreFoundation.h>
# include <IOKit/IOKitLib.h>
# include <IOKit/network/IOEthernetInterface.h>
# include <IOKit/network/IONetworkInterface.h>
# include <IOKit/network/IOEthernetController.h>
# include <CommonCrypto/CommonCryptor.h>
# endif
# define LOCTEXT_NAMESPACE "STaskBrowser"
DEFINE_LOG_CATEGORY_STATIC ( LogTaskBrowser , Log , All ) ;
/**
* Reads the mac address for the computer
*
* @ param MacAddr the buffer that receives the mac address
* @ param MacAddrLen ( in ) the size of the dest buffer , ( out ) the size of the data that was written
*
* @ return true if the address was read , false if it failed to get the address
*/
static bool GetMacAddress ( uint8 * MacAddr , uint32 & MacAddrLen )
{
TArray < uint8 > MacAddrArray = FPlatformMisc : : GetMacAddress ( ) ;
if ( MacAddrLen < ( uint32 ) MacAddrArray . Num ( ) | | MacAddrArray . Num ( ) = = 0 )
{
return false ;
}
MacAddrLen = MacAddrArray . Num ( ) ;
FMemory : : Memcpy ( MacAddr , MacAddrArray . GetData ( ) , MacAddrLen ) ;
return true ;
}
/**
* Encrypts a buffer using the crypto API
*
* @ param SrcBuffer the source data being encrypted
* @ param SrcLen the size of the buffer in bytes
* @ param DestBuffer ( out ) chunk of memory that is written to
* @ param DestLen ( in ) the size of the dest buffer , ( out ) the size of the encrypted data
*
* @ return true if the encryption worked , false otherwise
*/
static bool EncryptBuffer ( const uint8 * SrcBuffer , const uint32 SrcLen , uint8 * DestBuffer , uint32 & DestLen )
{
bool bEncryptedOk = false ;
# if PLATFORM_MAC
unsigned long long MacAddress = 0 ;
uint32 AddressSize = sizeof ( unsigned long long ) ;
GetMacAddress ( ( uint8 * ) & MacAddress , AddressSize ) ;
unsigned long long Entropy = 5148284414757334885ull ;
Entropy ^ = MacAddress ;
uint8 Key [ kCCKeySizeAES128 ] ;
check ( kCCKeySizeAES128 = = 2 * sizeof ( unsigned long long ) ) ;
FMemory : : Memcpy ( Key , & Entropy , sizeof ( Entropy ) ) ;
FMemory : : Memcpy ( Key + sizeof ( Entropy ) , & Entropy , sizeof ( Entropy ) ) ;
size_t OutBufferSize = SrcLen + kCCBlockSizeAES128 ;
uint8 * OutBuffer = ( uint8 * ) FMemory : : Malloc ( OutBufferSize ) ;
FMemory : : Memset ( OutBuffer , 0 , OutBufferSize ) ;
size_t BytesEncrypted = 0 ;
CCCryptorStatus Status = CCCrypt ( kCCEncrypt , kCCAlgorithmAES128 ,
kCCOptionPKCS7Padding , Key , kCCKeySizeAES128 , NULL , SrcBuffer ,
SrcLen , OutBuffer , OutBufferSize , & BytesEncrypted ) ;
if ( Status = = kCCSuccess )
{
DestLen = BytesEncrypted ;
FMemory : : Memcpy ( DestBuffer , OutBuffer , DestLen ) ;
bEncryptedOk = true ;
}
else
{
UE_LOG ( LogTaskBrowser , Log , TEXT ( " CCCrypt failed w/ 0x%08x " ) , Status ) ;
}
FMemory : : Free ( OutBuffer ) ;
2014-07-08 00:06:17 -04:00
# elif PLATFORM_LINUX
printf ( " STaskBrowser.cpp: LINUX EncryptBuffer() \n " ) ;
2014-06-05 17:11:45 -04:00
# elif PLATFORM_WINDOWS
2014-03-14 14:13:41 -04:00
DATA_BLOB SourceBlob , EntropyBlob , FinalBlob ;
// Set up the datablob to encrypt
SourceBlob . cbData = SrcLen ;
SourceBlob . pbData = ( uint8 * ) SrcBuffer ;
// Get the mac address for mixing into the entropy (ties the encryption to a location)
ULONGLONG MacAddress = 0 ;
uint32 AddressSize = sizeof ( ULONGLONG ) ;
GetMacAddress ( ( uint8 * ) & MacAddress , AddressSize ) ;
// Set up the entropy blob (changing this breaks all previous encrypted buffers!)
ULONGLONG Entropy = 5148284414757334885u i64 ;
Entropy ^ = MacAddress ;
EntropyBlob . cbData = sizeof ( ULONGLONG ) ;
EntropyBlob . pbData = ( uint8 * ) & Entropy ;
// Zero the output data
FMemory : : Memzero ( & FinalBlob , sizeof ( DATA_BLOB ) ) ;
// Now encrypt the data
if ( CryptProtectData ( & SourceBlob ,
NULL ,
& EntropyBlob ,
NULL ,
NULL ,
CRYPTPROTECT_UI_FORBIDDEN ,
& FinalBlob ) )
{
if ( FinalBlob . cbData < = DestLen )
{
// Copy the final results
DestLen = FinalBlob . cbData ;
FMemory : : Memcpy ( DestBuffer , FinalBlob . pbData , DestLen ) ;
bEncryptedOk = true ;
}
// Free the encryption buffer
LocalFree ( FinalBlob . pbData ) ;
}
else
{
uint32 Error = GetLastError ( ) ;
UE_LOG ( LogTaskBrowser , Log , TEXT ( " CryptProtectData failed w/ 0x%08x " ) , Error ) ;
}
2014-06-05 17:11:45 -04:00
# else
unimplemented ( ) ;
# endif
2014-03-14 14:13:41 -04:00
return bEncryptedOk ;
}
/**
* Decrypts a buffer using the crypto API
*
* @ param SrcBuffer the source data being decrypted
* @ param SrcLen the size of the buffer in bytes
* @ param DestBuffer ( out ) chunk of memory that is written to
* @ param DestLen ( in ) the size of the dest buffer , ( out ) the size of the encrypted data
*
* @ return true if the decryption worked , false otherwise
*/
static bool DecryptBuffer ( const uint8 * SrcBuffer , const uint32 SrcLen , uint8 * DestBuffer , uint32 & DestLen )
{
bool bDecryptedOk = false ;
# if PLATFORM_MAC
unsigned long long MacAddress = 0 ;
uint32 AddressSize = sizeof ( unsigned long long ) ;
GetMacAddress ( ( uint8 * ) & MacAddress , AddressSize ) ;
unsigned long long Entropy = 5148284414757334885ull ;
Entropy ^ = MacAddress ;
uint8 Key [ kCCKeySizeAES128 ] ;
check ( kCCKeySizeAES128 = = 2 * sizeof ( unsigned long long ) ) ;
FMemory : : Memcpy ( Key , & Entropy , sizeof ( Entropy ) ) ;
FMemory : : Memcpy ( Key + sizeof ( Entropy ) , & Entropy , sizeof ( Entropy ) ) ;
size_t OutBufferSize = SrcLen + kCCBlockSizeAES128 ;
uint8 * OutBuffer = ( uint8 * ) FMemory : : Malloc ( OutBufferSize ) ;
FMemory : : Memset ( OutBuffer , 0 , OutBufferSize ) ;
size_t BytesDecrypted = 0 ;
CCCryptorStatus Status = CCCrypt ( kCCDecrypt , kCCAlgorithmAES128 ,
kCCOptionPKCS7Padding , Key , kCCKeySizeAES128 , NULL , SrcBuffer ,
SrcLen , OutBuffer , OutBufferSize , & BytesDecrypted ) ;
if ( Status = = kCCSuccess )
{
DestLen = BytesDecrypted ;
FMemory : : Memcpy ( DestBuffer , OutBuffer , DestLen ) ;
bDecryptedOk = true ;
}
else
{
UE_LOG ( LogTaskBrowser , Log , TEXT ( " CCCrypt failed w/ 0x%08x " ) , Status ) ;
}
FMemory : : Free ( OutBuffer ) ;
2014-07-08 00:06:17 -04:00
# elif PLATFORM_LINUX
printf ( " STaskBrowser.cpp: LINUX DecryptBuffer() \n " ) ;
2014-06-05 17:11:45 -04:00
# elif PLATFORM_WINDOWS
2014-03-14 14:13:41 -04:00
DATA_BLOB SourceBlob , EntropyBlob , FinalBlob ;
// Set up the datablob to encrypt
SourceBlob . cbData = SrcLen ;
SourceBlob . pbData = ( uint8 * ) SrcBuffer ;
// Get the mac address for mixing into the entropy (ties the encryption to a location)
ULONGLONG MacAddress = 0 ;
uint32 AddressSize = sizeof ( ULONGLONG ) ;
GetMacAddress ( ( uint8 * ) & MacAddress , AddressSize ) ;
// Set up the entropy blob
ULONGLONG Entropy = 5148284414757334885u i64 ;
Entropy ^ = MacAddress ;
EntropyBlob . cbData = sizeof ( ULONGLONG ) ;
EntropyBlob . pbData = ( uint8 * ) & Entropy ;
// Zero the output data
FMemory : : Memzero ( & FinalBlob , sizeof ( DATA_BLOB ) ) ;
// Now encrypt the data
if ( CryptUnprotectData ( & SourceBlob ,
NULL ,
& EntropyBlob ,
NULL ,
NULL ,
CRYPTPROTECT_UI_FORBIDDEN ,
& FinalBlob ) )
{
if ( FinalBlob . cbData < = DestLen )
{
// Copy the final results
DestLen = FinalBlob . cbData ;
FMemory : : Memcpy ( DestBuffer , FinalBlob . pbData , DestLen ) ;
bDecryptedOk = true ;
}
// Free the decryption buffer
LocalFree ( FinalBlob . pbData ) ;
}
2014-06-05 17:11:45 -04:00
# else
unimplemented ( ) ;
# endif
2014-03-14 14:13:41 -04:00
return bDecryptedOk ;
}
//////////////////////////////////////////////////////////////////////////
// FTaskBrowserSettings
FTaskBrowserSettings : : FTaskBrowserSettings ( )
: ServerName ( ) ,
ServerPort ( 80 ) ,
UserName ( ) ,
Password ( ) ,
ProjectName ( ) ,
bAutoConnectAtStartup ( false ) ,
bUseSingleSignOn ( true ) ,
DBFilterName ( ) ,
bFilterOnlyOpen ( true ) ,
bFilterAssignedToMe ( false ) ,
bFilterCreatedByMe ( false ) ,
bFilterCurrentMap ( false ) ,
TaskListSortColumn ( static_cast < int32 > ( EField : : Priority ) ) ,
bTaskListSortAscending ( true )
{
// Load default settings for Epic task database server here
// NOTE: Licensees, you may want to replace the following to suit your own needs
GConfig - > GetString ( TEXT ( " TaskBrowser " ) , TEXT ( " EpicDefaultServerName " ) , ServerName , GEditorIni ) ;
GConfig - > GetInt ( TEXT ( " TaskBrowser " ) , TEXT ( " EpicDefaultServerPort " ) , ServerPort , GEditorIni ) ;
GConfig - > GetString ( TEXT ( " TaskBrowser " ) , TEXT ( " EpicDefaultProjectName " ) , ProjectName , GEditorIni ) ;
GConfig - > GetString ( TEXT ( " TaskBrowser " ) , TEXT ( " EpicDefaultDBFilterName " ) , DBFilterName , GEditorIni ) ;
}
/** Loads settings from the configuration file */
void FTaskBrowserSettings : : LoadSettings ( )
{
GConfig - > GetString ( TEXT ( " TaskBrowser " ) , TEXT ( " ServerName " ) , ServerName , GEditorUserSettingsIni ) ;
GConfig - > GetInt ( TEXT ( " TaskBrowser " ) , TEXT ( " ServerPort " ) , ServerPort , GEditorUserSettingsIni ) ;
GConfig - > GetString ( TEXT ( " TaskBrowser " ) , TEXT ( " UserName " ) , UserName , GEditorUserSettingsIni ) ;
// Load encrypted password from disk
FString EncryptedPasswordBlob = GConfig - > GetStr ( TEXT ( " TaskBrowser " ) , TEXT ( " Password " ) , GEditorUserSettingsIni ) ;
Password = TEXT ( " " ) ;
const uint32 MaxEncryptedPasswordSize = 2048 ;
uint8 EncryptedPasswordBuffer [ MaxEncryptedPasswordSize ] ;
if ( FString : : ToBlob ( EncryptedPasswordBlob , EncryptedPasswordBuffer , MaxEncryptedPasswordSize ) )
{
const uint32 MaxDecryptedPasswordSize = 2048 ;
uint8 DecryptedPasswordBuffer [ MaxDecryptedPasswordSize ] ;
const uint32 ExpectedEncryptedPasswordSize = EncryptedPasswordBlob . Len ( ) / 3 ;
uint32 DecryptedPasswordSize = MaxDecryptedPasswordSize ;
if ( DecryptBuffer (
EncryptedPasswordBuffer ,
ExpectedEncryptedPasswordSize ,
DecryptedPasswordBuffer ,
DecryptedPasswordSize ) )
{
FString DecryptedPassword = ( const TCHAR * ) DecryptedPasswordBuffer ;
// Store password
Password = DecryptedPassword ;
}
}
GConfig - > GetString ( TEXT ( " TaskBrowser " ) , TEXT ( " ProjectName " ) , ProjectName , GEditorUserSettingsIni ) ;
GConfig - > GetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " AutoConnectAtStartup " ) , bAutoConnectAtStartup , GEditorUserSettingsIni ) ;
GConfig - > GetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " UseSingleSignOn " ) , bUseSingleSignOn , GEditorUserSettingsIni ) ;
GConfig - > GetString ( TEXT ( " TaskBrowser " ) , TEXT ( " DBFilterName " ) , DBFilterName , GEditorUserSettingsIni ) ;
GConfig - > GetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " FilterOnlyOpen " ) , bFilterOnlyOpen , GEditorUserSettingsIni ) ;
GConfig - > GetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " FilterAssignedToMe " ) , bFilterAssignedToMe , GEditorUserSettingsIni ) ;
GConfig - > GetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " FilterCreatedByMe " ) , bFilterCreatedByMe , GEditorUserSettingsIni ) ;
GConfig - > GetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " FilterCurrentMap " ) , bFilterCurrentMap , GEditorUserSettingsIni ) ;
GConfig - > GetInt ( TEXT ( " TaskBrowser " ) , TEXT ( " TaskListSortColumn " ) , TaskListSortColumn , GEditorUserSettingsIni ) ;
GConfig - > GetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " TaskListSortAscending " ) , bTaskListSortAscending , GEditorUserSettingsIni ) ;
}
/** Saves settings to the configuration file */
void FTaskBrowserSettings : : SaveSettings ( )
{
GConfig - > SetString ( TEXT ( " TaskBrowser " ) , TEXT ( " ServerName " ) , * ServerName , GEditorUserSettingsIni ) ;
GConfig - > SetInt ( TEXT ( " TaskBrowser " ) , TEXT ( " ServerPort " ) , ServerPort , GEditorUserSettingsIni ) ;
GConfig - > SetString ( TEXT ( " TaskBrowser " ) , TEXT ( " UserName " ) , * UserName , GEditorUserSettingsIni ) ;
bool bHaveValidPassword = false ;
if ( Password . Len ( ) > 0 )
{
// Store the user's password encrypted on disk
const uint32 MaxEncryptedPasswordSize = 2048 ;
uint8 EncryptedPasswordBuffer [ MaxEncryptedPasswordSize ] ;
uint32 EncryptedPasswordSize = MaxEncryptedPasswordSize ;
if ( EncryptBuffer (
( const uint8 * ) & Password [ 0 ] ,
( Password . Len ( ) + 1 ) * sizeof ( TCHAR ) ,
EncryptedPasswordBuffer ,
EncryptedPasswordSize ) )
{
FString EncryptedPasswordBlob = FString : : FromBlob ( EncryptedPasswordBuffer , EncryptedPasswordSize ) ;
GConfig - > SetString ( TEXT ( " TaskBrowser " ) , TEXT ( " Password " ) , * EncryptedPasswordBlob , GEditorUserSettingsIni ) ;
bHaveValidPassword = true ;
}
}
if ( ! bHaveValidPassword )
{
// Empty password
GConfig - > SetString ( TEXT ( " TaskBrowser " ) , TEXT ( " Password " ) , TEXT ( " " ) , GEditorUserSettingsIni ) ;
}
GConfig - > SetString ( TEXT ( " TaskBrowser " ) , TEXT ( " ProjectName " ) , * ProjectName , GEditorUserSettingsIni ) ;
GConfig - > SetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " AutoConnectAtStartup " ) , bAutoConnectAtStartup , GEditorUserSettingsIni ) ;
GConfig - > SetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " UseSingleSignOn " ) , bUseSingleSignOn , GEditorUserSettingsIni ) ;
GConfig - > SetString ( TEXT ( " TaskBrowser " ) , TEXT ( " DBFilterName " ) , * DBFilterName , GEditorUserSettingsIni ) ;
GConfig - > SetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " FilterOnlyOpen " ) , bFilterOnlyOpen , GEditorUserSettingsIni ) ;
GConfig - > SetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " FilterAssignedToMe " ) , bFilterAssignedToMe , GEditorUserSettingsIni ) ;
GConfig - > SetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " FilterCreatedByMe " ) , bFilterCreatedByMe , GEditorUserSettingsIni ) ;
GConfig - > SetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " FilterCurrentMap " ) , bFilterCurrentMap , GEditorUserSettingsIni ) ;
GConfig - > SetInt ( TEXT ( " TaskBrowser " ) , TEXT ( " TaskListSortColumn " ) , TaskListSortColumn , GEditorUserSettingsIni ) ;
GConfig - > SetBool ( TEXT ( " TaskBrowser " ) , TEXT ( " TaskListSortAscending " ) , bTaskListSortAscending , GEditorUserSettingsIni ) ;
}
/** Returns true if the current connection settings are valid */
bool FTaskBrowserSettings : : AreConnectionSettingsValid ( ) const
{
if ( ServerName . Len ( ) = = 0 | |
ServerPort = = 0 | |
UserName . Len ( ) = = 0 | |
Password . Len ( ) = = 0 | |
ProjectName . Len ( ) = = 0 )
{
return false ;
}
return true ;
}
//////////////////////////////////////////////////////////////////////////
// FTaskOverview
TMap < EField , FName > FTaskOverview : : FieldNames ;
FTaskOverview : : FTaskOverview ( const FTaskDatabaseEntry & InEntry )
: FTaskDatabaseEntry ( )
{
Number = InEntry . Number ;
Priority = InEntry . Priority ;
Summary = InEntry . Summary ;
Status = InEntry . Status ;
CreatedBy = InEntry . CreatedBy ;
AssignedTo = InEntry . AssignedTo ;
}
FString FTaskOverview : : GetFieldEntry ( const FName InName ) const
{
// Retrieve the key from the name specified
PopulateFieldNames ( ) ;
const EField * FieldPtr = FieldNames . FindKey ( InName ) ;
check ( FieldPtr ) ;
// Convert the field to it's equivalent property
check ( * FieldPtr > EField : : Invalid ) ;
check ( * FieldPtr < EField : : NumColumnIDs ) ;
switch ( * FieldPtr )
{
case EField : : Number :
return FString : : FromInt ( Number ) ;
case EField : : Priority :
return Priority ;
case EField : : Summary :
return Summary ;
case EField : : Status :
return Status ;
case EField : : CreatedBy :
return CreatedBy ;
case EField : : AssignedTo :
return AssignedTo ;
}
return TEXT ( " " ) ;
}
FName FTaskOverview : : GetFieldName ( const EField InField )
{
// Retrieve the value from the field specified
PopulateFieldNames ( ) ;
const FName * NamePtr = FieldNames . Find ( InField ) ;
check ( NamePtr ) ;
return * NamePtr ;
}
void FTaskOverview : : PopulateFieldNames ( )
{
// Fill our map if it's empty
if ( FieldNames . Num ( ) = = 0 )
{
FieldNames . Add ( EField : : Number , FName ( TEXT ( " Number " ) ) ) ;
FieldNames . Add ( EField : : Priority , FName ( TEXT ( " Priority " ) ) ) ;
FieldNames . Add ( EField : : Summary , FName ( TEXT ( " Summary " ) ) ) ;
FieldNames . Add ( EField : : Status , FName ( TEXT ( " Status " ) ) ) ;
FieldNames . Add ( EField : : CreatedBy , FName ( TEXT ( " CreatedBy " ) ) ) ;
FieldNames . Add ( EField : : AssignedTo , FName ( TEXT ( " AssignedTo " ) ) ) ;
}
}
//////////////////////////////////////////////////////////////////////////
// STaskOverview
class STaskTreeWidgetItem : public SMultiColumnTableRow < TSharedPtr < FTaskOverview > >
{
public :
SLATE_BEGIN_ARGS ( STaskTreeWidgetItem )
: _WidgetInfoToVisualize ( )
{ }
SLATE_ARGUMENT ( TSharedPtr < FTaskOverview > , WidgetInfoToVisualize )
SLATE_END_ARGS ( )
/**
* Construct child widgets that comprise this widget .
*
* @ param InArgs Declaration from which to construct this widget
*/
void Construct ( const FArguments & InArgs , const TSharedRef < STableViewBase > & InOwnerTableView )
{
this - > WidgetInfo = InArgs . _WidgetInfoToVisualize ;
SMultiColumnTableRow < TSharedPtr < FTaskOverview > > : : Construct ( FSuperRowType : : FArguments ( ) , InOwnerTableView ) ;
}
/** @return Widget based on the column name */
2014-06-13 06:14:46 -04:00
virtual TSharedRef < SWidget > GenerateWidgetForColumn ( const FName & ColumnName ) override
2014-03-14 14:13:41 -04:00
{
const FString Entry = WidgetInfo . Get ( ) - > GetFieldEntry ( ColumnName ) ;
return
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 2 )
[
SNew ( STextBlock )
. Text ( Entry )
] ;
}
protected :
/** The info about the widget that we are visualizing */
TAttribute < TSharedPtr < FTaskOverview > > WidgetInfo ;
} ;
//////////////////////////////////////////////////////////////////////////
// STaskBrowser
/**
* Construct the widget
*
* @ param InArgs A declaration from which to construct the widget
*/
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void STaskBrowser : : Construct ( const FArguments & InArgs )
{
// Create task data manager instance
TaskDataManager = MakeShareable ( new FTaskDataManager ( this ) ) ;
// Load preferences
FTaskBrowserSettings TBSettings ;
TBSettings . LoadSettings ( ) ;
// Propagate server connection settings to the task data manager
FTaskDataManagerConnectionSettings ConnectionSettings ;
{
ConnectionSettings . ServerName = TBSettings . ServerName ;
ConnectionSettings . ServerPort = TBSettings . ServerPort ;
ConnectionSettings . UserName = TBSettings . UserName ;
ConnectionSettings . Password = TBSettings . Password ;
ConnectionSettings . ProjectName = TBSettings . ProjectName ;
}
TaskDataManager - > SetConnectionSettings ( ConnectionSettings ) ;
// Set column sorting rules
EField eField = static_cast < EField > ( TBSettings . TaskListSortColumn ) ;
TaskListSortColumn = ( ( eField > EField : : Invalid & & eField < EField : : NumColumnIDs ) ? eField : EField : : Priority ) ;
TaskListSortAscending = TBSettings . bTaskListSortAscending ;
TaskListNumSelectedAndOpen = - 1 ;
// Automatically connect to the server if we were asked to do that
if ( TBSettings . bAutoConnectAtStartup & & TBSettings . AreConnectionSettingsValid ( ) )
{
TaskDataManager - > AttemptConnection ( ) ;
}
// Standard paddings
const FMargin BorderPadding ( 6 , 6 ) ;
const FMargin ButtonPadding ( 8 , 4 ) ;
const FMargin SmallPadding ( 0 , 0 , 12 , 0 ) ;
const FMargin XLargePadding ( 0 , 0 , 48 , 0 ) ;
this - > ChildSlot
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. Padding ( BorderPadding )
. FillHeight ( 0.45f )
[
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " ToolPanel.GroupBorder " ) )
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( BorderPadding )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( SmallPadding )
[
SAssignNew ( MarkComplete , SButton )
. ContentPadding ( ButtonPadding )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
. IsEnabled_Raw ( this , & STaskBrowser : : GetMarkCompleteEnabled )
. OnClicked ( this , & STaskBrowser : : OnMarkCompleteClicked )
[
2014-04-23 18:06:41 -04:00
SNew ( STextBlock ) . Text ( LOCTEXT ( " MarkComplete " , " Mark Complete... " ) )
2014-03-14 14:13:41 -04:00
]
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( XLargePadding )
[
SAssignNew ( RefreshView , SButton )
. ContentPadding ( ButtonPadding )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
. OnClicked ( this , & STaskBrowser : : OnRefreshViewClicked )
[
2014-04-23 18:06:41 -04:00
SNew ( STextBlock ) . Text ( LOCTEXT ( " RefreshView " , " Refresh View " ) )
2014-03-14 14:13:41 -04:00
]
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( SmallPadding )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
[
2014-04-23 18:06:41 -04:00
SNew ( STextBlock ) . Text ( LOCTEXT ( " DatabaseFilter " , " Database filter " ) )
2014-03-14 14:13:41 -04:00
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( SmallPadding )
[
SAssignNew ( DatabaseFilter , STextComboBox )
. OptionsSource ( & DatabaseOptions )
. OnSelectionChanged ( this , & STaskBrowser : : OnDatabaseFilterSelect )
]
]
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( BorderPadding )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( SmallPadding )
[
2014-04-23 18:06:41 -04:00
SNew ( STextBlock ) . Text ( LOCTEXT ( " Display " , " Display " ) )
2014-03-14 14:13:41 -04:00
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SAssignNew ( OpenOnly , SCheckBox )
. OnCheckStateChanged ( this , & STaskBrowser : : OnOpenOnlyChanged )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( SmallPadding )
[
2014-04-23 18:06:41 -04:00
SNew ( STextBlock ) . Text ( LOCTEXT ( " OpenOnly " , " Open only " ) )
2014-03-14 14:13:41 -04:00
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SAssignNew ( AssignedToMe , SCheckBox )
. OnCheckStateChanged ( this , & STaskBrowser : : OnAssignedToMeChanged )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( SmallPadding )
[
2014-04-23 18:06:41 -04:00
SNew ( STextBlock ) . Text ( LOCTEXT ( " AssignedToMe " , " Assigned to me " ) )
2014-03-14 14:13:41 -04:00
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SAssignNew ( CreatedByMe , SCheckBox )
. OnCheckStateChanged ( this , & STaskBrowser : : OnCreatedByMeChanged )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( SmallPadding )
[
2014-04-23 18:06:41 -04:00
SNew ( STextBlock ) . Text ( LOCTEXT ( " CreatedByMe " , " Created by me " ) )
2014-03-14 14:13:41 -04:00
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SAssignNew ( CurrentMap , SCheckBox )
. OnCheckStateChanged ( this , & STaskBrowser : : OnCurrentMapChanged )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( SmallPadding )
[
2014-04-23 18:06:41 -04:00
SNew ( STextBlock ) . Text ( LOCTEXT ( " CurrentMap " , " Current map " ) )
2014-03-14 14:13:41 -04:00
]
]
+ SVerticalBox : : Slot ( )
. Padding ( BorderPadding )
. FillHeight ( 1.0f )
[
SNew ( SBox )
. Padding ( BorderPadding )
[
SAssignNew ( TaskList , SListView < TSharedPtr < FTaskOverview > > )
// .SelectionMode(ESelectionMode::Single)
. ItemHeight ( 24 )
. ListItemsSource ( & TaskEntries )
. OnGenerateRow ( this , & STaskBrowser : : OnTaskGenerateRow )
. OnSelectionChanged ( this , & STaskBrowser : : OnTaskSelectionChanged )
. OnMouseButtonDoubleClick ( this , & STaskBrowser : : OnTaskDoubleClicked )
. HeaderRow
(
SAssignNew ( TaskHeaders , SHeaderRow ) // @TODO as a workaround to columns not registering mouse clicks, use buttons instead
+ SHeaderRow : : Column ( FTaskOverview : : GetFieldName ( EField : : Number ) )
. FillWidth ( 90.0f )
[
SNew ( STaskColumn )
. TaskBrowser ( SharedThis ( this ) )
. Field ( EField : : Number )
]
+ SHeaderRow : : Column ( FTaskOverview : : GetFieldName ( EField : : Priority ) )
. FillWidth ( 150.0f )
[
SNew ( STaskColumn )
. TaskBrowser ( SharedThis ( this ) )
. Field ( EField : : Priority )
]
+ SHeaderRow : : Column ( FTaskOverview : : GetFieldName ( EField : : Summary ) )
. FillWidth ( 360.0f )
[
SNew ( STaskColumn )
. TaskBrowser ( SharedThis ( this ) )
. Field ( EField : : Summary )
]
+ SHeaderRow : : Column ( FTaskOverview : : GetFieldName ( EField : : AssignedTo ) )
. FillWidth ( 150.0f )
[
SNew ( STaskColumn )
. TaskBrowser ( SharedThis ( this ) )
. Field ( EField : : AssignedTo )
]
+ SHeaderRow : : Column ( FTaskOverview : : GetFieldName ( EField : : Status ) )
. FillWidth ( 200.0f )
[
SNew ( STaskColumn )
. TaskBrowser ( SharedThis ( this ) )
. Field ( EField : : Status )
]
+ SHeaderRow : : Column ( FTaskOverview : : GetFieldName ( EField : : CreatedBy ) )
. FillWidth ( 150.0f )
[
SNew ( STaskColumn )
. TaskBrowser ( SharedThis ( this ) )
. Field ( EField : : CreatedBy )
]
)
]
]
]
]
+ SVerticalBox : : Slot ( )
. Padding ( BorderPadding )
. FillHeight ( 0.55f )
[
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " ToolPanel.GroupBorder " ) )
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( BorderPadding )
[
SAssignNew ( Summary , SEditableTextBox ) . IsReadOnly ( true )
]
+ SVerticalBox : : Slot ( )
. Padding ( BorderPadding )
. FillHeight ( 1.0f )
[
SAssignNew ( Description , SEditableTextBox ) . IsReadOnly ( true )
]
]
]
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( BorderPadding )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( SmallPadding )
[
SAssignNew ( Connect , SButton )
. ContentPadding ( ButtonPadding )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
. IsEnabled_Raw ( this , & STaskBrowser : : GetConnectEnabled )
. OnClicked ( this , & STaskBrowser : : OnConnectClicked )
[
SNew ( STextBlock ) . Text_Raw ( this , & STaskBrowser : : GetConnectText )
]
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( SmallPadding )
[
SAssignNew ( Settings , SButton )
. ContentPadding ( ButtonPadding )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
. OnClicked ( this , & STaskBrowser : : OnSettingsClicked )
[
2014-04-23 18:06:41 -04:00
SNew ( STextBlock ) . Text ( LOCTEXT ( " Settings " , " Settings... " ) )
2014-03-14 14:13:41 -04:00
]
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( SmallPadding )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock ) . Text_Raw ( this , & STaskBrowser : : GetStatusText )
]
]
] ;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
TSharedRef < SWidget > STaskBrowser : : GetContent ( )
{
return SharedThis ( this ) ;
}
STaskBrowser : : ~ STaskBrowser ( )
{
// Cleanup task data manager
TaskDataManager . Reset ( ) ;
}
bool STaskBrowser : : GetMarkCompleteEnabled ( ) const
{
// Update the 'Fix' button
bool bEnableFixButton = false ;
// Must be connected to the server
if ( TaskDatabaseSystem : : IsConnected ( ) )
{
// Only enable the 'Mark as Fixed' button if at least one *OPEN* task is selected
if ( TaskListNumSelectedAndOpen > 0 )
{
bEnableFixButton = true ;
}
}
return bEnableFixButton ;
}
FReply STaskBrowser : : OnMarkCompleteClicked ( )
{
const bool bOnlyOpenTasks = true ;
TArray < uint32 > TaskNumbersToFix ;
QuerySelectedTaskNumbers ( TaskNumbersToFix , bOnlyOpenTasks ) ;
if ( TaskNumbersToFix . Num ( ) > 0 )
{
CompleteTaskDialog ( TaskNumbersToFix ) ;
}
return FReply : : Handled ( ) ;
}
FReply STaskBrowser : : OnRefreshViewClicked ( )
{
// Update everything using fresh data from the server
TaskDataManager - > ClearTaskDataAndInitiateRefresh ( ) ;
return FReply : : Handled ( ) ;
}
void STaskBrowser : : OnDatabaseFilterSelect ( TSharedPtr < FString > InFilter , ESelectInfo : : Type SelectInfo )
{
// Update the active filter!
TaskDataManager - > ChangeActiveFilter ( * InFilter ) ;
// Save the new filter name in our preferences
{
FTaskBrowserSettings TBSettings ;
TBSettings . LoadSettings ( ) ;
TBSettings . DBFilterName = * InFilter ;
TBSettings . SaveSettings ( ) ;
}
}
void STaskBrowser : : OnOpenOnlyChanged ( const ESlateCheckBoxState : : Type NewCheckedState )
{
// Refresh the GUI. It will apply the updated filters.
RefreshGUI ( ETaskBrowserGUIRefreshOptions : : RebuildTaskList ) ;
// A filter was changed, so save updated settings to disk
{
FTaskBrowserSettings TBSettings ;
TBSettings . LoadSettings ( ) ;
TBSettings . bFilterOnlyOpen = ! ! NewCheckedState ;
TBSettings . SaveSettings ( ) ;
}
}
void STaskBrowser : : OnAssignedToMeChanged ( const ESlateCheckBoxState : : Type NewCheckedState )
{
// Refresh the GUI. It will apply the updated filters.
RefreshGUI ( ETaskBrowserGUIRefreshOptions : : RebuildTaskList ) ;
// A filter was changed, so save updated settings to disk
{
FTaskBrowserSettings TBSettings ;
TBSettings . LoadSettings ( ) ;
TBSettings . bFilterAssignedToMe = ! ! NewCheckedState ;
TBSettings . SaveSettings ( ) ;
}
}
void STaskBrowser : : OnCreatedByMeChanged ( const ESlateCheckBoxState : : Type NewCheckedState )
{
// Refresh the GUI. It will apply the updated filters.
RefreshGUI ( ETaskBrowserGUIRefreshOptions : : RebuildTaskList ) ;
// A filter was changed, so save updated settings to disk
{
FTaskBrowserSettings TBSettings ;
TBSettings . LoadSettings ( ) ;
TBSettings . bFilterCreatedByMe = ! ! NewCheckedState ;
TBSettings . SaveSettings ( ) ;
}
}
void STaskBrowser : : OnCurrentMapChanged ( const ESlateCheckBoxState : : Type NewCheckedState )
{
// Refresh the GUI. It will apply the updated filters.
RefreshGUI ( ETaskBrowserGUIRefreshOptions : : RebuildTaskList ) ;
// A filter was changed, so save updated settings to disk
{
FTaskBrowserSettings TBSettings ;
TBSettings . LoadSettings ( ) ;
TBSettings . bFilterCurrentMap = ! ! NewCheckedState ;
TBSettings . SaveSettings ( ) ;
}
}
TSharedRef < ITableRow > STaskBrowser : : OnTaskGenerateRow ( TSharedPtr < FTaskOverview > InTaskOverview , const TSharedRef < STableViewBase > & OwnerTable )
{
return
SNew ( STaskTreeWidgetItem , OwnerTable )
. WidgetInfoToVisualize ( InTaskOverview ) ;
}
void STaskBrowser : : OnTaskSelectionChanged ( TSharedPtr < FTaskOverview > InTaskOverview , ESelectInfo : : Type /*SelectInfo*/ )
{
// Make sure the task data manager is keep track of this task
if ( InTaskOverview . IsValid ( ) )
{
TaskDataManager - > SetFocusedTaskNumber ( InTaskOverview - > Number ) ;
}
else
{
TaskDataManager - > SetFocusedTaskNumber ( INDEX_NONE ) ;
}
// Refresh the cached values for our Mark Complete button
TaskListNumSelectedAndOpen = GetNumSelectedTasks ( true ) ;
RefreshGUI ( ETaskBrowserGUIRefreshOptions : : UpdateTaskDescription ) ;
}
int32 STaskBrowser : : GetNumSelectedTasks ( const bool bOnlyOpenTasks ) const
{
// Just retrieve how maybe we have of that type
TArray < uint32 > SelectedTaskNumbers ;
QuerySelectedTaskNumbers ( SelectedTaskNumbers , bOnlyOpenTasks ) ;
const int32 iSelectedTaskNumbers = SelectedTaskNumbers . Num ( ) ;
return iSelectedTaskNumbers ;
}
void STaskBrowser : : OnTaskDoubleClicked ( TSharedPtr < FTaskOverview > InTaskOverview )
{
// Check to see if the bug status is "Open"
if ( InTaskOverview . IsValid ( ) & & InTaskOverview - > Status . StartsWith ( TaskDataManager - > GetOpenTaskStatusPrefix ( ) ) )
{
// Add this task's number to our list of tasks to fix
TArray < uint32 > TaskNumbersToFix ;
TaskNumbersToFix . Add ( InTaskOverview - > Number ) ;
CompleteTaskDialog ( TaskNumbersToFix ) ;
}
}
FReply STaskBrowser : : OnTaskColumnClicked ( const EField InField )
{
check ( InField > EField : : Invalid ) ;
check ( InField < EField : : NumColumnIDs )
if ( InField = = TaskListSortColumn )
{
// Clicking on the same column will flip the sort order
TaskListSortAscending = ! TaskListSortAscending ;
}
else
{
// Clicking on a new column will set that column as current and reset the sort order.
TaskListSortColumn = InField ;
TaskListSortAscending = true ;
}
// Save the sorting configuration
FTaskBrowserSettings TBSettings ;
TBSettings . LoadSettings ( ) ;
TBSettings . TaskListSortColumn = static_cast < int32 > ( TaskListSortColumn ) ;
TBSettings . bTaskListSortAscending = TaskListSortAscending ;
TBSettings . SaveSettings ( ) ;
// Refresh the GUI
RefreshGUI ( ETaskBrowserGUIRefreshOptions : : SortTaskList ) ;
return FReply : : Handled ( ) ;
}
bool STaskBrowser : : GetConnectEnabled ( ) const
{
switch ( TaskDataManager - > GetConnectionStatus ( ) )
{
case ETaskDataManagerStatus : : FailedToInit :
case ETaskDataManagerStatus : : Connecting :
case ETaskDataManagerStatus : : Disconnecting :
return false ;
default :
return true ;
}
}
FReply STaskBrowser : : OnConnectClicked ( )
{
if ( TaskDataManager - > GetConnectionStatus ( ) ! = ETaskDataManagerStatus : : FailedToInit )
{
if ( TaskDataManager - > GetConnectionStatus ( ) = = ETaskDataManagerStatus : : ReadyToConnect | |
TaskDataManager - > GetConnectionStatus ( ) = = ETaskDataManagerStatus : : ConnectionFailed )
{
// Did the user cancel the config dialog?
bool bUserCancelled = false ;
// Load server settings from disk
FTaskBrowserSettings TBSettings ;
TBSettings . LoadSettings ( ) ;
// Make sure that everything is valid, otherwise pop up a settings dialog
if ( ! TBSettings . AreConnectionSettingsValid ( ) )
{
// Give the user a chance to fix the settings
SettingsDialog ( ) ;
}
if ( TBSettings . AreConnectionSettingsValid ( ) )
{
// Connection failed, so allow the user to try again
TaskDataManager - > AttemptConnection ( ) ;
}
else
{
// Only warn the user if the user did not press cancel
if ( ! bUserCancelled )
{
// Warn the user that we'll need valid settings in order to connect to the server
FMessageDialog : : Open ( EAppMsgType : : Ok , NSLOCTEXT ( " UnrealEd " , " TaskBrowser_Error_NeedValidConnectionSettings " , " In order for the Task Browser to connect to the database server, you'll need to supply valid settings for the server name/port, user name and password, as well as the project (database) name to connect to. If you're not sure what settings to use then please ask a system administrator, or check the similar settings in desktop task management application's configuration. " ) ) ;
}
}
}
else
{
// Queue a disconnect
TaskDataManager - > AttemptDisconnection ( ) ;
}
}
return FReply : : Handled ( ) ;
}
2014-04-23 18:06:41 -04:00
FText STaskBrowser : : GetConnectText ( ) const
2014-03-14 14:13:41 -04:00
{
switch ( TaskDataManager - > GetConnectionStatus ( ) )
{
case ETaskDataManagerStatus : : FailedToInit :
case ETaskDataManagerStatus : : ReadyToConnect :
case ETaskDataManagerStatus : : ConnectionFailed :
case ETaskDataManagerStatus : : Disconnecting :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_ConnectButtonLabel " , " Connect " ) ;
2014-03-14 14:13:41 -04:00
default :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_DisconnectButtonLabel " , " Disconnect " ) ;
2014-03-14 14:13:41 -04:00
}
}
FReply STaskBrowser : : OnSettingsClicked ( )
{
SettingsDialog ( ) ;
return FReply : : Handled ( ) ;
}
2014-04-23 18:06:41 -04:00
FText STaskBrowser : : GetStatusText ( ) const
2014-03-14 14:13:41 -04:00
{
switch ( TaskDataManager - > GetGUIStatus ( ) )
{
case ETaskDataManagerStatus : : ReadyToConnect :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_ServerStatus_ReadyToConnect " , " Not connected. Click the Connect button to login to the task database. " ) ;
2014-03-14 14:13:41 -04:00
case ETaskDataManagerStatus : : Connecting :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_ServerStatus_Connecting " , " Connecting to server and logging in... " ) ;
2014-03-14 14:13:41 -04:00
case ETaskDataManagerStatus : : Connected :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_ServerStatus_Connected " , " Connected to the task database. " ) ;
2014-03-14 14:13:41 -04:00
case ETaskDataManagerStatus : : ConnectionFailed :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_ServerStatus_ConnectionFailed " , " Failed to connect to the task database. Click the Connect button to try again. " ) ;
2014-03-14 14:13:41 -04:00
case ETaskDataManagerStatus : : Disconnecting :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_ServerStatus_Disconnecting " , " Disconnecting... " ) ;
2014-03-14 14:13:41 -04:00
case ETaskDataManagerStatus : : QueryingFilters :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_ServerStatus_QueryingFilters " , " Retrieving filters... " ) ;
2014-03-14 14:13:41 -04:00
case ETaskDataManagerStatus : : QueryingTasks :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_ServerStatus_QueryingTasks " , " Retrieving task list from server... " ) ;
2014-03-14 14:13:41 -04:00
case ETaskDataManagerStatus : : QueryingTaskDetails :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_ServerStatus_QueryingTaskDetails " , " Retrieving task information... " ) ;
2014-03-14 14:13:41 -04:00
case ETaskDataManagerStatus : : MarkingTaskComplete :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_ServerStatus_MarkingTaskComplete " , " Marking task as fixed... " ) ;
2014-03-14 14:13:41 -04:00
default :
2014-04-23 18:06:41 -04:00
return NSLOCTEXT ( " UnrealEd " , " TaskBrowser_ServerStatus_FailedToInit " , " Failed to initialize. No task database providers are available. " ) ;
2014-03-14 14:13:41 -04:00
}
}
void STaskBrowser : : CompleteTaskDialog ( TArray < uint32 > & TaskNumbersToFix )
{
// Create a new modal settings dialog
const TArray < FString > & ResolutionValues = TaskDataManager - > GetResolutionValues ( ) ;
FTaskResolutionData ResolutionData ;
TSharedRef < SWindow > WidgetWindow = SNew ( SWindow )
. Title ( LOCTEXT ( " TaskBrowserComplete " , " Mark Task Complete " ) )
. ClientSize ( FVector2D ( 516 , 273 ) )
. SizingRule ( ESizingRule : : FixedSize )
. SupportsMinimize ( false ) . SupportsMaximize ( false ) ;
WidgetWindow - > SetContent
(
SNew ( STaskComplete )
. WidgetWindow ( WidgetWindow )
. ResolutionData ( & ResolutionData )
. ResolutionValues ( & ResolutionValues )
) ;
GEditor - > EditorAddModalWindow ( WidgetWindow ) ;
if ( ResolutionData . IsValid ( ) )
{
// Queue these up to be marked as fixed!
TaskDataManager - > StartMarkingTasksComplete ( TaskNumbersToFix , ResolutionData ) ;
}
}
/** Spawn our settings modal dialog */
void STaskBrowser : : SettingsDialog ( void )
{
// Create a new modal settings dialog
TSharedRef < SWindow > WidgetWindow = SNew ( SWindow )
. Title ( LOCTEXT ( " TaskBrowserSettings " , " Task Browser Settings " ) )
. ClientSize ( FVector2D ( 376 , 327 ) )
. SizingRule ( ESizingRule : : FixedSize )
. SupportsMinimize ( false ) . SupportsMaximize ( false ) ;
WidgetWindow - > SetContent
(
SNew ( STaskSettings )
. WidgetWindow ( WidgetWindow )
) ;
GEditor - > EditorAddModalWindow ( WidgetWindow ) ;
// Update the task data manager with any settings that may have changed
FTaskBrowserSettings TBSettings ;
TBSettings . LoadSettings ( ) ;
FTaskDataManagerConnectionSettings NewConnectionSettings ;
{
NewConnectionSettings . ServerName = TBSettings . ServerName ;
NewConnectionSettings . ServerPort = TBSettings . ServerPort ;
NewConnectionSettings . UserName = TBSettings . UserName ;
NewConnectionSettings . Password = TBSettings . Password ;
NewConnectionSettings . ProjectName = TBSettings . ProjectName ;
}
TaskDataManager - > SetConnectionSettings ( NewConnectionSettings ) ;
}
void STaskBrowser : : QuerySelectedTaskNumbers ( TArray < uint32 > & OutSelectedTaskNumbers , const bool bOnlyOpenTasks ) const
{
OutSelectedTaskNumbers . Reset ( ) ;
// Create a list of task numbers that are currently selected in the task list
TArray < TSharedPtr < FTaskOverview > > SelectedTasks = TaskList - > GetSelectedItems ( ) ;
for ( int32 iSelectedTask = 0 ; iSelectedTask < SelectedTasks . Num ( ) ; iSelectedTask + + )
{
TSharedPtr < FTaskOverview > SelectedTask = SelectedTasks [ iSelectedTask ] ;
// Make sure the task isn't already completed
if ( ! bOnlyOpenTasks | | SelectedTask - > Status . StartsWith ( TaskDataManager - > GetOpenTaskStatusPrefix ( ) ) )
{
// Add this task's number to our list of tasks
OutSelectedTaskNumbers . Add ( SelectedTask - > Number ) ;
}
}
}
bool STaskBrowser : : TaskListItemSort ( const TSharedPtr < FTaskOverview > TaskEntryA , const TSharedPtr < FTaskOverview > TaskEntryB ) const
{
int SortResult = 0 ;
check ( TaskListSortColumn > EField : : Invalid ) ;
check ( TaskListSortColumn < EField : : NumColumnIDs ) ;
switch ( TaskListSortColumn )
{
case EField : : Number :
if ( TaskEntryA - > Number ! = TaskEntryB - > Number )
{
SortResult = TaskEntryA - > Number > TaskEntryB - > Number ? 1 : - 1 ;
}
break ;
case EField : : Priority :
SortResult = FCString : : Stricmp ( * TaskEntryA - > Priority , * TaskEntryB - > Priority ) ;
break ;
case EField : : Summary :
SortResult = FCString : : Stricmp ( * TaskEntryA - > Summary , * TaskEntryB - > Summary ) ;
break ;
case EField : : AssignedTo :
SortResult = FCString : : Stricmp ( * TaskEntryA - > AssignedTo , * TaskEntryB - > AssignedTo ) ;
break ;
case EField : : Status :
SortResult = FCString : : Stricmp ( * TaskEntryA - > Status , * TaskEntryB - > Status ) ;
break ;
case EField : : CreatedBy :
SortResult = FCString : : Stricmp ( * TaskEntryA - > CreatedBy , * TaskEntryB - > CreatedBy ) ;
break ;
}
// If the items had the same value, then fallback to secondary sort criteria
// @todo: Support custom secondary sorts (stack of sorted columns and ascend/descend state)
if ( SortResult = = 0 )
{
if ( TaskListSortColumn = = EField : : Number )
{
// Secondary sort by priority
SortResult = TaskEntryA - > Number > TaskEntryB - > Number ? 1 : - 1 ;
}
else
{
// Secondary sort by name
SortResult = FCString : : Stricmp ( * TaskEntryA - > Summary , * TaskEntryB - > Summary ) ;
}
}
// Reverse the sort order if we were asked to do that
if ( ! TaskListSortAscending )
{
SortResult = - SortResult ;
}
return ( SortResult > 0 ? true : false ) ;
}
void STaskBrowser : : TaskListItemSort ( )
{
// Early out if there's no elements in the list
if ( TaskEntries . Num ( ) = = 0 )
{
return ;
}
bool bChanged = false ; // Did the list change at all?
bool bSwapped = true ; // Has the list changed this round?, keep sorting til it doesn't
while ( bSwapped )
{
bSwapped = false ;
for ( int32 CurTaskIndex = 0 ; CurTaskIndex < TaskEntries . Num ( ) - 1 ; + + CurTaskIndex )
{
// Check to see if the elements need swapping
TSharedPtr < FTaskOverview > TaskEntryA = TaskEntries [ CurTaskIndex ] ;
TSharedPtr < FTaskOverview > TaskEntryB = TaskEntries [ CurTaskIndex + 1 ] ;
const bool bExchange = TaskListItemSort ( TaskEntryA , TaskEntryB ) ;
// Do we need to swap the two elements around?
if ( bExchange )
{
bChanged = true ;
bSwapped = true ;
TaskEntries [ CurTaskIndex ] = TaskEntryB ;
TaskEntries [ CurTaskIndex + 1 ] = TaskEntryA ;
//FMemory::Memswap( TaskEntryA.Get(), TaskEntryB.Get(), sizeof( FTaskOverview ) );
}
}
}
if ( bChanged )
{
TaskList - > RequestListRefresh ( ) ;
}
}
void STaskBrowser : : RefreshGUI ( const ETaskBrowserGUIRefreshOptions : : Type Options )
{
if ( Options & ETaskBrowserGUIRefreshOptions : : RebuildFilterList )
{
// Clear the contents of the list
DatabaseOptions . Empty ( ) ;
// Copy all of the filters over to our own cached array
TArray < FString > FilterNames = TaskDataManager - > GetCachedFilterNames ( ) ;
for ( int32 iFilter = 0 ; iFilter < FilterNames . Num ( ) ; + + iFilter )
{
const FString & CurFilterName = FilterNames [ iFilter ] ;
// Add this filter to our list
DatabaseOptions . Add ( MakeShareable ( new FString ( CurFilterName ) ) ) ;
}
// Do we have an active filter already?
int32 SelectedFilterIndex = INDEX_NONE ;
if ( TaskDataManager - > GetActiveFilterName ( ) . Len ( ) > 0 )
{
verify ( FilterNames . Find ( TaskDataManager - > GetActiveFilterName ( ) , SelectedFilterIndex ) ) ;
}
else
{
// No active filter yet, so we'll set one up now
FTaskBrowserSettings TBSettings ;
TBSettings . LoadSettings ( ) ;
// Search for the default filter name
if ( ! FilterNames . Find ( TBSettings . DBFilterName , SelectedFilterIndex ) )
{
// Not found... hrm..
if ( FilterNames . Num ( ) > 0 )
{
// Just use the first available filter
SelectedFilterIndex = 0 ;
}
}
if ( SelectedFilterIndex ! = INDEX_NONE )
{
// Select the filter in the list
DatabaseFilter - > SetSelectedItem ( DatabaseOptions [ SelectedFilterIndex ] ) ;
// Update task data manager
TaskDataManager - > ChangeActiveFilter ( FilterNames [ SelectedFilterIndex ] ) ;
}
}
}
if ( Options & ETaskBrowserGUIRefreshOptions : : RebuildTaskList )
{
// Grab a list of task numbers we already had selected
TSet < int32 > SelectedTaskNumberSet ;
{
const bool bOnlyOpenTasks = false ;
TArray < uint32 > SelectedTaskNumbers ;
QuerySelectedTaskNumbers ( SelectedTaskNumbers , bOnlyOpenTasks ) ;
// Add everything to a set so that we can do quick tests later on
for ( int32 CurTaskIndex = 0 ; CurTaskIndex < SelectedTaskNumbers . Num ( ) ; + + CurTaskIndex )
{
SelectedTaskNumberSet . Add ( SelectedTaskNumbers [ CurTaskIndex ] ) ;
}
}
// Check to see which 'display filters' are enabled
const bool bOnlyOpen = OpenOnly - > IsChecked ( ) ;
const bool bAssignedToMe = AssignedToMe - > IsChecked ( ) ;
const bool bCreatedByMe = CreatedByMe - > IsChecked ( ) ;
const bool bCurrentMap = CurrentMap - > IsChecked ( ) ;
// Grab the current loaded map name from the editor
// @todo: Register for event to auto refresh task list when map loaded or new?
FString CurrentMaNamePtr = GWorld - > GetMapName ( ) ;
{
const int32 MaxPrefixChars = 2 ;
const int32 MaxSuffixChars = 3 ;
if ( CurrentMaNamePtr . Len ( ) > MaxPrefixChars + 1 )
{
// Clean up any small prefixes or suffixes on the map name
int32 FirstUnderscore = CurrentMaNamePtr . Find ( TEXT ( " _ " ) ) ;
if ( FirstUnderscore ! = INDEX_NONE )
{
const int32 NumPrefixChars = FirstUnderscore ;
if ( NumPrefixChars < = MaxPrefixChars )
{
// Chop it!
CurrentMaNamePtr = CurrentMaNamePtr . Mid ( FirstUnderscore + 1 ) ;
}
}
}
// Chop off multiple small suffixes
bool bCheckForSuffix = true ;
while ( bCheckForSuffix )
{
bCheckForSuffix = false ;
if ( CurrentMaNamePtr . Len ( ) > MaxSuffixChars + 1 )
{
// Clean up any small prefixes or suffixes on the map name
int32 LastUnderscore = CurrentMaNamePtr . Find ( TEXT ( " _ " ) , ESearchCase : : CaseSensitive , ESearchDir : : FromEnd ) ;
if ( LastUnderscore ! = INDEX_NONE )
{
const int32 NumSuffixChars = CurrentMaNamePtr . Len ( ) - LastUnderscore ;
if ( NumSuffixChars < = MaxSuffixChars )
{
// Chop it!
CurrentMaNamePtr = CurrentMaNamePtr . Left ( LastUnderscore ) ;
// Check for another suffix!
bCheckForSuffix = true ;
}
}
}
}
}
// Clear everything
TaskEntries . Empty ( ) ;
TaskList - > ClearSelection ( ) ;
// Grab the current user's real name
FString UserRealName = TaskDataManager - > GetUserRealName ( ) ;
// Copy all of the task entries to our own cached array
const TArray < FTaskDatabaseEntry > & Tasks = TaskDataManager - > GetCachedTaskArray ( ) ;
for ( int32 CurTaskIndex = 0 ; CurTaskIndex < Tasks . Num ( ) ; + + CurTaskIndex )
{
const FTaskDatabaseEntry & CurTask = Tasks [ CurTaskIndex ] ;
if ( ( ! bOnlyOpen | | CurTask . Status . StartsWith ( TaskDataManager - > GetOpenTaskStatusPrefix ( ) ) ) & &
( ! bAssignedToMe | | CurTask . AssignedTo . Contains ( UserRealName ) ) & &
( ! bCreatedByMe | | CurTask . CreatedBy . Contains ( UserRealName ) ) & &
( ! bCurrentMap | | CurTask . Summary . Contains ( CurrentMaNamePtr ) ) )
{
TSharedPtr < FTaskOverview > NewTask = MakeShareable ( new FTaskOverview ( CurTask ) ) ;
TaskEntries . Add ( NewTask ) ;
// Try to keep the currently selected task selected
if ( SelectedTaskNumberSet . Contains ( CurTask . Number ) )
{
TaskList - > SetItemSelection ( NewTask , true ) ;
}
}
}
TaskList - > RequestListRefresh ( ) ;
}
if ( Options & ( ETaskBrowserGUIRefreshOptions : : ResetColumnSizes | ETaskBrowserGUIRefreshOptions : : RebuildTaskList ) )
{
// Update task list column sizes
TaskHeaders - > ResetColumnWidths ( ) ;
}
if ( Options & ( ETaskBrowserGUIRefreshOptions : : SortTaskList | ETaskBrowserGUIRefreshOptions : : RebuildTaskList ) )
{
// Sort the task list
TaskListItemSort ( ) ;
}
if ( Options & ETaskBrowserGUIRefreshOptions : : UpdateTaskDescription )
{
FString TaskSummary ;
FString TaskDescription ;
const uint32 TaskNumber = TaskDataManager - > GetFocusedTaskNumber ( ) ;
bool bHaveTask = false ;
if ( TaskNumber ! = INDEX_NONE )
{
// Do we have any cached results to display?
const FTaskDatabaseEntryDetails * TaskDetails = TaskDataManager - > FindCachedTaskDetails ( TaskNumber ) ;
if ( TaskDetails ! = NULL )
{
// We have the task details!
TaskSummary = TaskDetails - > Summary ;
TaskDescription = TaskDetails - > Description ;
// Append the task number to the name
TaskSummary + = FString : : Printf ( TEXT ( " (# %i) " ) , TaskNumber ) ;
bHaveTask = true ;
}
}
if ( ! bHaveTask )
{
// OK we don't have the task description yet, but it may be on it's way! Let's check.
if ( TaskDataManager - > GetGUIStatus ( ) = = ETaskDataManagerStatus : : QueryingTaskDetails )
{
// Try to find the name of the task in our cached task entry array
for ( int32 CurTaskIndex = 0 ; CurTaskIndex < TaskEntries . Num ( ) ; + + CurTaskIndex )
{
TSharedPtr < FTaskOverview > CurTask = TaskEntries [ CurTaskIndex ] ;
if ( CurTask - > Number = = TaskDataManager - > GetFocusedTaskNumber ( ) )
{
// Found it!
TaskSummary = CurTask - > Summary ;
// Append the task number to the name
TaskSummary + = FString : : Printf ( TEXT ( " (# %i) " ) , TaskNumber ) ;
break ;
}
}
// Let the user know we're downloading the task description now
TaskDescription = NSLOCTEXT ( " UnrealEd " , " TaskBrowser_WaitingForDescription " , " \n (Downloading task details from server. Please wait...) " ) . ToString ( ) ;
}
}
// Update the task name text
Summary - > SetText ( FText : : FromString ( TaskSummary ) ) ;
// Update the task description
Description - > SetText ( FText : : FromString ( TaskDescription ) ) ;
}
}
void STaskBrowser : : Callback_RefreshGUI ( const ETaskBrowserGUIRefreshOptions : : Type Options )
{
// Refresh the GUI
RefreshGUI ( Options ) ;
}
# undef LOCTEXT_NAMESPACE